From 543da850741d6aa6ef84e39a266162a7ceac17d3 Mon Sep 17 00:00:00 2001
From: Arkerthan <arkerthan@gmail.com>
Date: Thu, 7 May 2020 11:46:39 +0200
Subject: [PATCH] remove 2 unneded clone calls on passage change

---
 .../sugarcube stuff/2.31.1-debug-format.js    |  2 +-
 devNotes/sugarcube stuff/2.31.1-format.js     |  2 +-
 .../sugarcube-fc-changes.patch                | 22 ++++++++++++++++++-
 .../tweeGo/storyFormats/sugarcube-2/format.js |  2 +-
 4 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/devNotes/sugarcube stuff/2.31.1-debug-format.js b/devNotes/sugarcube stuff/2.31.1-debug-format.js
index b6e72bbe1a7..b199654f5f0 100644
--- a/devNotes/sugarcube stuff/2.31.1-debug-format.js	
+++ b/devNotes/sugarcube stuff/2.31.1-debug-format.js	
@@ -1 +1 @@
-window.storyFormat({"name":"SugarCube","version":"2.31.1","description":"A full featured, highly customizable story format.  See its <a href=\"http://www.motoslave.net/sugarcube/2/#documentation\" target=\"_blank\">documentation</a>.","author":"Thomas Michael Edwards","image":"icon.svg","url":"http://www.motoslave.net/sugarcube/","license":"BSD-2-Clause","proofing":false,"source":"<!DOCTYPE html>\n<html data-init=\"no-js\">\n<head>\n<meta charset=\"UTF-8\" />\n<title>{{STORY_NAME}}</title>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n<!--\n\nSugarCube (v2.31.1): A free (gratis and libre) story format.\n\nCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n-->\n<script id=\"script-libraries\" type=\"text/javascript\">\nif(document.head&&document.addEventListener&&document.querySelector&&Object.create&&Object.freeze&&JSON){document.documentElement.setAttribute(\"data-init\", \"loading\");\n/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js */\nif(\"document\" in self){if(!(\"classList\" in document.createElement(\"_\"))){(function(j){\"use strict\";if(!(\"Element\" in j)){return}var a=\"classList\",f=\"prototype\",m=j.Element[f],b=Object,k=String[f].trim||function(){return this.replace(/^\\s+|\\s+$/g,\"\")},c=Array[f].indexOf||function(q){var p=0,o=this.length;for(;p<o;p++){if(p in this&&this[p]===q){return p}}return -1},n=function(o,p){this.name=o;this.code=DOMException[o];this.message=p},g=function(p,o){if(o===\"\"){throw new n(\"SYNTAX_ERR\",\"An invalid or illegal string was specified\")}if(/\\s/.test(o)){throw new n(\"INVALID_CHARACTER_ERR\",\"String contains an invalid character\")}return c.call(p,o)},d=function(s){var r=k.call(s.getAttribute(\"class\")||\"\"),q=r?r.split(/\\s+/):[],p=0,o=q.length;for(;p<o;p++){this.push(q[p])}this._updateClassName=function(){s.setAttribute(\"class\",this.toString())}},e=d[f]=[],i=function(){return new d(this)};n[f]=Error[f];e.item=function(o){return this[o]||null};e.contains=function(o){o+=\"\";return g(this,o)!==-1};e.add=function(){var s=arguments,r=0,p=s.length,q,o=false;do{q=s[r]+\"\";if(g(this,q)===-1){this.push(q);o=true}}while(++r<p);if(o){this._updateClassName()}};e.remove=function(){var t=arguments,s=0,p=t.length,r,o=false,q;do{r=t[s]+\"\";q=g(this,r);while(q!==-1){this.splice(q,1);o=true;q=g(this,r)}}while(++s<p);if(o){this._updateClassName()}};e.toggle=function(p,q){p+=\"\";var o=this.contains(p),r=o?q!==true&&\"remove\":q!==false&&\"add\";if(r){this[r](p)}if(q===true||q===false){return q}else{return !o}};e.toString=function(){return this.join(\" \")};if(b.defineProperty){var l={get:i,enumerable:true,configurable:true};try{b.defineProperty(m,a,l)}catch(h){if(h.number===-2146823252){l.enumerable=false;b.defineProperty(m,a,l)}}}else{if(b[f].__defineGetter__){m.__defineGetter__(a,i)}}}(self))}else{(function(){var b=document.createElement(\"_\");b.classList.add(\"c1\",\"c2\");if(!b.classList.contains(\"c2\")){var c=function(e){var d=DOMTokenList.prototype[e];DOMTokenList.prototype[e]=function(h){var g,f=arguments.length;for(g=0;g<f;g++){h=arguments[g];d.call(this,h)}}};c(\"add\");c(\"remove\")}b.classList.toggle(\"c3\",false);if(b.classList.contains(\"c3\")){var a=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(d,e){if(1 in arguments&&!this.contains(d)===!e){return e}else{return a.call(this,d)}}}b=null}())}};\n/*!\n * https://github.com/es-shims/es5-shim\n * @license es5-shim Copyright 2009-2015 by contributors, MIT License\n * see https://github.com/es-shims/es5-shim/blob/v4.5.13/LICENSE\n */\n(function(t,r){\"use strict\";if(typeof define===\"function\"&&define.amd){define(r)}else if(typeof exports===\"object\"){module.exports=r()}else{t.returnExports=r()}})(this,function(){var t=Array;var r=t.prototype;var e=Object;var n=e.prototype;var i=Function;var a=i.prototype;var o=String;var f=o.prototype;var u=Number;var l=u.prototype;var s=r.slice;var c=r.splice;var v=r.push;var h=r.unshift;var p=r.concat;var y=r.join;var d=a.call;var g=a.apply;var w=Math.max;var b=Math.min;var T=n.toString;var m=typeof Symbol===\"function\"&&typeof Symbol.toStringTag===\"symbol\";var D;var S=Function.prototype.toString,x=/^\\s*class /,O=function isES6ClassFn(t){try{var r=S.call(t);var e=r.replace(/\\/\\/.*\\n/g,\"\");var n=e.replace(/\\/\\*[.\\s\\S]*\\*\\//g,\"\");var i=n.replace(/\\n/gm,\" \").replace(/ {2}/g,\" \");return x.test(i)}catch(a){return false}},E=function tryFunctionObject(t){try{if(O(t)){return false}S.call(t);return true}catch(r){return false}},j=\"[object Function]\",I=\"[object GeneratorFunction]\",D=function isCallable(t){if(!t){return false}if(typeof t!==\"function\"&&typeof t!==\"object\"){return false}if(m){return E(t)}if(O(t)){return false}var r=T.call(t);return r===j||r===I};var M;var U=RegExp.prototype.exec,$=function tryRegexExec(t){try{U.call(t);return true}catch(r){return false}},F=\"[object RegExp]\";M=function isRegex(t){if(typeof t!==\"object\"){return false}return m?$(t):T.call(t)===F};var N;var C=String.prototype.valueOf,k=function tryStringObject(t){try{C.call(t);return true}catch(r){return false}},A=\"[object String]\";N=function isString(t){if(typeof t===\"string\"){return true}if(typeof t!==\"object\"){return false}return m?k(t):T.call(t)===A};var R=e.defineProperty&&function(){try{var t={};e.defineProperty(t,\"x\",{enumerable:false,value:t});for(var r in t){return false}return t.x===t}catch(n){return false}}();var P=function(t){var r;if(R){r=function(t,r,n,i){if(!i&&r in t){return}e.defineProperty(t,r,{configurable:true,enumerable:false,writable:true,value:n})}}else{r=function(t,r,e,n){if(!n&&r in t){return}t[r]=e}}return function defineProperties(e,n,i){for(var a in n){if(t.call(n,a)){r(e,a,n[a],i)}}}}(n.hasOwnProperty);var J=function isPrimitive(t){var r=typeof t;return t===null||r!==\"object\"&&r!==\"function\"};var Y=u.isNaN||function isActualNaN(t){return t!==t};var z={ToInteger:function ToInteger(t){var r=+t;if(Y(r)){r=0}else if(r!==0&&r!==1/0&&r!==-(1/0)){r=(r>0||-1)*Math.floor(Math.abs(r))}return r},ToPrimitive:function ToPrimitive(t){var r,e,n;if(J(t)){return t}e=t.valueOf;if(D(e)){r=e.call(t);if(J(r)){return r}}n=t.toString;if(D(n)){r=n.call(t);if(J(r)){return r}}throw new TypeError},ToObject:function(t){if(t==null){throw new TypeError(\"can't convert \"+t+\" to object\")}return e(t)},ToUint32:function ToUint32(t){return t>>>0}};var Z=function Empty(){};P(a,{bind:function bind(t){var r=this;if(!D(r)){throw new TypeError(\"Function.prototype.bind called on incompatible \"+r)}var n=s.call(arguments,1);var a;var o=function(){if(this instanceof a){var i=g.call(r,this,p.call(n,s.call(arguments)));if(e(i)===i){return i}return this}else{return g.call(r,t,p.call(n,s.call(arguments)))}};var f=w(0,r.length-n.length);var u=[];for(var l=0;l<f;l++){v.call(u,\"$\"+l)}a=i(\"binder\",\"return function (\"+y.call(u,\",\")+\"){ return binder.apply(this, arguments); }\")(o);if(r.prototype){Z.prototype=r.prototype;a.prototype=new Z;Z.prototype=null}return a}});var G=d.bind(n.hasOwnProperty);var H=d.bind(n.toString);var W=d.bind(s);var B=g.bind(s);if(typeof document===\"object\"&&document&&document.documentElement){try{W(document.documentElement.childNodes)}catch(X){var L=W;var q=B;W=function arraySliceIE(t){var r=[];var e=t.length;while(e-- >0){r[e]=t[e]}return q(r,L(arguments,1))};B=function arraySliceApplyIE(t,r){return q(W(t),r)}}}var K=d.bind(f.slice);var Q=d.bind(f.split);var V=d.bind(f.indexOf);var _=d.bind(v);var tt=d.bind(n.propertyIsEnumerable);var rt=d.bind(r.sort);var et=t.isArray||function isArray(t){return H(t)===\"[object Array]\"};var nt=[].unshift(0)!==1;P(r,{unshift:function(){h.apply(this,arguments);return this.length}},nt);P(t,{isArray:et});var it=e(\"a\");var at=it[0]!==\"a\"||!(0 in it);var ot=function properlyBoxed(t){var r=true;var e=true;var n=false;if(t){try{t.call(\"foo\",function(t,e,n){if(typeof n!==\"object\"){r=false}});t.call([1],function(){\"use strict\";e=typeof this===\"string\"},\"x\")}catch(i){n=true}}return!!t&&!n&&r&&e};P(r,{forEach:function forEach(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=-1;var i=z.ToUint32(e.length);var a;if(arguments.length>1){a=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.forEach callback must be a function\")}while(++n<i){if(n in e){if(typeof a===\"undefined\"){t(e[n],n,r)}else{t.call(a,e[n],n,r)}}}}},!ot(r.forEach));P(r,{map:function map(r){var e=z.ToObject(this);var n=at&&N(this)?Q(this,\"\"):e;var i=z.ToUint32(n.length);var a=t(i);var o;if(arguments.length>1){o=arguments[1]}if(!D(r)){throw new TypeError(\"Array.prototype.map callback must be a function\")}for(var f=0;f<i;f++){if(f in n){if(typeof o===\"undefined\"){a[f]=r(n[f],f,e)}else{a[f]=r.call(o,n[f],f,e)}}}return a}},!ot(r.map));P(r,{filter:function filter(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i=[];var a;var o;if(arguments.length>1){o=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.filter callback must be a function\")}for(var f=0;f<n;f++){if(f in e){a=e[f];if(typeof o===\"undefined\"?t(a,f,r):t.call(o,a,f,r)){_(i,a)}}}return i}},!ot(r.filter));P(r,{every:function every(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i;if(arguments.length>1){i=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.every callback must be a function\")}for(var a=0;a<n;a++){if(a in e&&!(typeof i===\"undefined\"?t(e[a],a,r):t.call(i,e[a],a,r))){return false}}return true}},!ot(r.every));P(r,{some:function some(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i;if(arguments.length>1){i=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.some callback must be a function\")}for(var a=0;a<n;a++){if(a in e&&(typeof i===\"undefined\"?t(e[a],a,r):t.call(i,e[a],a,r))){return true}}return false}},!ot(r.some));var ft=false;if(r.reduce){ft=typeof r.reduce.call(\"es5\",function(t,r,e,n){return n})===\"object\"}P(r,{reduce:function reduce(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);if(!D(t)){throw new TypeError(\"Array.prototype.reduce callback must be a function\")}if(n===0&&arguments.length===1){throw new TypeError(\"reduce of empty array with no initial value\")}var i=0;var a;if(arguments.length>=2){a=arguments[1]}else{do{if(i in e){a=e[i++];break}if(++i>=n){throw new TypeError(\"reduce of empty array with no initial value\")}}while(true)}for(;i<n;i++){if(i in e){a=t(a,e[i],i,r)}}return a}},!ft);var ut=false;if(r.reduceRight){ut=typeof r.reduceRight.call(\"es5\",function(t,r,e,n){return n})===\"object\"}P(r,{reduceRight:function reduceRight(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);if(!D(t)){throw new TypeError(\"Array.prototype.reduceRight callback must be a function\")}if(n===0&&arguments.length===1){throw new TypeError(\"reduceRight of empty array with no initial value\")}var i;var a=n-1;if(arguments.length>=2){i=arguments[1]}else{do{if(a in e){i=e[a--];break}if(--a<0){throw new TypeError(\"reduceRight of empty array with no initial value\")}}while(true)}if(a<0){return i}do{if(a in e){i=t(i,e[a],a,r)}}while(a--);return i}},!ut);var lt=r.indexOf&&[0,1].indexOf(1,2)!==-1;P(r,{indexOf:function indexOf(t){var r=at&&N(this)?Q(this,\"\"):z.ToObject(this);var e=z.ToUint32(r.length);if(e===0){return-1}var n=0;if(arguments.length>1){n=z.ToInteger(arguments[1])}n=n>=0?n:w(0,e+n);for(;n<e;n++){if(n in r&&r[n]===t){return n}}return-1}},lt);var st=r.lastIndexOf&&[0,1].lastIndexOf(0,-3)!==-1;P(r,{lastIndexOf:function lastIndexOf(t){var r=at&&N(this)?Q(this,\"\"):z.ToObject(this);var e=z.ToUint32(r.length);if(e===0){return-1}var n=e-1;if(arguments.length>1){n=b(n,z.ToInteger(arguments[1]))}n=n>=0?n:e-Math.abs(n);for(;n>=0;n--){if(n in r&&t===r[n]){return n}}return-1}},st);var ct=function(){var t=[1,2];var r=t.splice();return t.length===2&&et(r)&&r.length===0}();P(r,{splice:function splice(t,r){if(arguments.length===0){return[]}else{return c.apply(this,arguments)}}},!ct);var vt=function(){var t={};r.splice.call(t,0,0,1);return t.length===1}();P(r,{splice:function splice(t,r){if(arguments.length===0){return[]}var e=arguments;this.length=w(z.ToInteger(this.length),0);if(arguments.length>0&&typeof r!==\"number\"){e=W(arguments);if(e.length<2){_(e,this.length-t)}else{e[1]=z.ToInteger(r)}}return c.apply(this,e)}},!vt);var ht=function(){var r=new t(1e5);r[8]=\"x\";r.splice(1,1);return r.indexOf(\"x\")===7}();var pt=function(){var t=256;var r=[];r[t]=\"a\";r.splice(t+1,0,\"b\");return r[t]===\"a\"}();P(r,{splice:function splice(t,r){var e=z.ToObject(this);var n=[];var i=z.ToUint32(e.length);var a=z.ToInteger(t);var f=a<0?w(i+a,0):b(a,i);var u=b(w(z.ToInteger(r),0),i-f);var l=0;var s;while(l<u){s=o(f+l);if(G(e,s)){n[l]=e[s]}l+=1}var c=W(arguments,2);var v=c.length;var h;if(v<u){l=f;var p=i-u;while(l<p){s=o(l+u);h=o(l+v);if(G(e,s)){e[h]=e[s]}else{delete e[h]}l+=1}l=i;var y=i-u+v;while(l>y){delete e[l-1];l-=1}}else if(v>u){l=i-u;while(l>f){s=o(l+u-1);h=o(l+v-1);if(G(e,s)){e[h]=e[s]}else{delete e[h]}l-=1}}l=f;for(var d=0;d<c.length;++d){e[l]=c[d];l+=1}e.length=i-u+v;return n}},!ht||!pt);var yt=r.join;var dt;try{dt=Array.prototype.join.call(\"123\",\",\")!==\"1,2,3\"}catch(X){dt=true}if(dt){P(r,{join:function join(t){var r=typeof t===\"undefined\"?\",\":t;return yt.call(N(this)?Q(this,\"\"):this,r)}},dt)}var gt=[1,2].join(undefined)!==\"1,2\";if(gt){P(r,{join:function join(t){var r=typeof t===\"undefined\"?\",\":t;return yt.call(this,r)}},gt)}var wt=function push(t){var r=z.ToObject(this);var e=z.ToUint32(r.length);var n=0;while(n<arguments.length){r[e+n]=arguments[n];n+=1}r.length=e+n;return e+n};var bt=function(){var t={};var r=Array.prototype.push.call(t,undefined);return r!==1||t.length!==1||typeof t[0]!==\"undefined\"||!G(t,0)}();P(r,{push:function push(t){if(et(this)){return v.apply(this,arguments)}return wt.apply(this,arguments)}},bt);var Tt=function(){var t=[];var r=t.push(undefined);return r!==1||t.length!==1||typeof t[0]!==\"undefined\"||!G(t,0)}();P(r,{push:wt},Tt);P(r,{slice:function(t,r){var e=N(this)?Q(this,\"\"):this;return B(e,arguments)}},at);var mt=function(){try{[1,2].sort(null)}catch(t){try{[1,2].sort({})}catch(r){return false}}return true}();var Dt=function(){try{[1,2].sort(/a/);return false}catch(t){}return true}();var St=function(){try{[1,2].sort(undefined);return true}catch(t){}return false}();P(r,{sort:function sort(t){if(typeof t===\"undefined\"){return rt(this)}if(!D(t)){throw new TypeError(\"Array.prototype.sort callback must be a function\")}return rt(this,t)}},mt||!St||!Dt);var xt=!tt({toString:null},\"toString\");var Ot=tt(function(){},\"prototype\");var Et=!G(\"x\",\"0\");var jt=function(t){var r=t.constructor;return r&&r.prototype===t};var It={$applicationCache:true,$console:true,$external:true,$frame:true,$frameElement:true,$frames:true,$innerHeight:true,$innerWidth:true,$onmozfullscreenchange:true,$onmozfullscreenerror:true,$outerHeight:true,$outerWidth:true,$pageXOffset:true,$pageYOffset:true,$parent:true,$scrollLeft:true,$scrollTop:true,$scrollX:true,$scrollY:true,$self:true,$webkitIndexedDB:true,$webkitStorageInfo:true,$window:true,$width:true,$height:true,$top:true,$localStorage:true};var Mt=function(){if(typeof window===\"undefined\"){return false}for(var t in window){try{if(!It[\"$\"+t]&&G(window,t)&&window[t]!==null&&typeof window[t]===\"object\"){jt(window[t])}}catch(r){return true}}return false}();var Ut=function(t){if(typeof window===\"undefined\"||!Mt){return jt(t)}try{return jt(t)}catch(r){return false}};var $t=[\"toString\",\"toLocaleString\",\"valueOf\",\"hasOwnProperty\",\"isPrototypeOf\",\"propertyIsEnumerable\",\"constructor\"];var Ft=$t.length;var Nt=function isArguments(t){return H(t)===\"[object Arguments]\"};var Ct=function isArguments(t){return t!==null&&typeof t===\"object\"&&typeof t.length===\"number\"&&t.length>=0&&!et(t)&&D(t.callee)};var kt=Nt(arguments)?Nt:Ct;P(e,{keys:function keys(t){var r=D(t);var e=kt(t);var n=t!==null&&typeof t===\"object\";var i=n&&N(t);if(!n&&!r&&!e){throw new TypeError(\"Object.keys called on a non-object\")}var a=[];var f=Ot&&r;if(i&&Et||e){for(var u=0;u<t.length;++u){_(a,o(u))}}if(!e){for(var l in t){if(!(f&&l===\"prototype\")&&G(t,l)){_(a,o(l))}}}if(xt){var s=Ut(t);for(var c=0;c<Ft;c++){var v=$t[c];if(!(s&&v===\"constructor\")&&G(t,v)){_(a,v)}}}return a}});var At=e.keys&&function(){return e.keys(arguments).length===2}(1,2);var Rt=e.keys&&function(){var t=e.keys(arguments);return arguments.length!==1||t.length!==1||t[0]!==1}(1);var Pt=e.keys;P(e,{keys:function keys(t){if(kt(t)){return Pt(W(t))}else{return Pt(t)}}},!At||Rt);var Jt=new Date(-0xc782b5b342b24).getUTCMonth()!==0;var Yt=new Date(-0x55d318d56a724);var zt=new Date(14496624e5);var Zt=Yt.toUTCString()!==\"Mon, 01 Jan -45875 11:59:59 GMT\";var Gt;var Ht;var Wt=Yt.getTimezoneOffset();if(Wt<-720){Gt=Yt.toDateString()!==\"Tue Jan 02 -45875\";Ht=!/^Thu Dec 10 2015 \\d\\d:\\d\\d:\\d\\d GMT[-+]\\d\\d\\d\\d(?: |$)/.test(String(zt))}else{Gt=Yt.toDateString()!==\"Mon Jan 01 -45875\";Ht=!/^Wed Dec 09 2015 \\d\\d:\\d\\d:\\d\\d GMT[-+]\\d\\d\\d\\d(?: |$)/.test(String(zt))}var Bt=d.bind(Date.prototype.getFullYear);var Xt=d.bind(Date.prototype.getMonth);var Lt=d.bind(Date.prototype.getDate);var qt=d.bind(Date.prototype.getUTCFullYear);var Kt=d.bind(Date.prototype.getUTCMonth);var Qt=d.bind(Date.prototype.getUTCDate);var Vt=d.bind(Date.prototype.getUTCDay);var _t=d.bind(Date.prototype.getUTCHours);var tr=d.bind(Date.prototype.getUTCMinutes);var rr=d.bind(Date.prototype.getUTCSeconds);var er=d.bind(Date.prototype.getUTCMilliseconds);var nr=[\"Sun\",\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\"];var ir=[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"];var ar=function daysInMonth(t,r){return Lt(new Date(r,t,0))};P(Date.prototype,{getFullYear:function getFullYear(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);if(t<0&&Xt(this)>11){return t+1}return t},getMonth:function getMonth(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);var r=Xt(this);if(t<0&&r>11){return 0}return r},getDate:function getDate(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);var r=Xt(this);var e=Lt(this);if(t<0&&r>11){if(r===12){return e}var n=ar(0,t+1);return n-e+1}return e},getUTCFullYear:function getUTCFullYear(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);if(t<0&&Kt(this)>11){return t+1}return t},getUTCMonth:function getUTCMonth(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);var r=Kt(this);if(t<0&&r>11){return 0}return r},getUTCDate:function getUTCDate(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);var r=Kt(this);var e=Qt(this);if(t<0&&r>11){if(r===12){return e}var n=ar(0,t+1);return n-e+1}return e}},Jt);P(Date.prototype,{toUTCString:function toUTCString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Vt(this);var r=Qt(this);var e=Kt(this);var n=qt(this);var i=_t(this);var a=tr(this);var o=rr(this);return nr[t]+\", \"+(r<10?\"0\"+r:r)+\" \"+ir[e]+\" \"+n+\" \"+(i<10?\"0\"+i:i)+\":\"+(a<10?\"0\"+a:a)+\":\"+(o<10?\"0\"+o:o)+\" GMT\"}},Jt||Zt);P(Date.prototype,{toDateString:function toDateString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=this.getDay();var r=this.getDate();var e=this.getMonth();var n=this.getFullYear();return nr[t]+\" \"+ir[e]+\" \"+(r<10?\"0\"+r:r)+\" \"+n}},Jt||Gt);if(Jt||Ht){Date.prototype.toString=function toString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=this.getDay();var r=this.getDate();var e=this.getMonth();var n=this.getFullYear();var i=this.getHours();var a=this.getMinutes();var o=this.getSeconds();var f=this.getTimezoneOffset();var u=Math.floor(Math.abs(f)/60);var l=Math.floor(Math.abs(f)%60);return nr[t]+\" \"+ir[e]+\" \"+(r<10?\"0\"+r:r)+\" \"+n+\" \"+(i<10?\"0\"+i:i)+\":\"+(a<10?\"0\"+a:a)+\":\"+(o<10?\"0\"+o:o)+\" GMT\"+(f>0?\"-\":\"+\")+(u<10?\"0\"+u:u)+(l<10?\"0\"+l:l)};if(R){e.defineProperty(Date.prototype,\"toString\",{configurable:true,enumerable:false,writable:true})}}var or=-621987552e5;var fr=\"-000001\";var ur=Date.prototype.toISOString&&new Date(or).toISOString().indexOf(fr)===-1;var lr=Date.prototype.toISOString&&new Date(-1).toISOString()!==\"1969-12-31T23:59:59.999Z\";var sr=d.bind(Date.prototype.getTime);P(Date.prototype,{toISOString:function toISOString(){if(!isFinite(this)||!isFinite(sr(this))){throw new RangeError(\"Date.prototype.toISOString called on non-finite value.\")}var t=qt(this);var r=Kt(this);t+=Math.floor(r/12);r=(r%12+12)%12;var e=[r+1,Qt(this),_t(this),tr(this),rr(this)];t=(t<0?\"-\":t>9999?\"+\":\"\")+K(\"00000\"+Math.abs(t),0<=t&&t<=9999?-4:-6);for(var n=0;n<e.length;++n){e[n]=K(\"00\"+e[n],-2)}return t+\"-\"+W(e,0,2).join(\"-\")+\"T\"+W(e,2).join(\":\")+\".\"+K(\"000\"+er(this),-3)+\"Z\"}},ur||lr);var cr=function(){try{return Date.prototype.toJSON&&new Date(NaN).toJSON()===null&&new Date(or).toJSON().indexOf(fr)!==-1&&Date.prototype.toJSON.call({toISOString:function(){return true}})}catch(t){return false}}();if(!cr){Date.prototype.toJSON=function toJSON(t){var r=e(this);var n=z.ToPrimitive(r);if(typeof n===\"number\"&&!isFinite(n)){return null}var i=r.toISOString;if(!D(i)){throw new TypeError(\"toISOString property is not callable\")}return i.call(r)}}var vr=Date.parse(\"+033658-09-27T01:46:40.000Z\")===1e15;var hr=!isNaN(Date.parse(\"2012-04-04T24:00:00.500Z\"))||!isNaN(Date.parse(\"2012-11-31T23:59:59.000Z\"))||!isNaN(Date.parse(\"2012-12-31T23:59:60.000Z\"));var pr=isNaN(Date.parse(\"2000-01-01T00:00:00.000Z\"));if(pr||hr||!vr){var yr=Math.pow(2,31)-1;var dr=Y(new Date(1970,0,1,0,0,0,yr+1).getTime());Date=function(t){var r=function Date(e,n,i,a,f,u,l){var s=arguments.length;var c;if(this instanceof t){var v=u;var h=l;if(dr&&s>=7&&l>yr){var p=Math.floor(l/yr)*yr;var y=Math.floor(p/1e3);v+=y;h-=y*1e3}c=s===1&&o(e)===e?new t(r.parse(e)):s>=7?new t(e,n,i,a,f,v,h):s>=6?new t(e,n,i,a,f,v):s>=5?new t(e,n,i,a,f):s>=4?new t(e,n,i,a):s>=3?new t(e,n,i):s>=2?new t(e,n):s>=1?new t(e instanceof t?+e:e):new t}else{c=t.apply(this,arguments)}if(!J(c)){P(c,{constructor:r},true)}return c};var e=new RegExp(\"^\"+\"(\\\\d{4}|[+-]\\\\d{6})\"+\"(?:-(\\\\d{2})\"+\"(?:-(\\\\d{2})\"+\"(?:\"+\"T(\\\\d{2})\"+\":(\\\\d{2})\"+\"(?:\"+\":(\\\\d{2})\"+\"(?:(\\\\.\\\\d{1,}))?\"+\")?\"+\"(\"+\"Z|\"+\"(?:\"+\"([-+])\"+\"(\\\\d{2})\"+\":(\\\\d{2})\"+\")\"+\")?)?)?)?\"+\"$\");var n=[0,31,59,90,120,151,181,212,243,273,304,334,365];var i=function dayFromMonth(t,r){var e=r>1?1:0;return n[r]+Math.floor((t-1969+e)/4)-Math.floor((t-1901+e)/100)+Math.floor((t-1601+e)/400)+365*(t-1970)};var a=function toUTC(r){var e=0;var n=r;if(dr&&n>yr){var i=Math.floor(n/yr)*yr;var a=Math.floor(i/1e3);e+=a;n-=a*1e3}return u(new t(1970,0,1,0,0,e,n))};for(var f in t){if(G(t,f)){r[f]=t[f]}}P(r,{now:t.now,UTC:t.UTC},true);r.prototype=t.prototype;P(r.prototype,{constructor:r},true);var l=function parse(r){var n=e.exec(r);if(n){var o=u(n[1]),f=u(n[2]||1)-1,l=u(n[3]||1)-1,s=u(n[4]||0),c=u(n[5]||0),v=u(n[6]||0),h=Math.floor(u(n[7]||0)*1e3),p=Boolean(n[4]&&!n[8]),y=n[9]===\"-\"?1:-1,d=u(n[10]||0),g=u(n[11]||0),w;var b=c>0||v>0||h>0;if(s<(b?24:25)&&c<60&&v<60&&h<1e3&&f>-1&&f<12&&d<24&&g<60&&l>-1&&l<i(o,f+1)-i(o,f)){w=((i(o,f)+l)*24+s+d*y)*60;w=((w+c+g*y)*60+v)*1e3+h;if(p){w=a(w)}if(-864e13<=w&&w<=864e13){return w}}return NaN}return t.parse.apply(this,arguments)};P(r,{parse:l});return r}(Date)}if(!Date.now){Date.now=function now(){return(new Date).getTime()}}var gr=l.toFixed&&(8e-5.toFixed(3)!==\"0.000\"||.9.toFixed(0)!==\"1\"||1.255.toFixed(2)!==\"1.25\"||(1000000000000000128).toFixed(0)!==\"1000000000000000128\");var wr={base:1e7,size:6,data:[0,0,0,0,0,0],multiply:function multiply(t,r){var e=-1;var n=r;while(++e<wr.size){n+=t*wr.data[e];wr.data[e]=n%wr.base;n=Math.floor(n/wr.base)}},divide:function divide(t){var r=wr.size;var e=0;while(--r>=0){e+=wr.data[r];wr.data[r]=Math.floor(e/t);e=e%t*wr.base}},numToString:function numToString(){var t=wr.size;var r=\"\";while(--t>=0){if(r!==\"\"||t===0||wr.data[t]!==0){var e=o(wr.data[t]);if(r===\"\"){r=e}else{r+=K(\"0000000\",0,7-e.length)+e}}}return r},pow:function pow(t,r,e){return r===0?e:r%2===1?pow(t,r-1,e*t):pow(t*t,r/2,e)},log:function log(t){var r=0;var e=t;while(e>=4096){r+=12;e/=4096}while(e>=2){r+=1;e/=2}return r}};var br=function toFixed(t){var r,e,n,i,a,f,l,s;r=u(t);r=Y(r)?0:Math.floor(r);if(r<0||r>20){throw new RangeError(\"Number.toFixed called with invalid number of decimals\")}e=u(this);if(Y(e)){return\"NaN\"}if(e<=-1e21||e>=1e21){return o(e)}n=\"\";if(e<0){n=\"-\";e=-e}i=\"0\";if(e>1e-21){a=wr.log(e*wr.pow(2,69,1))-69;f=a<0?e*wr.pow(2,-a,1):e/wr.pow(2,a,1);f*=4503599627370496;a=52-a;if(a>0){wr.multiply(0,f);l=r;while(l>=7){wr.multiply(1e7,0);l-=7}wr.multiply(wr.pow(10,l,1),0);l=a-1;while(l>=23){wr.divide(1<<23);l-=23}wr.divide(1<<l);wr.multiply(1,1);wr.divide(2);i=wr.numToString()}else{wr.multiply(0,f);wr.multiply(1<<-a,0);i=wr.numToString()+K(\"0.00000000000000000000\",2,2+r)}}if(r>0){s=i.length;if(s<=r){i=n+K(\"0.0000000000000000000\",0,r-s+2)+i}else{i=n+K(i,0,s-r)+\".\"+K(i,s-r)}}else{i=n+i}return i};P(l,{toFixed:br},gr);var Tr=function(){try{return 1..toPrecision(undefined)===\"1\"}catch(t){return true}}();var mr=l.toPrecision;P(l,{toPrecision:function toPrecision(t){return typeof t===\"undefined\"?mr.call(this):mr.call(this,t)}},Tr);if(\"ab\".split(/(?:ab)*/).length!==2||\".\".split(/(.?)(.?)/).length!==4||\"tesst\".split(/(s)*/)[1]===\"t\"||\"test\".split(/(?:)/,-1).length!==4||\"\".split(/.?/).length||\".\".split(/()()/).length>1){(function(){var t=typeof/()??/.exec(\"\")[1]===\"undefined\";var r=Math.pow(2,32)-1;f.split=function(e,n){var i=String(this);if(typeof e===\"undefined\"&&n===0){return[]}if(!M(e)){return Q(this,e,n)}var a=[];var o=(e.ignoreCase?\"i\":\"\")+(e.multiline?\"m\":\"\")+(e.unicode?\"u\":\"\")+(e.sticky?\"y\":\"\"),f=0,u,l,s,c;var h=new RegExp(e.source,o+\"g\");if(!t){u=new RegExp(\"^\"+h.source+\"$(?!\\\\s)\",o)}var p=typeof n===\"undefined\"?r:z.ToUint32(n);l=h.exec(i);while(l){s=l.index+l[0].length;if(s>f){_(a,K(i,f,l.index));if(!t&&l.length>1){l[0].replace(u,function(){for(var t=1;t<arguments.length-2;t++){if(typeof arguments[t]===\"undefined\"){l[t]=void 0}}})}if(l.length>1&&l.index<i.length){v.apply(a,W(l,1))}c=l[0].length;f=s;if(a.length>=p){break}}if(h.lastIndex===l.index){h.lastIndex++}l=h.exec(i)}if(f===i.length){if(c||!h.test(\"\")){_(a,\"\")}}else{_(a,K(i,f))}return a.length>p?W(a,0,p):a}})()}else if(\"0\".split(void 0,0).length){f.split=function split(t,r){if(typeof t===\"undefined\"&&r===0){return[]}return Q(this,t,r)}}var Dr=f.replace;var Sr=function(){var t=[];\"x\".replace(/x(.)?/g,function(r,e){_(t,e)});return t.length===1&&typeof t[0]===\"undefined\"}();if(!Sr){f.replace=function replace(t,r){var e=D(r);var n=M(t)&&/\\)[*?]/.test(t.source);if(!e||!n){return Dr.call(this,t,r)}else{var i=function(e){var n=arguments.length;var i=t.lastIndex;t.lastIndex=0;var a=t.exec(e)||[];t.lastIndex=i;_(a,arguments[n-2],arguments[n-1]);return r.apply(this,a)};return Dr.call(this,t,i)}}}var xr=f.substr;var Or=\"\".substr&&\"0b\".substr(-1)!==\"b\";P(f,{substr:function substr(t,r){var e=t;if(t<0){e=w(this.length+t,0)}return xr.call(this,e,r)}},Or);var Er=\"\\t\\n\\x0B\\f\\r \\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\"+\"\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\"+\"\\u2029\\ufeff\";var jr=\"\\u200b\";var Ir=\"[\"+Er+\"]\";var Mr=new RegExp(\"^\"+Ir+Ir+\"*\");var Ur=new RegExp(Ir+Ir+\"*$\");var $r=f.trim&&(Er.trim()||!jr.trim());P(f,{trim:function trim(){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}return o(this).replace(Mr,\"\").replace(Ur,\"\")}},$r);var Fr=d.bind(String.prototype.trim);var Nr=f.lastIndexOf&&\"abc\\u3042\\u3044\".lastIndexOf(\"\\u3042\\u3044\",2)!==-1;P(f,{lastIndexOf:function lastIndexOf(t){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}var r=o(this);var e=o(t);var n=arguments.length>1?u(arguments[1]):NaN;var i=Y(n)?Infinity:z.ToInteger(n);var a=b(w(i,0),r.length);var f=e.length;var l=a+f;while(l>0){l=w(0,l-f);var s=V(K(r,l,a+f),e);if(s!==-1){return l+s}}return-1}},Nr);var Cr=f.lastIndexOf;P(f,{lastIndexOf:function lastIndexOf(t){return Cr.apply(this,arguments)}},f.lastIndexOf.length!==1);if(parseInt(Er+\"08\")!==8||parseInt(Er+\"0x16\")!==22){parseInt=function(t){var r=/^[-+]?0[xX]/;return function parseInt(e,n){if(typeof e===\"symbol\"){\"\"+e}var i=Fr(String(e));var a=u(n)||(r.test(i)?16:10);return t(i,a)}}(parseInt)}if(1/parseFloat(\"-0\")!==-Infinity){parseFloat=function(t){return function parseFloat(r){var e=Fr(String(r));var n=t(e);return n===0&&K(e,0,1)===\"-\"?-0:n}}(parseFloat)}if(String(new RangeError(\"test\"))!==\"RangeError: test\"){var kr=function toString(){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}var t=this.name;if(typeof t===\"undefined\"){t=\"Error\"}else if(typeof t!==\"string\"){t=o(t)}var r=this.message;if(typeof r===\"undefined\"){r=\"\"}else if(typeof r!==\"string\"){r=o(r)}if(!t){return r}if(!r){return t}return t+\": \"+r};Error.prototype.toString=kr}if(R){var Ar=function(t,r){if(tt(t,r)){var e=Object.getOwnPropertyDescriptor(t,r);if(e.configurable){e.enumerable=false;Object.defineProperty(t,r,e)}}};Ar(Error.prototype,\"message\");if(Error.prototype.message!==\"\"){Error.prototype.message=\"\"}Ar(Error.prototype,\"name\")}if(String(/a/gim)!==\"/a/gim\"){var Rr=function toString(){var t=\"/\"+this.source+\"/\";if(this.global){t+=\"g\"}if(this.ignoreCase){t+=\"i\"}if(this.multiline){t+=\"m\"}return t};RegExp.prototype.toString=Rr}});\n//# sourceMappingURL=es5-shim.map\n/*!\n * https://github.com/paulmillr/es6-shim\n * @license es6-shim Copyright 2013-2016 by Paul Miller (http://paulmillr.com)\n *   and contributors,  MIT License\n * es6-shim: v0.35.4\n * see https://github.com/paulmillr/es6-shim/blob/0.35.4/LICENSE\n * Details and documentation:\n * https://github.com/paulmillr/es6-shim/\n */\n(function(e,t){if(typeof define===\"function\"&&define.amd){define(t)}else if(typeof exports===\"object\"){module.exports=t()}else{e.returnExports=t()}})(this,function(){\"use strict\";var e=Function.call.bind(Function.apply);var t=Function.call.bind(Function.call);var r=Array.isArray;var n=Object.keys;var o=function notThunker(t){return function notThunk(){return!e(t,this,arguments)}};var i=function(e){try{e();return false}catch(t){return true}};var a=function valueOrFalseIfThrows(e){try{return e()}catch(t){return false}};var u=o(i);var f=function(){return!i(function(){return Object.defineProperty({},\"x\",{get:function(){}})})};var s=!!Object.defineProperty&&f();var c=function foo(){}.name===\"foo\";var l=Function.call.bind(Array.prototype.forEach);var p=Function.call.bind(Array.prototype.reduce);var v=Function.call.bind(Array.prototype.filter);var y=Function.call.bind(Array.prototype.some);var h=function(e,t,r,n){if(!n&&t in e){return}if(s){Object.defineProperty(e,t,{configurable:true,enumerable:false,writable:true,value:r})}else{e[t]=r}};var b=function(e,t,r){l(n(t),function(n){var o=t[n];h(e,n,o,!!r)})};var g=Function.call.bind(Object.prototype.toString);var d=typeof/abc/===\"function\"?function IsCallableSlow(e){return typeof e===\"function\"&&g(e)===\"[object Function]\"}:function IsCallableFast(e){return typeof e===\"function\"};var m={getter:function(e,t,r){if(!s){throw new TypeError(\"getters require true ES5 support\")}Object.defineProperty(e,t,{configurable:true,enumerable:false,get:r})},proxy:function(e,t,r){if(!s){throw new TypeError(\"getters require true ES5 support\")}var n=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,{configurable:n.configurable,enumerable:n.enumerable,get:function getKey(){return e[t]},set:function setKey(r){e[t]=r}})},redefine:function(e,t,r){if(s){var n=Object.getOwnPropertyDescriptor(e,t);n.value=r;Object.defineProperty(e,t,n)}else{e[t]=r}},defineByDescriptor:function(e,t,r){if(s){Object.defineProperty(e,t,r)}else if(\"value\"in r){e[t]=r.value}},preserveToString:function(e,t){if(t&&d(t.toString)){h(e,\"toString\",t.toString.bind(t),true)}}};var O=Object.create||function(e,t){var r=function Prototype(){};r.prototype=e;var o=new r;if(typeof t!==\"undefined\"){n(t).forEach(function(e){m.defineByDescriptor(o,e,t[e])})}return o};var w=function(e,t){if(!Object.setPrototypeOf){return false}return a(function(){var r=function Subclass(t){var r=new e(t);Object.setPrototypeOf(r,Subclass.prototype);return r};Object.setPrototypeOf(r,e);r.prototype=O(e.prototype,{constructor:{value:r}});return t(r)})};var j=function(){if(typeof self!==\"undefined\"){return self}if(typeof window!==\"undefined\"){return window}if(typeof global!==\"undefined\"){return global}throw new Error(\"unable to locate global object\")};var S=j();var T=S.isFinite;var I=Function.call.bind(String.prototype.indexOf);var E=Function.apply.bind(Array.prototype.indexOf);var P=Function.call.bind(Array.prototype.concat);var C=Function.call.bind(String.prototype.slice);var M=Function.call.bind(Array.prototype.push);var x=Function.apply.bind(Array.prototype.push);var N=Function.call.bind(Array.prototype.shift);var A=Math.max;var R=Math.min;var _=Math.floor;var k=Math.abs;var L=Math.exp;var F=Math.log;var D=Math.sqrt;var z=Function.call.bind(Object.prototype.hasOwnProperty);var q;var W=function(){};var G=S.Map;var H=G&&G.prototype[\"delete\"];var V=G&&G.prototype.get;var B=G&&G.prototype.has;var U=G&&G.prototype.set;var $=S.Symbol||{};var J=$.species||\"@@species\";var X=Number.isNaN||function isNaN(e){return e!==e};var K=Number.isFinite||function isFinite(e){return typeof e===\"number\"&&T(e)};var Z=d(Math.sign)?Math.sign:function sign(e){var t=Number(e);if(t===0){return t}if(X(t)){return t}return t<0?-1:1};var Y=function log1p(e){var t=Number(e);if(t<-1||X(t)){return NaN}if(t===0||t===Infinity){return t}if(t===-1){return-Infinity}return 1+t-1===0?t:t*(F(1+t)/(1+t-1))};var Q=function isArguments(e){return g(e)===\"[object Arguments]\"};var ee=function isArguments(e){return e!==null&&typeof e===\"object\"&&typeof e.length===\"number\"&&e.length>=0&&g(e)!==\"[object Array]\"&&g(e.callee)===\"[object Function]\"};var te=Q(arguments)?Q:ee;var re={primitive:function(e){return e===null||typeof e!==\"function\"&&typeof e!==\"object\"},string:function(e){return g(e)===\"[object String]\"},regex:function(e){return g(e)===\"[object RegExp]\"},symbol:function(e){return typeof S.Symbol===\"function\"&&typeof e===\"symbol\"}};var ne=function overrideNative(e,t,r){var n=e[t];h(e,t,r,true);m.preserveToString(e[t],n)};var oe=typeof $===\"function\"&&typeof $[\"for\"]===\"function\"&&re.symbol($());var ie=re.symbol($.iterator)?$.iterator:\"_es6-shim iterator_\";if(S.Set&&typeof(new S.Set)[\"@@iterator\"]===\"function\"){ie=\"@@iterator\"}if(!S.Reflect){h(S,\"Reflect\",{},true)}var ae=S.Reflect;var ue=String;var fe=typeof document===\"undefined\"||!document?null:document.all;var se=fe==null?function isNullOrUndefined(e){return e==null}:function isNullOrUndefinedAndNotDocumentAll(e){return e==null&&e!==fe};var ce={Call:function Call(t,r){var n=arguments.length>2?arguments[2]:[];if(!ce.IsCallable(t)){throw new TypeError(t+\" is not a function\")}return e(t,r,n)},RequireObjectCoercible:function(e,t){if(se(e)){throw new TypeError(t||\"Cannot call method on \"+e)}return e},TypeIsObject:function(e){if(e===void 0||e===null||e===true||e===false){return false}return typeof e===\"function\"||typeof e===\"object\"||e===fe},ToObject:function(e,t){return Object(ce.RequireObjectCoercible(e,t))},IsCallable:d,IsConstructor:function(e){return ce.IsCallable(e)},ToInt32:function(e){return ce.ToNumber(e)>>0},ToUint32:function(e){return ce.ToNumber(e)>>>0},ToNumber:function(e){if(g(e)===\"[object Symbol]\"){throw new TypeError(\"Cannot convert a Symbol value to a number\")}return+e},ToInteger:function(e){var t=ce.ToNumber(e);if(X(t)){return 0}if(t===0||!K(t)){return t}return(t>0?1:-1)*_(k(t))},ToLength:function(e){var t=ce.ToInteger(e);if(t<=0){return 0}if(t>Number.MAX_SAFE_INTEGER){return Number.MAX_SAFE_INTEGER}return t},SameValue:function(e,t){if(e===t){if(e===0){return 1/e===1/t}return true}return X(e)&&X(t)},SameValueZero:function(e,t){return e===t||X(e)&&X(t)},IsIterable:function(e){return ce.TypeIsObject(e)&&(typeof e[ie]!==\"undefined\"||te(e))},GetIterator:function(e){if(te(e)){return new q(e,\"value\")}var t=ce.GetMethod(e,ie);if(!ce.IsCallable(t)){throw new TypeError(\"value is not an iterable\")}var r=ce.Call(t,e);if(!ce.TypeIsObject(r)){throw new TypeError(\"bad iterator\")}return r},GetMethod:function(e,t){var r=ce.ToObject(e)[t];if(se(r)){return void 0}if(!ce.IsCallable(r)){throw new TypeError(\"Method not callable: \"+t)}return r},IteratorComplete:function(e){return!!e.done},IteratorClose:function(e,t){var r=ce.GetMethod(e,\"return\");if(r===void 0){return}var n,o;try{n=ce.Call(r,e)}catch(i){o=i}if(t){return}if(o){throw o}if(!ce.TypeIsObject(n)){throw new TypeError(\"Iterator's return method returned a non-object.\")}},IteratorNext:function(e){var t=arguments.length>1?e.next(arguments[1]):e.next();if(!ce.TypeIsObject(t)){throw new TypeError(\"bad iterator\")}return t},IteratorStep:function(e){var t=ce.IteratorNext(e);var r=ce.IteratorComplete(t);return r?false:t},Construct:function(e,t,r,n){var o=typeof r===\"undefined\"?e:r;if(!n&&ae.construct){return ae.construct(e,t,o)}var i=o.prototype;if(!ce.TypeIsObject(i)){i=Object.prototype}var a=O(i);var u=ce.Call(e,a,t);return ce.TypeIsObject(u)?u:a},SpeciesConstructor:function(e,t){var r=e.constructor;if(r===void 0){return t}if(!ce.TypeIsObject(r)){throw new TypeError(\"Bad constructor\")}var n=r[J];if(se(n)){return t}if(!ce.IsConstructor(n)){throw new TypeError(\"Bad @@species\")}return n},CreateHTML:function(e,t,r,n){var o=ce.ToString(e);var i=\"<\"+t;if(r!==\"\"){var a=ce.ToString(n);var u=a.replace(/\"/g,\"&quot;\");i+=\" \"+r+'=\"'+u+'\"'}var f=i+\">\";var s=f+o;return s+\"</\"+t+\">\"},IsRegExp:function IsRegExp(e){if(!ce.TypeIsObject(e)){return false}var t=e[$.match];if(typeof t!==\"undefined\"){return!!t}return re.regex(e)},ToString:function ToString(e){return ue(e)}};if(s&&oe){var le=function defineWellKnownSymbol(e){if(re.symbol($[e])){return $[e]}var t=$[\"for\"](\"Symbol.\"+e);Object.defineProperty($,e,{configurable:false,enumerable:false,writable:false,value:t});return t};if(!re.symbol($.search)){var pe=le(\"search\");var ve=String.prototype.search;h(RegExp.prototype,pe,function search(e){return ce.Call(ve,e,[this])});var ye=function search(e){var t=ce.RequireObjectCoercible(this);if(!se(e)){var r=ce.GetMethod(e,pe);if(typeof r!==\"undefined\"){return ce.Call(r,e,[t])}}return ce.Call(ve,t,[ce.ToString(e)])};ne(String.prototype,\"search\",ye)}if(!re.symbol($.replace)){var he=le(\"replace\");var be=String.prototype.replace;h(RegExp.prototype,he,function replace(e,t){return ce.Call(be,e,[this,t])});var ge=function replace(e,t){var r=ce.RequireObjectCoercible(this);if(!se(e)){var n=ce.GetMethod(e,he);if(typeof n!==\"undefined\"){return ce.Call(n,e,[r,t])}}return ce.Call(be,r,[ce.ToString(e),t])};ne(String.prototype,\"replace\",ge)}if(!re.symbol($.split)){var de=le(\"split\");var me=String.prototype.split;h(RegExp.prototype,de,function split(e,t){return ce.Call(me,e,[this,t])});var Oe=function split(e,t){var r=ce.RequireObjectCoercible(this);if(!se(e)){var n=ce.GetMethod(e,de);if(typeof n!==\"undefined\"){return ce.Call(n,e,[r,t])}}return ce.Call(me,r,[ce.ToString(e),t])};ne(String.prototype,\"split\",Oe)}var we=re.symbol($.match);var je=we&&function(){var e={};e[$.match]=function(){return 42};return\"a\".match(e)!==42}();if(!we||je){var Se=le(\"match\");var Te=String.prototype.match;h(RegExp.prototype,Se,function match(e){return ce.Call(Te,e,[this])});var Ie=function match(e){var t=ce.RequireObjectCoercible(this);if(!se(e)){var r=ce.GetMethod(e,Se);if(typeof r!==\"undefined\"){return ce.Call(r,e,[t])}}return ce.Call(Te,t,[ce.ToString(e)])};ne(String.prototype,\"match\",Ie)}}var Ee=function wrapConstructor(e,t,r){m.preserveToString(t,e);if(Object.setPrototypeOf){Object.setPrototypeOf(e,t)}if(s){l(Object.getOwnPropertyNames(e),function(n){if(n in W||r[n]){return}m.proxy(e,n,t)})}else{l(Object.keys(e),function(n){if(n in W||r[n]){return}t[n]=e[n]})}t.prototype=e.prototype;m.redefine(e.prototype,\"constructor\",t)};var Pe=function(){return this};var Ce=function(e){if(s&&!z(e,J)){m.getter(e,J,Pe)}};var Me=function(e,t){var r=t||function iterator(){return this};h(e,ie,r);if(!e[ie]&&re.symbol(ie)){e[ie]=r}};var xe=function createDataProperty(e,t,r){if(s){Object.defineProperty(e,t,{configurable:true,enumerable:true,writable:true,value:r})}else{e[t]=r}};var Ne=function createDataPropertyOrThrow(e,t,r){xe(e,t,r);if(!ce.SameValue(e[t],r)){throw new TypeError(\"property is nonconfigurable\")}};var Ae=function(e,t,r,n){if(!ce.TypeIsObject(e)){throw new TypeError(\"Constructor requires `new`: \"+t.name)}var o=t.prototype;if(!ce.TypeIsObject(o)){o=r}var i=O(o);for(var a in n){if(z(n,a)){var u=n[a];h(i,a,u,true)}}return i};if(String.fromCodePoint&&String.fromCodePoint.length!==1){var Re=String.fromCodePoint;ne(String,\"fromCodePoint\",function fromCodePoint(e){return ce.Call(Re,this,arguments)})}var _e={fromCodePoint:function fromCodePoint(e){var t=[];var r;for(var n=0,o=arguments.length;n<o;n++){r=Number(arguments[n]);if(!ce.SameValue(r,ce.ToInteger(r))||r<0||r>1114111){throw new RangeError(\"Invalid code point \"+r)}if(r<65536){M(t,String.fromCharCode(r))}else{r-=65536;M(t,String.fromCharCode((r>>10)+55296));M(t,String.fromCharCode(r%1024+56320))}}return t.join(\"\")},raw:function raw(e){var t=ce.ToObject(e,\"bad callSite\");var r=ce.ToObject(t.raw,\"bad raw value\");var n=r.length;var o=ce.ToLength(n);if(o<=0){return\"\"}var i=[];var a=0;var u,f,s,c;while(a<o){u=ce.ToString(a);s=ce.ToString(r[u]);M(i,s);if(a+1>=o){break}f=a+1<arguments.length?arguments[a+1]:\"\";c=ce.ToString(f);M(i,c);a+=1}return i.join(\"\")}};if(String.raw&&String.raw({raw:{0:\"x\",1:\"y\",length:2}})!==\"xy\"){ne(String,\"raw\",_e.raw)}b(String,_e);var ke=function repeat(e,t){if(t<1){return\"\"}if(t%2){return repeat(e,t-1)+e}var r=repeat(e,t/2);return r+r};var Le=Infinity;var Fe={repeat:function repeat(e){var t=ce.ToString(ce.RequireObjectCoercible(this));var r=ce.ToInteger(e);if(r<0||r>=Le){throw new RangeError(\"repeat count must be less than infinity and not overflow maximum string size\")}return ke(t,r)},startsWith:function startsWith(e){var t=ce.ToString(ce.RequireObjectCoercible(this));if(ce.IsRegExp(e)){throw new TypeError('Cannot call method \"startsWith\" with a regex')}var r=ce.ToString(e);var n;if(arguments.length>1){n=arguments[1]}var o=A(ce.ToInteger(n),0);return C(t,o,o+r.length)===r},endsWith:function endsWith(e){var t=ce.ToString(ce.RequireObjectCoercible(this));if(ce.IsRegExp(e)){throw new TypeError('Cannot call method \"endsWith\" with a regex')}var r=ce.ToString(e);var n=t.length;var o;if(arguments.length>1){o=arguments[1]}var i=typeof o===\"undefined\"?n:ce.ToInteger(o);var a=R(A(i,0),n);return C(t,a-r.length,a)===r},includes:function includes(e){if(ce.IsRegExp(e)){throw new TypeError('\"includes\" does not accept a RegExp')}var t=ce.ToString(e);var r;if(arguments.length>1){r=arguments[1]}return I(this,t,r)!==-1},codePointAt:function codePointAt(e){var t=ce.ToString(ce.RequireObjectCoercible(this));var r=ce.ToInteger(e);var n=t.length;if(r>=0&&r<n){var o=t.charCodeAt(r);var i=r+1===n;if(o<55296||o>56319||i){return o}var a=t.charCodeAt(r+1);if(a<56320||a>57343){return o}return(o-55296)*1024+(a-56320)+65536}}};if(String.prototype.includes&&\"a\".includes(\"a\",Infinity)!==false){ne(String.prototype,\"includes\",Fe.includes)}if(String.prototype.startsWith&&String.prototype.endsWith){var De=i(function(){return\"/a/\".startsWith(/a/)});var ze=a(function(){return\"abc\".startsWith(\"a\",Infinity)===false});if(!De||!ze){ne(String.prototype,\"startsWith\",Fe.startsWith);ne(String.prototype,\"endsWith\",Fe.endsWith)}}if(oe){var qe=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".startsWith(e)});if(!qe){ne(String.prototype,\"startsWith\",Fe.startsWith)}var We=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".endsWith(e)});if(!We){ne(String.prototype,\"endsWith\",Fe.endsWith)}var Ge=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".includes(e)});if(!Ge){ne(String.prototype,\"includes\",Fe.includes)}}b(String.prototype,Fe);var He=[\"\\t\\n\\x0B\\f\\r \\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\",\"\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\",\"\\u2029\\ufeff\"].join(\"\");var Ve=new RegExp(\"(^[\"+He+\"]+)|([\"+He+\"]+$)\",\"g\");var Be=function trim(){return ce.ToString(ce.RequireObjectCoercible(this)).replace(Ve,\"\")};var Ue=[\"\\x85\",\"\\u200b\",\"\\ufffe\"].join(\"\");var $e=new RegExp(\"[\"+Ue+\"]\",\"g\");var Je=/^[-+]0x[0-9a-f]+$/i;var Xe=Ue.trim().length!==Ue.length;h(String.prototype,\"trim\",Be,Xe);var Ke=function(e){return{value:e,done:arguments.length===0}};var Ze=function(e){ce.RequireObjectCoercible(e);this._s=ce.ToString(e);this._i=0};Ze.prototype.next=function(){var e=this._s;var t=this._i;if(typeof e===\"undefined\"||t>=e.length){this._s=void 0;return Ke()}var r=e.charCodeAt(t);var n,o;if(r<55296||r>56319||t+1===e.length){o=1}else{n=e.charCodeAt(t+1);o=n<56320||n>57343?1:2}this._i=t+o;return Ke(e.substr(t,o))};Me(Ze.prototype);Me(String.prototype,function(){return new Ze(this)});var Ye={from:function from(e){var r=this;var n;if(arguments.length>1){n=arguments[1]}var o,i;if(typeof n===\"undefined\"){o=false}else{if(!ce.IsCallable(n)){throw new TypeError(\"Array.from: when provided, the second argument must be a function\")}if(arguments.length>2){i=arguments[2]}o=true}var a=typeof(te(e)||ce.GetMethod(e,ie))!==\"undefined\";var u,f,s;if(a){f=ce.IsConstructor(r)?Object(new r):[];var c=ce.GetIterator(e);var l,p;s=0;while(true){l=ce.IteratorStep(c);if(l===false){break}p=l.value;try{if(o){p=typeof i===\"undefined\"?n(p,s):t(n,i,p,s)}f[s]=p}catch(v){ce.IteratorClose(c,true);throw v}s+=1}u=s}else{var y=ce.ToObject(e);u=ce.ToLength(y.length);f=ce.IsConstructor(r)?Object(new r(u)):new Array(u);var h;for(s=0;s<u;++s){h=y[s];if(o){h=typeof i===\"undefined\"?n(h,s):t(n,i,h,s)}Ne(f,s,h)}}f.length=u;return f},of:function of(){var e=arguments.length;var t=this;var n=r(t)||!ce.IsCallable(t)?new Array(e):ce.Construct(t,[e]);for(var o=0;o<e;++o){Ne(n,o,arguments[o])}n.length=e;return n}};b(Array,Ye);Ce(Array);q=function(e,t){this.i=0;this.array=e;this.kind=t};b(q.prototype,{next:function(){var e=this.i;var t=this.array;if(!(this instanceof q)){throw new TypeError(\"Not an ArrayIterator\")}if(typeof t!==\"undefined\"){var r=ce.ToLength(t.length);for(;e<r;e++){var n=this.kind;var o;if(n===\"key\"){o=e}else if(n===\"value\"){o=t[e]}else if(n===\"entry\"){o=[e,t[e]]}this.i=e+1;return Ke(o)}}this.array=void 0;return Ke()}});Me(q.prototype);var Qe=Array.of===Ye.of||function(){var e=function Foo(e){this.length=e};e.prototype=[];var t=Array.of.apply(e,[1,2]);return t instanceof e&&t.length===2}();if(!Qe){ne(Array,\"of\",Ye.of)}var et={copyWithin:function copyWithin(e,t){var r=ce.ToObject(this);var n=ce.ToLength(r.length);var o=ce.ToInteger(e);var i=ce.ToInteger(t);var a=o<0?A(n+o,0):R(o,n);var u=i<0?A(n+i,0):R(i,n);var f;if(arguments.length>2){f=arguments[2]}var s=typeof f===\"undefined\"?n:ce.ToInteger(f);var c=s<0?A(n+s,0):R(s,n);var l=R(c-u,n-a);var p=1;if(u<a&&a<u+l){p=-1;u+=l-1;a+=l-1}while(l>0){if(u in r){r[a]=r[u]}else{delete r[a]}u+=p;a+=p;l-=1}return r},fill:function fill(e){var t;if(arguments.length>1){t=arguments[1]}var r;if(arguments.length>2){r=arguments[2]}var n=ce.ToObject(this);var o=ce.ToLength(n.length);t=ce.ToInteger(typeof t===\"undefined\"?0:t);r=ce.ToInteger(typeof r===\"undefined\"?o:r);var i=t<0?A(o+t,0):R(t,o);var a=r<0?o+r:r;for(var u=i;u<o&&u<a;++u){n[u]=e}return n},find:function find(e){var r=ce.ToObject(this);var n=ce.ToLength(r.length);if(!ce.IsCallable(e)){throw new TypeError(\"Array#find: predicate must be a function\")}var o=arguments.length>1?arguments[1]:null;for(var i=0,a;i<n;i++){a=r[i];if(o){if(t(e,o,a,i,r)){return a}}else if(e(a,i,r)){return a}}},findIndex:function findIndex(e){var r=ce.ToObject(this);var n=ce.ToLength(r.length);if(!ce.IsCallable(e)){throw new TypeError(\"Array#findIndex: predicate must be a function\")}var o=arguments.length>1?arguments[1]:null;for(var i=0;i<n;i++){if(o){if(t(e,o,r[i],i,r)){return i}}else if(e(r[i],i,r)){return i}}return-1},keys:function keys(){return new q(this,\"key\")},values:function values(){return new q(this,\"value\")},entries:function entries(){return new q(this,\"entry\")}};if(Array.prototype.keys&&!ce.IsCallable([1].keys().next)){delete Array.prototype.keys}if(Array.prototype.entries&&!ce.IsCallable([1].entries().next)){delete Array.prototype.entries}if(Array.prototype.keys&&Array.prototype.entries&&!Array.prototype.values&&Array.prototype[ie]){b(Array.prototype,{values:Array.prototype[ie]});if(re.symbol($.unscopables)){Array.prototype[$.unscopables].values=true}}if(c&&Array.prototype.values&&Array.prototype.values.name!==\"values\"){var tt=Array.prototype.values;ne(Array.prototype,\"values\",function values(){return ce.Call(tt,this,arguments)});h(Array.prototype,ie,Array.prototype.values,true)}b(Array.prototype,et);if(1/[true].indexOf(true,-0)<0){h(Array.prototype,\"indexOf\",function indexOf(e){var t=E(this,arguments);if(t===0&&1/t<0){return 0}return t},true)}Me(Array.prototype,function(){return this.values()});if(Object.getPrototypeOf){Me(Object.getPrototypeOf([].values()))}var rt=function(){return a(function(){return Array.from({length:-1}).length===0})}();var nt=function(){var e=Array.from([0].entries());return e.length===1&&r(e[0])&&e[0][0]===0&&e[0][1]===0}();if(!rt||!nt){ne(Array,\"from\",Ye.from)}var ot=function(){return a(function(){return Array.from([0],void 0)})}();if(!ot){var it=Array.from;ne(Array,\"from\",function from(e){if(arguments.length>1&&typeof arguments[1]!==\"undefined\"){return ce.Call(it,this,arguments)}else{return t(it,this,e)}})}var at=-(Math.pow(2,32)-1);var ut=function(e,r){var n={length:at};n[r?(n.length>>>0)-1:0]=true;return a(function(){t(e,n,function(){throw new RangeError(\"should not reach here\")},[]);return true})};if(!ut(Array.prototype.forEach)){var ft=Array.prototype.forEach;ne(Array.prototype,\"forEach\",function forEach(e){return ce.Call(ft,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.map)){var st=Array.prototype.map;ne(Array.prototype,\"map\",function map(e){return ce.Call(st,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.filter)){var ct=Array.prototype.filter;ne(Array.prototype,\"filter\",function filter(e){return ce.Call(ct,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.some)){var lt=Array.prototype.some;ne(Array.prototype,\"some\",function some(e){return ce.Call(lt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.every)){var pt=Array.prototype.every;ne(Array.prototype,\"every\",function every(e){return ce.Call(pt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.reduce)){var vt=Array.prototype.reduce;ne(Array.prototype,\"reduce\",function reduce(e){return ce.Call(vt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.reduceRight,true)){var yt=Array.prototype.reduceRight;ne(Array.prototype,\"reduceRight\",function reduceRight(e){return ce.Call(yt,this.length>=0?this:[],arguments)},true)}var ht=Number(\"0o10\")!==8;var bt=Number(\"0b10\")!==2;var gt=y(Ue,function(e){return Number(e+0+e)===0});if(ht||bt||gt){var dt=Number;var mt=/^0b[01]+$/i;var Ot=/^0o[0-7]+$/i;var wt=mt.test.bind(mt);var jt=Ot.test.bind(Ot);var St=function(e){var t;if(typeof e.valueOf===\"function\"){t=e.valueOf();if(re.primitive(t)){return t}}if(typeof e.toString===\"function\"){t=e.toString();if(re.primitive(t)){return t}}throw new TypeError(\"No default value\")};var Tt=$e.test.bind($e);var It=Je.test.bind(Je);var Et=function(){var e=function Number(t){var r;if(arguments.length>0){r=re.primitive(t)?t:St(t,\"number\")}else{r=0}if(typeof r===\"string\"){r=ce.Call(Be,r);if(wt(r)){r=parseInt(C(r,2),2)}else if(jt(r)){r=parseInt(C(r,2),8)}else if(Tt(r)||It(r)){r=NaN}}var n=this;var o=a(function(){dt.prototype.valueOf.call(n);return true});if(n instanceof e&&!o){return new dt(r)}return dt(r)};return e}();Ee(dt,Et,{});b(Et,{NaN:dt.NaN,MAX_VALUE:dt.MAX_VALUE,MIN_VALUE:dt.MIN_VALUE,NEGATIVE_INFINITY:dt.NEGATIVE_INFINITY,POSITIVE_INFINITY:dt.POSITIVE_INFINITY});Number=Et;m.redefine(S,\"Number\",Et)}var Pt=Math.pow(2,53)-1;b(Number,{MAX_SAFE_INTEGER:Pt,MIN_SAFE_INTEGER:-Pt,EPSILON:2.220446049250313e-16,parseInt:S.parseInt,parseFloat:S.parseFloat,isFinite:K,isInteger:function isInteger(e){return K(e)&&ce.ToInteger(e)===e},isSafeInteger:function isSafeInteger(e){return Number.isInteger(e)&&k(e)<=Number.MAX_SAFE_INTEGER},isNaN:X});h(Number,\"parseInt\",S.parseInt,Number.parseInt!==S.parseInt);if([,1].find(function(){return true})===1){ne(Array.prototype,\"find\",et.find)}if([,1].findIndex(function(){return true})!==0){ne(Array.prototype,\"findIndex\",et.findIndex)}var Ct=Function.bind.call(Function.bind,Object.prototype.propertyIsEnumerable);var Mt=function ensureEnumerable(e,t){if(s&&Ct(e,t)){Object.defineProperty(e,t,{enumerable:false})}};var xt=function sliceArgs(){var e=Number(this);var t=arguments.length;var r=t-e;var n=new Array(r<0?0:r);for(var o=e;o<t;++o){n[o-e]=arguments[o]}return n};var Nt=function assignTo(e){return function assignToSource(t,r){t[r]=e[r];return t}};var At=function(e,t){var r=n(Object(t));var o;if(ce.IsCallable(Object.getOwnPropertySymbols)){o=v(Object.getOwnPropertySymbols(Object(t)),Ct(t))}return p(P(r,o||[]),Nt(t),e)};var Rt={assign:function(e,t){var r=ce.ToObject(e,\"Cannot convert undefined or null to object\");return p(ce.Call(xt,1,arguments),At,r)},is:function is(e,t){return ce.SameValue(e,t)}};var _t=Object.assign&&Object.preventExtensions&&function(){var e=Object.preventExtensions({1:2});try{Object.assign(e,\"xy\")}catch(t){return e[1]===\"y\"}}();if(_t){ne(Object,\"assign\",Rt.assign)}b(Object,Rt);if(s){var kt={setPrototypeOf:function(e,r){var n;var o=function(e,t){if(!ce.TypeIsObject(e)){throw new TypeError(\"cannot set prototype on a non-object\")}if(!(t===null||ce.TypeIsObject(t))){throw new TypeError(\"can only set prototype to an object or null\"+t)}};var i=function(e,r){o(e,r);t(n,e,r);return e};try{n=e.getOwnPropertyDescriptor(e.prototype,r).set;t(n,{},null)}catch(a){if(e.prototype!=={}[r]){return}n=function(e){this[r]=e};i.polyfill=i(i({},null),e.prototype)instanceof e}return i}(Object,\"__proto__\")};b(Object,kt)}if(Object.setPrototypeOf&&Object.getPrototypeOf&&Object.getPrototypeOf(Object.setPrototypeOf({},null))!==null&&Object.getPrototypeOf(Object.create(null))===null){(function(){var e=Object.create(null);var t=Object.getPrototypeOf;var r=Object.setPrototypeOf;Object.getPrototypeOf=function(r){var n=t(r);return n===e?null:n};Object.setPrototypeOf=function(t,n){var o=n===null?e:n;return r(t,o)};Object.setPrototypeOf.polyfill=false})()}var Lt=!i(function(){return Object.keys(\"foo\")});if(!Lt){var Ft=Object.keys;ne(Object,\"keys\",function keys(e){return Ft(ce.ToObject(e))});n=Object.keys}var Dt=i(function(){return Object.keys(/a/g)});if(Dt){var zt=Object.keys;ne(Object,\"keys\",function keys(e){if(re.regex(e)){var t=[];for(var r in e){if(z(e,r)){M(t,r)}}return t}return zt(e)});n=Object.keys}if(Object.getOwnPropertyNames){var qt=!i(function(){return Object.getOwnPropertyNames(\"foo\")});if(!qt){var Wt=typeof window===\"object\"?Object.getOwnPropertyNames(window):[];var Gt=Object.getOwnPropertyNames;ne(Object,\"getOwnPropertyNames\",function getOwnPropertyNames(e){var t=ce.ToObject(e);if(g(t)===\"[object Window]\"){try{return Gt(t)}catch(r){return P([],Wt)}}return Gt(t)})}}if(Object.getOwnPropertyDescriptor){var Ht=!i(function(){return Object.getOwnPropertyDescriptor(\"foo\",\"bar\")});if(!Ht){var Vt=Object.getOwnPropertyDescriptor;ne(Object,\"getOwnPropertyDescriptor\",function getOwnPropertyDescriptor(e,t){return Vt(ce.ToObject(e),t)})}}if(Object.seal){var Bt=!i(function(){return Object.seal(\"foo\")});if(!Bt){var Ut=Object.seal;ne(Object,\"seal\",function seal(e){if(!ce.TypeIsObject(e)){return e}return Ut(e)})}}if(Object.isSealed){var $t=!i(function(){return Object.isSealed(\"foo\")});if(!$t){var Jt=Object.isSealed;ne(Object,\"isSealed\",function isSealed(e){if(!ce.TypeIsObject(e)){return true}return Jt(e)})}}if(Object.freeze){var Xt=!i(function(){return Object.freeze(\"foo\")});if(!Xt){var Kt=Object.freeze;ne(Object,\"freeze\",function freeze(e){if(!ce.TypeIsObject(e)){return e}return Kt(e)})}}if(Object.isFrozen){var Zt=!i(function(){return Object.isFrozen(\"foo\")});if(!Zt){var Yt=Object.isFrozen;ne(Object,\"isFrozen\",function isFrozen(e){if(!ce.TypeIsObject(e)){return true}return Yt(e)})}}if(Object.preventExtensions){var Qt=!i(function(){return Object.preventExtensions(\"foo\")});if(!Qt){var er=Object.preventExtensions;ne(Object,\"preventExtensions\",function preventExtensions(e){if(!ce.TypeIsObject(e)){return e}return er(e)})}}if(Object.isExtensible){var tr=!i(function(){return Object.isExtensible(\"foo\")});if(!tr){var rr=Object.isExtensible;ne(Object,\"isExtensible\",function isExtensible(e){if(!ce.TypeIsObject(e)){return false}return rr(e)})}}if(Object.getPrototypeOf){var nr=!i(function(){return Object.getPrototypeOf(\"foo\")});if(!nr){var or=Object.getPrototypeOf;ne(Object,\"getPrototypeOf\",function getPrototypeOf(e){return or(ce.ToObject(e))})}}var ir=s&&function(){var e=Object.getOwnPropertyDescriptor(RegExp.prototype,\"flags\");return e&&ce.IsCallable(e.get)}();if(s&&!ir){var ar=function flags(){if(!ce.TypeIsObject(this)){throw new TypeError(\"Method called on incompatible type: must be an object.\")}var e=\"\";if(this.global){e+=\"g\"}if(this.ignoreCase){e+=\"i\"}if(this.multiline){e+=\"m\"}if(this.unicode){e+=\"u\"}if(this.sticky){e+=\"y\"}return e};m.getter(RegExp.prototype,\"flags\",ar)}var ur=s&&a(function(){return String(new RegExp(/a/g,\"i\"))===\"/a/i\"});var fr=oe&&s&&function(){var e=/./;e[$.match]=false;return RegExp(e)===e}();var sr=a(function(){return RegExp.prototype.toString.call({source:\"abc\"})===\"/abc/\"});var cr=sr&&a(function(){return RegExp.prototype.toString.call({source:\"a\",flags:\"b\"})===\"/a/b\"});if(!sr||!cr){var lr=RegExp.prototype.toString;h(RegExp.prototype,\"toString\",function toString(){var e=ce.RequireObjectCoercible(this);if(re.regex(e)){return t(lr,e)}var r=ue(e.source);var n=ue(e.flags);return\"/\"+r+\"/\"+n},true);m.preserveToString(RegExp.prototype.toString,lr)}if(s&&(!ur||fr)){var pr=Object.getOwnPropertyDescriptor(RegExp.prototype,\"flags\").get;var vr=Object.getOwnPropertyDescriptor(RegExp.prototype,\"source\")||{};var yr=function(){return this.source};var hr=ce.IsCallable(vr.get)?vr.get:yr;var br=RegExp;var gr=function(){return function RegExp(e,t){var r=ce.IsRegExp(e);var n=this instanceof RegExp;if(!n&&r&&typeof t===\"undefined\"&&e.constructor===RegExp){return e}var o=e;var i=t;if(re.regex(e)){o=ce.Call(hr,e);i=typeof t===\"undefined\"?ce.Call(pr,e):t;return new RegExp(o,i)}else if(r){o=e.source;i=typeof t===\"undefined\"?e.flags:t}return new br(e,t)}}();Ee(br,gr,{$input:true});RegExp=gr;m.redefine(S,\"RegExp\",gr)}if(s){var dr={input:\"$_\",lastMatch:\"$&\",lastParen:\"$+\",leftContext:\"$`\",rightContext:\"$'\"};l(n(dr),function(e){if(e in RegExp&&!(dr[e]in RegExp)){m.getter(RegExp,dr[e],function get(){return RegExp[e]})}})}Ce(RegExp);var mr=1/Number.EPSILON;var Or=function roundTiesToEven(e){return e+mr-mr};var wr=Math.pow(2,-23);var jr=Math.pow(2,127)*(2-wr);var Sr=Math.pow(2,-126);var Tr=Math.E;var Ir=Math.LOG2E;var Er=Math.LOG10E;var Pr=Number.prototype.clz;delete Number.prototype.clz;var Cr={acosh:function acosh(e){var t=Number(e);if(X(t)||e<1){return NaN}if(t===1){return 0}if(t===Infinity){return t}var r=1/(t*t);if(t<2){return Y(t-1+D(1-r)*t)}var n=t/2;return Y(n+D(1-r)*n-1)+1/Ir},asinh:function asinh(e){var t=Number(e);if(t===0||!T(t)){return t}var r=k(t);var n=r*r;var o=Z(t);if(r<1){return o*Y(r+n/(D(n+1)+1))}return o*(Y(r/2+D(1+1/n)*r/2-1)+1/Ir)},atanh:function atanh(e){var t=Number(e);if(t===0){return t}if(t===-1){return-Infinity}if(t===1){return Infinity}if(X(t)||t<-1||t>1){return NaN}var r=k(t);return Z(t)*Y(2*r/(1-r))/2},cbrt:function cbrt(e){var t=Number(e);if(t===0){return t}var r=t<0;var n;if(r){t=-t}if(t===Infinity){n=Infinity}else{n=L(F(t)/3);n=(t/(n*n)+2*n)/3}return r?-n:n},clz32:function clz32(e){var t=Number(e);var r=ce.ToUint32(t);if(r===0){return 32}return Pr?ce.Call(Pr,r):31-_(F(r+.5)*Ir)},cosh:function cosh(e){var t=Number(e);if(t===0){return 1}if(X(t)){return NaN}if(!T(t)){return Infinity}var r=L(k(t)-1);return(r+1/(r*Tr*Tr))*(Tr/2)},expm1:function expm1(e){var t=Number(e);if(t===-Infinity){return-1}if(!T(t)||t===0){return t}if(k(t)>.5){return L(t)-1}var r=t;var n=0;var o=1;while(n+r!==n){n+=r;o+=1;r*=t/o}return n},hypot:function hypot(e,t){var r=0;var n=0;for(var o=0;o<arguments.length;++o){var i=k(Number(arguments[o]));if(n<i){r*=n/i*(n/i);r+=1;n=i}else{r+=i>0?i/n*(i/n):i}}return n===Infinity?Infinity:n*D(r)},log2:function log2(e){return F(e)*Ir},log10:function log10(e){return F(e)*Er},log1p:Y,sign:Z,sinh:function sinh(e){var t=Number(e);if(!T(t)||t===0){return t}var r=k(t);if(r<1){var n=Math.expm1(r);return Z(t)*n*(1+1/(n+1))/2}var o=L(r-1);return Z(t)*(o-1/(o*Tr*Tr))*(Tr/2)},tanh:function tanh(e){var t=Number(e);if(X(t)||t===0){return t}if(t>=20){return 1}if(t<=-20){return-1}return(Math.expm1(t)-Math.expm1(-t))/(L(t)+L(-t))},trunc:function trunc(e){var t=Number(e);return t<0?-_(-t):_(t)},imul:function imul(e,t){var r=ce.ToUint32(e);var n=ce.ToUint32(t);var o=r>>>16&65535;var i=r&65535;var a=n>>>16&65535;var u=n&65535;return i*u+(o*u+i*a<<16>>>0)|0},fround:function fround(e){var t=Number(e);if(t===0||t===Infinity||t===-Infinity||X(t)){return t}var r=Z(t);var n=k(t);if(n<Sr){return r*Or(n/Sr/wr)*Sr*wr}var o=(1+wr/Number.EPSILON)*n;var i=o-(o-n);if(i>jr||X(i)){return r*Infinity}return r*i}};var Mr=function withinULPDistance(e,t,r){return k(1-e/t)/Number.EPSILON<(r||8)};b(Math,Cr);h(Math,\"sinh\",Cr.sinh,Math.sinh(710)===Infinity);h(Math,\"cosh\",Cr.cosh,Math.cosh(710)===Infinity);h(Math,\"log1p\",Cr.log1p,Math.log1p(-1e-17)!==-1e-17);h(Math,\"asinh\",Cr.asinh,Math.asinh(-1e7)!==-Math.asinh(1e7));h(Math,\"asinh\",Cr.asinh,Math.asinh(1e300)===Infinity);h(Math,\"atanh\",Cr.atanh,Math.atanh(1e-300)===0);h(Math,\"tanh\",Cr.tanh,Math.tanh(-2e-17)!==-2e-17);\nh(Math,\"acosh\",Cr.acosh,Math.acosh(Number.MAX_VALUE)===Infinity);h(Math,\"acosh\",Cr.acosh,!Mr(Math.acosh(1+Number.EPSILON),Math.sqrt(2*Number.EPSILON)));h(Math,\"cbrt\",Cr.cbrt,!Mr(Math.cbrt(1e-300),1e-100));h(Math,\"sinh\",Cr.sinh,Math.sinh(-2e-17)!==-2e-17);var xr=Math.expm1(10);h(Math,\"expm1\",Cr.expm1,xr>22025.465794806718||xr<22025.465794806718);var Nr=Math.round;var Ar=Math.round(.5-Number.EPSILON/4)===0&&Math.round(-.5+Number.EPSILON/3.99)===1;var Rr=mr+1;var _r=2*mr-1;var kr=[Rr,_r].every(function(e){return Math.round(e)===e});h(Math,\"round\",function round(e){var t=_(e);var r=t===-1?-0:t+1;return e-t<.5?t:r},!Ar||!kr);m.preserveToString(Math.round,Nr);var Lr=Math.imul;if(Math.imul(4294967295,5)!==-5){Math.imul=Cr.imul;m.preserveToString(Math.imul,Lr)}if(Math.imul.length!==2){ne(Math,\"imul\",function imul(e,t){return ce.Call(Lr,Math,arguments)})}var Fr=function(){var e=S.setTimeout;if(typeof e!==\"function\"&&typeof e!==\"object\"){return}ce.IsPromise=function(e){if(!ce.TypeIsObject(e)){return false}if(typeof e._promise===\"undefined\"){return false}return true};var r=function(e){if(!ce.IsConstructor(e)){throw new TypeError(\"Bad promise constructor\")}var t=this;var r=function(e,r){if(t.resolve!==void 0||t.reject!==void 0){throw new TypeError(\"Bad Promise implementation!\")}t.resolve=e;t.reject=r};t.resolve=void 0;t.reject=void 0;t.promise=new e(r);if(!(ce.IsCallable(t.resolve)&&ce.IsCallable(t.reject))){throw new TypeError(\"Bad promise constructor\")}};var n;if(typeof window!==\"undefined\"&&ce.IsCallable(window.postMessage)){n=function(){var e=[];var t=\"zero-timeout-message\";var r=function(r){M(e,r);window.postMessage(t,\"*\")};var n=function(r){if(r.source===window&&r.data===t){r.stopPropagation();if(e.length===0){return}var n=N(e);n()}};window.addEventListener(\"message\",n,true);return r}}var o=function(){var e=S.Promise;var t=e&&e.resolve&&e.resolve();return t&&function(e){return t.then(e)}};var i=ce.IsCallable(S.setImmediate)?S.setImmediate:typeof process===\"object\"&&process.nextTick?process.nextTick:o()||(ce.IsCallable(n)?n():function(t){e(t,0)});var a=function(e){return e};var u=function(e){throw e};var f=0;var s=1;var c=2;var l=0;var p=1;var v=2;var y={};var h=function(e,t,r){i(function(){g(e,t,r)})};var g=function(e,t,r){var n,o;if(t===y){return e(r)}try{n=e(r);o=t.resolve}catch(i){n=i;o=t.reject}o(n)};var d=function(e,t){var r=e._promise;var n=r.reactionLength;if(n>0){h(r.fulfillReactionHandler0,r.reactionCapability0,t);r.fulfillReactionHandler0=void 0;r.rejectReactions0=void 0;r.reactionCapability0=void 0;if(n>1){for(var o=1,i=0;o<n;o++,i+=3){h(r[i+l],r[i+v],t);e[i+l]=void 0;e[i+p]=void 0;e[i+v]=void 0}}}r.result=t;r.state=s;r.reactionLength=0};var m=function(e,t){var r=e._promise;var n=r.reactionLength;if(n>0){h(r.rejectReactionHandler0,r.reactionCapability0,t);r.fulfillReactionHandler0=void 0;r.rejectReactions0=void 0;r.reactionCapability0=void 0;if(n>1){for(var o=1,i=0;o<n;o++,i+=3){h(r[i+p],r[i+v],t);e[i+l]=void 0;e[i+p]=void 0;e[i+v]=void 0}}}r.result=t;r.state=c;r.reactionLength=0};var O=function(e){var t=false;var r=function(r){var n;if(t){return}t=true;if(r===e){return m(e,new TypeError(\"Self resolution\"))}if(!ce.TypeIsObject(r)){return d(e,r)}try{n=r.then}catch(o){return m(e,o)}if(!ce.IsCallable(n)){return d(e,r)}i(function(){j(e,r,n)})};var n=function(r){if(t){return}t=true;return m(e,r)};return{resolve:r,reject:n}};var w=function(e,r,n,o){if(e===I){t(e,r,n,o,y)}else{t(e,r,n,o)}};var j=function(e,t,r){var n=O(e);var o=n.resolve;var i=n.reject;try{w(r,t,o,i)}catch(a){i(a)}};var T,I;var E=function(){var e=function Promise(t){if(!(this instanceof e)){throw new TypeError('Constructor Promise requires \"new\"')}if(this&&this._promise){throw new TypeError(\"Bad construction\")}if(!ce.IsCallable(t)){throw new TypeError(\"not a valid resolver\")}var r=Ae(this,e,T,{_promise:{result:void 0,state:f,reactionLength:0,fulfillReactionHandler0:void 0,rejectReactionHandler0:void 0,reactionCapability0:void 0}});var n=O(r);var o=n.reject;try{t(n.resolve,o)}catch(i){o(i)}return r};return e}();T=E.prototype;var P=function(e,t,r,n){var o=false;return function(i){if(o){return}o=true;t[e]=i;if(--n.count===0){var a=r.resolve;a(t)}}};var C=function(e,t,r){var n=e.iterator;var o=[];var i={count:1};var a,u;var f=0;while(true){try{a=ce.IteratorStep(n);if(a===false){e.done=true;break}u=a.value}catch(s){e.done=true;throw s}o[f]=void 0;var c=t.resolve(u);var l=P(f,o,r,i);i.count+=1;w(c.then,c,l,r.reject);f+=1}if(--i.count===0){var p=r.resolve;p(o)}return r.promise};var x=function(e,t,r){var n=e.iterator;var o,i,a;while(true){try{o=ce.IteratorStep(n);if(o===false){e.done=true;break}i=o.value}catch(u){e.done=true;throw u}a=t.resolve(i);w(a.then,a,r.resolve,r.reject)}return r.promise};b(E,{all:function all(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Promise is not object\")}var n=new r(t);var o,i;try{o=ce.GetIterator(e);i={iterator:o,done:false};return C(i,t,n)}catch(a){var u=a;if(i&&!i.done){try{ce.IteratorClose(o,true)}catch(f){u=f}}var s=n.reject;s(u);return n.promise}},race:function race(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Promise is not object\")}var n=new r(t);var o,i;try{o=ce.GetIterator(e);i={iterator:o,done:false};return x(i,t,n)}catch(a){var u=a;if(i&&!i.done){try{ce.IteratorClose(o,true)}catch(f){u=f}}var s=n.reject;s(u);return n.promise}},reject:function reject(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Bad promise constructor\")}var n=new r(t);var o=n.reject;o(e);return n.promise},resolve:function resolve(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Bad promise constructor\")}if(ce.IsPromise(e)){var n=e.constructor;if(n===t){return e}}var o=new r(t);var i=o.resolve;i(e);return o.promise}});b(T,{\"catch\":function(e){return this.then(null,e)},then:function then(e,t){var n=this;if(!ce.IsPromise(n)){throw new TypeError(\"not a promise\")}var o=ce.SpeciesConstructor(n,E);var i;var b=arguments.length>2&&arguments[2]===y;if(b&&o===E){i=y}else{i=new r(o)}var g=ce.IsCallable(e)?e:a;var d=ce.IsCallable(t)?t:u;var m=n._promise;var O;if(m.state===f){if(m.reactionLength===0){m.fulfillReactionHandler0=g;m.rejectReactionHandler0=d;m.reactionCapability0=i}else{var w=3*(m.reactionLength-1);m[w+l]=g;m[w+p]=d;m[w+v]=i}m.reactionLength+=1}else if(m.state===s){O=m.result;h(g,i,O)}else if(m.state===c){O=m.result;h(d,i,O)}else{throw new TypeError(\"unexpected Promise state\")}return i.promise}});y=new r(E);I=T.then;return E}();if(S.Promise){delete S.Promise.accept;delete S.Promise.defer;delete S.Promise.prototype.chain}if(typeof Fr===\"function\"){b(S,{Promise:Fr});var Dr=w(S.Promise,function(e){return e.resolve(42).then(function(){})instanceof e});var zr=!i(function(){return S.Promise.reject(42).then(null,5).then(null,W)});var qr=i(function(){return S.Promise.call(3,W)});var Wr=function(e){var t=e.resolve(5);t.constructor={};var r=e.resolve(t);try{r.then(null,W).then(null,W)}catch(n){return true}return t===r}(S.Promise);var Gr=s&&function(){var e=0;var t=Object.defineProperty({},\"then\",{get:function(){e+=1}});Promise.resolve(t);return e===1}();var Hr=function BadResolverPromise(e){var t=new Promise(e);e(3,function(){});this.then=t.then;this.constructor=BadResolverPromise};Hr.prototype=Promise.prototype;Hr.all=Promise.all;var Vr=a(function(){return!!Hr.all([1,2])});if(!Dr||!zr||!qr||Wr||!Gr||Vr){Promise=Fr;ne(S,\"Promise\",Fr)}if(Promise.all.length!==1){var Br=Promise.all;ne(Promise,\"all\",function all(e){return ce.Call(Br,this,arguments)})}if(Promise.race.length!==1){var Ur=Promise.race;ne(Promise,\"race\",function race(e){return ce.Call(Ur,this,arguments)})}if(Promise.resolve.length!==1){var $r=Promise.resolve;ne(Promise,\"resolve\",function resolve(e){return ce.Call($r,this,arguments)})}if(Promise.reject.length!==1){var Jr=Promise.reject;ne(Promise,\"reject\",function reject(e){return ce.Call(Jr,this,arguments)})}Mt(Promise,\"all\");Mt(Promise,\"race\");Mt(Promise,\"resolve\");Mt(Promise,\"reject\");Ce(Promise)}var Xr=function(e){var t=n(p(e,function(e,t){e[t]=true;return e},{}));return e.join(\":\")===t.join(\":\")};var Kr=Xr([\"z\",\"a\",\"bb\"]);var Zr=Xr([\"z\",1,\"a\",\"3\",2]);if(s){var Yr=function fastkey(e,t){if(!t&&!Kr){return null}if(se(e)){return\"^\"+ce.ToString(e)}else if(typeof e===\"string\"){return\"$\"+e}else if(typeof e===\"number\"){if(!Zr){return\"n\"+e}return e}else if(typeof e===\"boolean\"){return\"b\"+e}return null};var Qr=function emptyObject(){return Object.create?Object.create(null):{}};var en=function addIterableToMap(e,n,o){if(r(o)||re.string(o)){l(o,function(e){if(!ce.TypeIsObject(e)){throw new TypeError(\"Iterator value \"+e+\" is not an entry object\")}n.set(e[0],e[1])})}else if(o instanceof e){t(e.prototype.forEach,o,function(e,t){n.set(t,e)})}else{var i,a;if(!se(o)){a=n.set;if(!ce.IsCallable(a)){throw new TypeError(\"bad map\")}i=ce.GetIterator(o)}if(typeof i!==\"undefined\"){while(true){var u=ce.IteratorStep(i);if(u===false){break}var f=u.value;try{if(!ce.TypeIsObject(f)){throw new TypeError(\"Iterator value \"+f+\" is not an entry object\")}t(a,n,f[0],f[1])}catch(s){ce.IteratorClose(i,true);throw s}}}}};var tn=function addIterableToSet(e,n,o){if(r(o)||re.string(o)){l(o,function(e){n.add(e)})}else if(o instanceof e){t(e.prototype.forEach,o,function(e){n.add(e)})}else{var i,a;if(!se(o)){a=n.add;if(!ce.IsCallable(a)){throw new TypeError(\"bad set\")}i=ce.GetIterator(o)}if(typeof i!==\"undefined\"){while(true){var u=ce.IteratorStep(i);if(u===false){break}var f=u.value;try{t(a,n,f)}catch(s){ce.IteratorClose(i,true);throw s}}}}};var rn={Map:function(){var e={};var r=function MapEntry(e,t){this.key=e;this.value=t;this.next=null;this.prev=null};r.prototype.isRemoved=function isRemoved(){return this.key===e};var n=function isMap(e){return!!e._es6map};var o=function requireMapSlot(e,t){if(!ce.TypeIsObject(e)||!n(e)){throw new TypeError(\"Method Map.prototype.\"+t+\" called on incompatible receiver \"+ce.ToString(e))}};var i=function MapIterator(e,t){o(e,\"[[MapIterator]]\");this.head=e._head;this.i=this.head;this.kind=t};i.prototype={isMapIterator:true,next:function next(){if(!this.isMapIterator){throw new TypeError(\"Not a MapIterator\")}var e=this.i;var t=this.kind;var r=this.head;if(typeof this.i===\"undefined\"){return Ke()}while(e.isRemoved()&&e!==r){e=e.prev}var n;while(e.next!==r){e=e.next;if(!e.isRemoved()){if(t===\"key\"){n=e.key}else if(t===\"value\"){n=e.value}else{n=[e.key,e.value]}this.i=e;return Ke(n)}}this.i=void 0;return Ke()}};Me(i.prototype);var a;var u=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}if(this&&this._es6map){throw new TypeError(\"Bad construction\")}var e=Ae(this,Map,a,{_es6map:true,_head:null,_map:G?new G:null,_size:0,_storage:Qr()});var t=new r(null,null);t.next=t.prev=t;e._head=t;if(arguments.length>0){en(Map,e,arguments[0])}return e};a=u.prototype;m.getter(a,\"size\",function(){if(typeof this._size===\"undefined\"){throw new TypeError(\"size method called on incompatible Map\")}return this._size});b(a,{get:function get(e){o(this,\"get\");var t;var r=Yr(e,true);if(r!==null){t=this._storage[r];if(t){return t.value}else{return}}if(this._map){t=V.call(this._map,e);if(t){return t.value}else{return}}var n=this._head;var i=n;while((i=i.next)!==n){if(ce.SameValueZero(i.key,e)){return i.value}}},has:function has(e){o(this,\"has\");var t=Yr(e,true);if(t!==null){return typeof this._storage[t]!==\"undefined\"}if(this._map){return B.call(this._map,e)}var r=this._head;var n=r;while((n=n.next)!==r){if(ce.SameValueZero(n.key,e)){return true}}return false},set:function set(e,t){o(this,\"set\");var n=this._head;var i=n;var a;var u=Yr(e,true);if(u!==null){if(typeof this._storage[u]!==\"undefined\"){this._storage[u].value=t;return this}else{a=this._storage[u]=new r(e,t);i=n.prev}}else if(this._map){if(B.call(this._map,e)){V.call(this._map,e).value=t}else{a=new r(e,t);U.call(this._map,e,a);i=n.prev}}while((i=i.next)!==n){if(ce.SameValueZero(i.key,e)){i.value=t;return this}}a=a||new r(e,t);if(ce.SameValue(-0,e)){a.key=+0}a.next=this._head;a.prev=this._head.prev;a.prev.next=a;a.next.prev=a;this._size+=1;return this},\"delete\":function(t){o(this,\"delete\");var r=this._head;var n=r;var i=Yr(t,true);if(i!==null){if(typeof this._storage[i]===\"undefined\"){return false}n=this._storage[i].prev;delete this._storage[i]}else if(this._map){if(!B.call(this._map,t)){return false}n=V.call(this._map,t).prev;H.call(this._map,t)}while((n=n.next)!==r){if(ce.SameValueZero(n.key,t)){n.key=e;n.value=e;n.prev.next=n.next;n.next.prev=n.prev;this._size-=1;return true}}return false},clear:function clear(){o(this,\"clear\");this._map=G?new G:null;this._size=0;this._storage=Qr();var t=this._head;var r=t;var n=r.next;while((r=n)!==t){r.key=e;r.value=e;n=r.next;r.next=r.prev=t}t.next=t.prev=t},keys:function keys(){o(this,\"keys\");return new i(this,\"key\")},values:function values(){o(this,\"values\");return new i(this,\"value\")},entries:function entries(){o(this,\"entries\");return new i(this,\"key+value\")},forEach:function forEach(e){o(this,\"forEach\");var r=arguments.length>1?arguments[1]:null;var n=this.entries();for(var i=n.next();!i.done;i=n.next()){if(r){t(e,r,i.value[1],i.value[0],this)}else{e(i.value[1],i.value[0],this)}}}});Me(a,a.entries);return u}(),Set:function(){var e=function isSet(e){return e._es6set&&typeof e._storage!==\"undefined\"};var r=function requireSetSlot(t,r){if(!ce.TypeIsObject(t)||!e(t)){throw new TypeError(\"Set.prototype.\"+r+\" called on incompatible receiver \"+ce.ToString(t))}};var o;var i=function Set(){if(!(this instanceof Set)){throw new TypeError('Constructor Set requires \"new\"')}if(this&&this._es6set){throw new TypeError(\"Bad construction\")}var e=Ae(this,Set,o,{_es6set:true,\"[[SetData]]\":null,_storage:Qr()});if(!e._es6set){throw new TypeError(\"bad set\")}if(arguments.length>0){tn(Set,e,arguments[0])}return e};o=i.prototype;var a=function(e){var t=e;if(t===\"^null\"){return null}else if(t===\"^undefined\"){return void 0}else{var r=t.charAt(0);if(r===\"$\"){return C(t,1)}else if(r===\"n\"){return+C(t,1)}else if(r===\"b\"){return t===\"btrue\"}}return+t};var u=function ensureMap(e){if(!e[\"[[SetData]]\"]){var t=new rn.Map;e[\"[[SetData]]\"]=t;l(n(e._storage),function(e){var r=a(e);t.set(r,r)});e[\"[[SetData]]\"]=t}e._storage=null};m.getter(i.prototype,\"size\",function(){r(this,\"size\");if(this._storage){return n(this._storage).length}u(this);return this[\"[[SetData]]\"].size});b(i.prototype,{has:function has(e){r(this,\"has\");var t;if(this._storage&&(t=Yr(e))!==null){return!!this._storage[t]}u(this);return this[\"[[SetData]]\"].has(e)},add:function add(e){r(this,\"add\");var t;if(this._storage&&(t=Yr(e))!==null){this._storage[t]=true;return this}u(this);this[\"[[SetData]]\"].set(e,e);return this},\"delete\":function(e){r(this,\"delete\");var t;if(this._storage&&(t=Yr(e))!==null){var n=z(this._storage,t);return delete this._storage[t]&&n}u(this);return this[\"[[SetData]]\"][\"delete\"](e)},clear:function clear(){r(this,\"clear\");if(this._storage){this._storage=Qr()}if(this[\"[[SetData]]\"]){this[\"[[SetData]]\"].clear()}},values:function values(){r(this,\"values\");u(this);return new f(this[\"[[SetData]]\"].values())},entries:function entries(){r(this,\"entries\");u(this);return new f(this[\"[[SetData]]\"].entries())},forEach:function forEach(e){r(this,\"forEach\");var n=arguments.length>1?arguments[1]:null;var o=this;u(o);this[\"[[SetData]]\"].forEach(function(r,i){if(n){t(e,n,i,i,o)}else{e(i,i,o)}})}});h(i.prototype,\"keys\",i.prototype.values,true);Me(i.prototype,i.prototype.values);var f=function SetIterator(e){this.it=e};f.prototype={isSetIterator:true,next:function next(){if(!this.isSetIterator){throw new TypeError(\"Not a SetIterator\")}return this.it.next()}};Me(f.prototype);return i}()};var nn=S.Set&&!Set.prototype[\"delete\"]&&Set.prototype.remove&&Set.prototype.items&&Set.prototype.map&&Array.isArray((new Set).keys);if(nn){S.Set=rn.Set}if(S.Map||S.Set){var on=a(function(){return new Map([[1,2]]).get(1)===2});if(!on){S.Map=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}var e=new G;if(arguments.length>0){en(Map,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,S.Map.prototype);return e};S.Map.prototype=O(G.prototype);h(S.Map.prototype,\"constructor\",S.Map,true);m.preserveToString(S.Map,G)}var an=new Map;var un=function(){var e=new Map([[1,0],[2,0],[3,0],[4,0]]);e.set(-0,e);return e.get(0)===e&&e.get(-0)===e&&e.has(0)&&e.has(-0)}();var fn=an.set(1,2)===an;if(!un||!fn){ne(Map.prototype,\"set\",function set(e,r){t(U,this,e===0?0:e,r);return this})}if(!un){b(Map.prototype,{get:function get(e){return t(V,this,e===0?0:e)},has:function has(e){return t(B,this,e===0?0:e)}},true);m.preserveToString(Map.prototype.get,V);m.preserveToString(Map.prototype.has,B)}var sn=new Set;var cn=Set.prototype[\"delete\"]&&Set.prototype.add&&Set.prototype.has&&function(e){e[\"delete\"](0);e.add(-0);return!e.has(0)}(sn);var ln=sn.add(1)===sn;if(!cn||!ln){var pn=Set.prototype.add;Set.prototype.add=function add(e){t(pn,this,e===0?0:e);return this};m.preserveToString(Set.prototype.add,pn)}if(!cn){var vn=Set.prototype.has;Set.prototype.has=function has(e){return t(vn,this,e===0?0:e)};m.preserveToString(Set.prototype.has,vn);var yn=Set.prototype[\"delete\"];Set.prototype[\"delete\"]=function SetDelete(e){return t(yn,this,e===0?0:e)};m.preserveToString(Set.prototype[\"delete\"],yn)}var hn=w(S.Map,function(e){var t=new e([]);t.set(42,42);return t instanceof e});var bn=Object.setPrototypeOf&&!hn;var gn=function(){try{return!(S.Map()instanceof S.Map)}catch(e){return e instanceof TypeError}}();if(S.Map.length!==0||bn||!gn){S.Map=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}var e=new G;if(arguments.length>0){en(Map,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,Map.prototype);return e};S.Map.prototype=G.prototype;h(S.Map.prototype,\"constructor\",S.Map,true);m.preserveToString(S.Map,G)}var dn=w(S.Set,function(e){var t=new e([]);t.add(42,42);return t instanceof e});var mn=Object.setPrototypeOf&&!dn;var On=function(){try{return!(S.Set()instanceof S.Set)}catch(e){return e instanceof TypeError}}();if(S.Set.length!==0||mn||!On){var wn=S.Set;S.Set=function Set(){if(!(this instanceof Set)){throw new TypeError('Constructor Set requires \"new\"')}var e=new wn;if(arguments.length>0){tn(Set,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,Set.prototype);return e};S.Set.prototype=wn.prototype;h(S.Set.prototype,\"constructor\",S.Set,true);m.preserveToString(S.Set,wn)}var jn=new S.Map;var Sn=!a(function(){return jn.keys().next().done});if(typeof S.Map.prototype.clear!==\"function\"||(new S.Set).size!==0||jn.size!==0||typeof S.Map.prototype.keys!==\"function\"||typeof S.Set.prototype.keys!==\"function\"||typeof S.Map.prototype.forEach!==\"function\"||typeof S.Set.prototype.forEach!==\"function\"||u(S.Map)||u(S.Set)||typeof jn.keys().next!==\"function\"||Sn||!hn){b(S,{Map:rn.Map,Set:rn.Set},true)}if(S.Set.prototype.keys!==S.Set.prototype.values){h(S.Set.prototype,\"keys\",S.Set.prototype.values,true)}Me(Object.getPrototypeOf((new S.Map).keys()));Me(Object.getPrototypeOf((new S.Set).keys()));if(c&&S.Set.prototype.has.name!==\"has\"){var Tn=S.Set.prototype.has;ne(S.Set.prototype,\"has\",function has(e){return t(Tn,this,e)})}}b(S,rn);Ce(S.Map);Ce(S.Set)}var In=function throwUnlessTargetIsObject(e){if(!ce.TypeIsObject(e)){throw new TypeError(\"target must be an object\")}};var En={apply:function apply(){return ce.Call(ce.Call,null,arguments)},construct:function construct(e,t){if(!ce.IsConstructor(e)){throw new TypeError(\"First argument must be a constructor.\")}var r=arguments.length>2?arguments[2]:e;if(!ce.IsConstructor(r)){throw new TypeError(\"new.target must be a constructor.\")}return ce.Construct(e,t,r,\"internal\")},deleteProperty:function deleteProperty(e,t){In(e);if(s){var r=Object.getOwnPropertyDescriptor(e,t);if(r&&!r.configurable){return false}}return delete e[t]},has:function has(e,t){In(e);return t in e}};if(Object.getOwnPropertyNames){Object.assign(En,{ownKeys:function ownKeys(e){In(e);var t=Object.getOwnPropertyNames(e);if(ce.IsCallable(Object.getOwnPropertySymbols)){x(t,Object.getOwnPropertySymbols(e))}return t}})}var Pn=function ConvertExceptionToBoolean(e){return!i(e)};if(Object.preventExtensions){Object.assign(En,{isExtensible:function isExtensible(e){In(e);return Object.isExtensible(e)},preventExtensions:function preventExtensions(e){In(e);return Pn(function(){return Object.preventExtensions(e)})}})}if(s){var Cn=function get(e,t,r){var n=Object.getOwnPropertyDescriptor(e,t);if(!n){var o=Object.getPrototypeOf(e);if(o===null){return void 0}return Cn(o,t,r)}if(\"value\"in n){return n.value}if(n.get){return ce.Call(n.get,r)}return void 0};var Mn=function set(e,r,n,o){var i=Object.getOwnPropertyDescriptor(e,r);if(!i){var a=Object.getPrototypeOf(e);if(a!==null){return Mn(a,r,n,o)}i={value:void 0,writable:true,enumerable:true,configurable:true}}if(\"value\"in i){if(!i.writable){return false}if(!ce.TypeIsObject(o)){return false}var u=Object.getOwnPropertyDescriptor(o,r);if(u){return ae.defineProperty(o,r,{value:n})}else{return ae.defineProperty(o,r,{value:n,writable:true,enumerable:true,configurable:true})}}if(i.set){t(i.set,o,n);return true}return false};Object.assign(En,{defineProperty:function defineProperty(e,t,r){In(e);return Pn(function(){return Object.defineProperty(e,t,r)})},getOwnPropertyDescriptor:function getOwnPropertyDescriptor(e,t){In(e);return Object.getOwnPropertyDescriptor(e,t)},get:function get(e,t){In(e);var r=arguments.length>2?arguments[2]:e;return Cn(e,t,r)},set:function set(e,t,r){In(e);var n=arguments.length>3?arguments[3]:e;return Mn(e,t,r,n)}})}if(Object.getPrototypeOf){var xn=Object.getPrototypeOf;En.getPrototypeOf=function getPrototypeOf(e){In(e);return xn(e)}}if(Object.setPrototypeOf&&En.getPrototypeOf){var Nn=function(e,t){var r=t;while(r){if(e===r){return true}r=En.getPrototypeOf(r)}return false};Object.assign(En,{setPrototypeOf:function setPrototypeOf(e,t){In(e);if(t!==null&&!ce.TypeIsObject(t)){throw new TypeError(\"proto must be an object or null\")}if(t===ae.getPrototypeOf(e)){return true}if(ae.isExtensible&&!ae.isExtensible(e)){return false}if(Nn(e,t)){return false}Object.setPrototypeOf(e,t);return true}})}var An=function(e,t){if(!ce.IsCallable(S.Reflect[e])){h(S.Reflect,e,t)}else{var r=a(function(){S.Reflect[e](1);S.Reflect[e](NaN);S.Reflect[e](true);return true});if(r){ne(S.Reflect,e,t)}}};Object.keys(En).forEach(function(e){An(e,En[e])});var Rn=S.Reflect.getPrototypeOf;if(c&&Rn&&Rn.name!==\"getPrototypeOf\"){ne(S.Reflect,\"getPrototypeOf\",function getPrototypeOf(e){return t(Rn,S.Reflect,e)})}if(S.Reflect.setPrototypeOf){if(a(function(){S.Reflect.setPrototypeOf(1,{});return true})){ne(S.Reflect,\"setPrototypeOf\",En.setPrototypeOf)}}if(S.Reflect.defineProperty){if(!a(function(){var e=!S.Reflect.defineProperty(1,\"test\",{value:1});var t=typeof Object.preventExtensions!==\"function\"||!S.Reflect.defineProperty(Object.preventExtensions({}),\"test\",{});return e&&t})){ne(S.Reflect,\"defineProperty\",En.defineProperty)}}if(S.Reflect.construct){if(!a(function(){var e=function F(){};return S.Reflect.construct(function(){},[],e)instanceof e})){ne(S.Reflect,\"construct\",En.construct)}}if(String(new Date(NaN))!==\"Invalid Date\"){var _n=Date.prototype.toString;var kn=function toString(){var e=+this;if(e!==e){return\"Invalid Date\"}return ce.Call(_n,this)};ne(Date.prototype,\"toString\",kn)}var Ln={anchor:function anchor(e){return ce.CreateHTML(this,\"a\",\"name\",e)},big:function big(){return ce.CreateHTML(this,\"big\",\"\",\"\")},blink:function blink(){return ce.CreateHTML(this,\"blink\",\"\",\"\")},bold:function bold(){return ce.CreateHTML(this,\"b\",\"\",\"\")},fixed:function fixed(){return ce.CreateHTML(this,\"tt\",\"\",\"\")},fontcolor:function fontcolor(e){return ce.CreateHTML(this,\"font\",\"color\",e)},fontsize:function fontsize(e){return ce.CreateHTML(this,\"font\",\"size\",e)},italics:function italics(){return ce.CreateHTML(this,\"i\",\"\",\"\")},link:function link(e){return ce.CreateHTML(this,\"a\",\"href\",e)},small:function small(){return ce.CreateHTML(this,\"small\",\"\",\"\")},strike:function strike(){return ce.CreateHTML(this,\"strike\",\"\",\"\")},sub:function sub(){return ce.CreateHTML(this,\"sub\",\"\",\"\")},sup:function sub(){return ce.CreateHTML(this,\"sup\",\"\",\"\")}};l(Object.keys(Ln),function(e){var r=String.prototype[e];var n=false;if(ce.IsCallable(r)){var o=t(r,\"\",' \" ');var i=P([],o.match(/\"/g)).length;n=o!==o.toLowerCase()||i>2}else{n=true}if(n){ne(String.prototype,e,Ln[e])}});var Fn=function(){if(!oe){return false}var e=typeof JSON===\"object\"&&typeof JSON.stringify===\"function\"?JSON.stringify:null;if(!e){return false}if(typeof e($())!==\"undefined\"){return true}if(e([$()])!==\"[null]\"){return true}var t={a:$()};t[$()]=true;if(e(t)!==\"{}\"){return true}return false}();var Dn=a(function(){if(!oe){return true}return JSON.stringify(Object($()))===\"{}\"&&JSON.stringify([Object($())])===\"[{}]\"});if(Fn||!Dn){var zn=JSON.stringify;ne(JSON,\"stringify\",function stringify(e){if(typeof e===\"symbol\"){return}var n;if(arguments.length>1){n=arguments[1]}var o=[e];if(!r(n)){var i=ce.IsCallable(n)?n:null;var a=function(e,r){var n=i?t(i,this,e,r):r;if(typeof n!==\"symbol\"){if(re.symbol(n)){return Nt({})(n)}else{return n}}};o.push(a)}else{o.push(n)}if(arguments.length>2){o.push(arguments[2])}return zn.apply(this,o)})}return S});\n//# sourceMappingURL=es6-shim.map\n/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */\n!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return t(e)}:t(e)}(\"undefined\"!=typeof window?window:this,function(C,e){\"use strict\";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return\"function\"==typeof e&&\"number\"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement(\"script\");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?n[o.call(e)]||\"object\":typeof e}var f=\"3.4.1\",k=function(e,t){return new k.fn.init(e,t)},p=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;function d(e){var t=!!e&&\"length\"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&0<t&&t-1 in e)}k.fn=k.prototype={jquery:f,constructor:k,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=k.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return k.each(this,e)},map:function(n){return this.pushStack(k.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},k.extend=k.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for(\"boolean\"==typeof a&&(l=a,a=arguments[s]||{},s++),\"object\"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],\"__proto__\"!==t&&a!==r&&(l&&r&&(k.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||k.isPlainObject(n)?n:{},i=!1,a[t]=k.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},k.extend({expando:\"jQuery\"+(f+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||\"[object Object]\"!==o.call(e))&&(!(t=r(e))||\"function\"==typeof(n=v.call(t,\"constructor\")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t){b(e,{nonce:t&&t.nonce})},each:function(e,t){var n,r=0;if(d(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?\"\":(e+\"\").replace(p,\"\")},makeArray:function(e,t){var n=t||[];return null!=e&&(d(Object(e))?k.merge(n,\"string\"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(d(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g.apply([],a)},guid:1,support:y}),\"function\"==typeof Symbol&&(k.fn[Symbol.iterator]=t[Symbol.iterator]),k.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){n[\"[object \"+t+\"]\"]=t.toLowerCase()});var h=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,k=\"sizzle\"+1*new Date,m=n.document,S=0,r=0,p=ue(),x=ue(),N=ue(),A=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",M=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",I=\"(?:\\\\\\\\.|[\\\\w-]|[^\\0-\\\\xa0])+\",W=\"\\\\[\"+M+\"*(\"+I+\")(?:\"+M+\"*([*^$|!~]?=)\"+M+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+I+\"))|)\"+M+\"*\\\\]\",$=\":(\"+I+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+W+\")*)|.*)\\\\)|)\",F=new RegExp(M+\"+\",\"g\"),B=new RegExp(\"^\"+M+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+M+\"+$\",\"g\"),_=new RegExp(\"^\"+M+\"*,\"+M+\"*\"),z=new RegExp(\"^\"+M+\"*([>+~]|\"+M+\")\"+M+\"*\"),U=new RegExp(M+\"|>\"),X=new RegExp($),V=new RegExp(\"^\"+I+\"$\"),G={ID:new RegExp(\"^#(\"+I+\")\"),CLASS:new RegExp(\"^\\\\.(\"+I+\")\"),TAG:new RegExp(\"^(\"+I+\"|[*])\"),ATTR:new RegExp(\"^\"+W),PSEUDO:new RegExp(\"^\"+$),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+M+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+M+\"*(?:([+-]|)\"+M+\"*(\\\\d+)|))\"+M+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+R+\")$\",\"i\"),needsContext:new RegExp(\"^\"+M+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+M+\"*((?:-\\\\d)?\\\\d*)\"+M+\"*\\\\)|)(?=[^-]|$)\",\"i\")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\\d$/i,K=/^[^{]+\\{\\s*\\[native \\w/,Z=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,ee=/[+~]/,te=new RegExp(\"\\\\\\\\([\\\\da-f]{1,6}\"+M+\"?|(\"+M+\")|.)\",\"ig\"),ne=function(e,t,n){var r=\"0x\"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,ie=function(e,t){return t?\"\\0\"===e?\"\\ufffd\":e.slice(0,-1)+\"\\\\\"+e.charCodeAt(e.length-1).toString(16)+\" \":\"\\\\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&\"fieldset\"===e.nodeName.toLowerCase()},{dir:\"parentNode\",next:\"legend\"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],\"string\"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+\" \"]&&(!v||!v.test(t))&&(1!==p||\"object\"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute(\"id\"))?s=s.replace(re,ie):e.setAttribute(\"id\",s=k),o=(l=h(t)).length;while(o--)l[o]=\"#\"+s+\" \"+xe(l[o]);c=l.join(\",\"),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute(\"id\")}}}return g(t.replace(B,\"$1\"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+\" \")>b.cacheLength&&delete e[r.shift()],e[t+\" \"]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement(\"fieldset\");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split(\"|\"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return\"input\"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return(\"input\"===t||\"button\"===t)&&e.type===n}}function ge(t){return function(e){return\"form\"in e?e.parentNode&&!1===e.disabled?\"label\"in e?\"label\"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:\"label\"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&\"undefined\"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||\"HTML\")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener(\"unload\",oe,!1):n.attachEvent&&n.attachEvent(\"onunload\",oe)),d.attributes=ce(function(e){return e.className=\"i\",!e.getAttribute(\"className\")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment(\"\")),!e.getElementsByTagName(\"*\").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute(\"id\")===t}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t=\"undefined\"!=typeof e.getAttributeNode&&e.getAttributeNode(\"id\");return t&&t.value===n}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return\"undefined\"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if(\"*\"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if(\"undefined\"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML=\"<a id='\"+k+\"'></a><select id='\"+k+\"-\\r\\\\' msallowcapture=''><option selected=''></option></select>\",e.querySelectorAll(\"[msallowcapture^='']\").length&&v.push(\"[*^$]=\"+M+\"*(?:''|\\\"\\\")\"),e.querySelectorAll(\"[selected]\").length||v.push(\"\\\\[\"+M+\"*(?:value|\"+R+\")\"),e.querySelectorAll(\"[id~=\"+k+\"-]\").length||v.push(\"~=\"),e.querySelectorAll(\":checked\").length||v.push(\":checked\"),e.querySelectorAll(\"a#\"+k+\"+*\").length||v.push(\".#.+[+~]\")}),ce(function(e){e.innerHTML=\"<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>\";var t=C.createElement(\"input\");t.setAttribute(\"type\",\"hidden\"),e.appendChild(t).setAttribute(\"name\",\"D\"),e.querySelectorAll(\"[name=d]\").length&&v.push(\"name\"+M+\"*[*^$|!~]?=\"),2!==e.querySelectorAll(\":enabled\").length&&v.push(\":enabled\",\":disabled\"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(\":disabled\").length&&v.push(\":enabled\",\":disabled\"),e.querySelectorAll(\"*,:x\"),v.push(\",.*:\")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,\"*\"),c.call(e,\"[s!='']:x\"),s.push(\"!=\",$)}),v=v.length&&new RegExp(v.join(\"|\")),s=s.length&&new RegExp(s.join(\"|\")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+\" \"]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!==C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!==C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+\"\").replace(re,ie)},se.error=function(e){throw new Error(\"Syntax error, unrecognized expression: \"+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n=\"\",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if(\"string\"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||\"\").replace(te,ne),\"~=\"===e[2]&&(e[3]=\" \"+e[3]+\" \"),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),\"nth\"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*(\"even\"===e[3]||\"odd\"===e[3])),e[5]=+(e[7]+e[8]||\"odd\"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||\"\":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(\")\",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return\"*\"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+\" \"];return t||(t=new RegExp(\"(^|\"+M+\")\"+e+\"(\"+M+\"|$)\"))&&p(e,function(e){return t.test(\"string\"==typeof e.className&&e.className||\"undefined\"!=typeof e.getAttribute&&e.getAttribute(\"class\")||\"\")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?\"!=\"===r:!r||(t+=\"\",\"=\"===r?t===i:\"!=\"===r?t!==i:\"^=\"===r?i&&0===t.indexOf(i):\"*=\"===r?i&&-1<t.indexOf(i):\"$=\"===r?i&&t.slice(-i.length)===i:\"~=\"===r?-1<(\" \"+t.replace(F,\" \")+\" \").indexOf(i):\"|=\"===r&&(t===i||t.slice(0,i.length+1)===i+\"-\"))}},CHILD:function(h,e,t,g,v){var y=\"nth\"!==h.slice(0,3),m=\"last\"!==h.slice(-4),x=\"of-type\"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?\"nextSibling\":\"previousSibling\",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l=\"only\"===h&&!u&&\"nextSibling\"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[S,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[S,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error(\"unsupported pseudo: \"+e);return a[k]?a(o):1<a.length?(t=[e,e,\"\",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace(B,\"$1\"));return s[k]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||\"\")||se.error(\"unsupported lang: \"+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute(\"xml:lang\")||e.getAttribute(\"lang\"))return(t=t.toLowerCase())===n||0===t.indexOf(n+\"-\")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&!!e.checked||\"option\"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&\"button\"===e.type||\"button\"===t},text:function(e){var t;return\"input\"===e.nodeName.toLowerCase()&&\"text\"===e.type&&(null==(t=e.getAttribute(\"type\"))||\"text\"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r=\"\";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&\"parentNode\"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[S,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[k]||(e[k]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===S&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[k]&&(v=Ce(v)),y&&!y[k]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||\"*\",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[\" \"],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[k]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:\" \"===e[s-2].type?\"*\":\"\"})).replace(B,\"$1\"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+\" \"];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace(B,\" \")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=N[e+\" \"];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[k]?i.push(a):o.push(a);(a=N(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l=\"0\",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG(\"*\",i),h=S+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t===C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument===C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(S=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(S=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l=\"function\"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&\"ID\"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=k.split(\"\").sort(D).join(\"\")===k,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement(\"fieldset\"))}),ce(function(e){return e.innerHTML=\"<a href='#'></a>\",\"#\"===e.firstChild.getAttribute(\"href\")})||fe(\"type|href|height|width\",function(e,t,n){if(!n)return e.getAttribute(t,\"type\"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML=\"<input/>\",e.firstChild.setAttribute(\"value\",\"\"),\"\"===e.firstChild.getAttribute(\"value\")})||fe(\"value\",function(e,t,n){if(!n&&\"input\"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute(\"disabled\")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);k.find=h,k.expr=h.selectors,k.expr[\":\"]=k.expr.pseudos,k.uniqueSort=k.unique=h.uniqueSort,k.text=h.getText,k.isXMLDoc=h.isXML,k.contains=h.contains,k.escapeSelector=h.escape;var T=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&k(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},N=k.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var D=/^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):\"string\"!=typeof n?k.grep(e,function(e){return-1<i.call(n,e)!==r}):k.filter(n,e,r)}k.filter=function(e,t,n){var r=t[0];return n&&(e=\":not(\"+e+\")\"),1===t.length&&1===r.nodeType?k.find.matchesSelector(r,e)?[r]:[]:k.find.matches(e,k.grep(t,function(e){return 1===e.nodeType}))},k.fn.extend({find:function(e){var t,n,r=this.length,i=this;if(\"string\"!=typeof e)return this.pushStack(k(e).filter(function(){for(t=0;t<r;t++)if(k.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)k.find(e,i[t],n);return 1<r?k.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,\"string\"==typeof e&&N.test(e)?k(e):e||[],!1).length}});var q,L=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,\"string\"==typeof e){if(!(r=\"<\"===e[0]&&\">\"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(k.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a=\"string\"!=typeof e&&k(e);if(!N.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&k.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?k.uniqueSort(o):o)},index:function(e){return e?\"string\"==typeof e?i.call(k(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(k.uniqueSort(k.merge(this.get(),k(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),k.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return T(e,\"parentNode\")},parentsUntil:function(e,t,n){return T(e,\"parentNode\",n)},next:function(e){return P(e,\"nextSibling\")},prev:function(e){return P(e,\"previousSibling\")},nextAll:function(e){return T(e,\"nextSibling\")},prevAll:function(e){return T(e,\"previousSibling\")},nextUntil:function(e,t,n){return T(e,\"nextSibling\",n)},prevUntil:function(e,t,n){return T(e,\"previousSibling\",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return\"undefined\"!=typeof e.contentDocument?e.contentDocument:(A(e,\"template\")&&(e=e.content||e),k.merge([],e.childNodes))}},function(r,i){k.fn[r]=function(e,t){var n=k.map(this,i,e);return\"Until\"!==r.slice(-5)&&(t=e),t&&\"string\"==typeof t&&(n=k.filter(t,n)),1<this.length&&(O[r]||k.uniqueSort(n),H.test(r)&&n.reverse()),this.pushStack(n)}});var R=/[^\\x20\\t\\r\\n\\f]+/g;function M(e){return e}function I(e){throw e}function W(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}k.Callbacks=function(r){var e,n;r=\"string\"==typeof r?(e=r,n={},k.each(e.match(R)||[],function(e,t){n[t]=!0}),n):k.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:\"\")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){k.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&\"string\"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return k.each(arguments,function(e,t){var n;while(-1<(n=k.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<k.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t=\"\",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=\"\"),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},k.extend({Deferred:function(e){var o=[[\"notify\",\"progress\",k.Callbacks(\"memory\"),k.Callbacks(\"memory\"),2],[\"resolve\",\"done\",k.Callbacks(\"once memory\"),k.Callbacks(\"once memory\"),0,\"resolved\"],[\"reject\",\"fail\",k.Callbacks(\"once memory\"),k.Callbacks(\"once memory\"),1,\"rejected\"]],i=\"pending\",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},\"catch\":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return k.Deferred(function(r){k.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+\"With\"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError(\"Thenable self-resolution\");t=e&&(\"object\"==typeof e||\"function\"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,M,s),l(u,o,I,s)):(u++,t.call(e,l(u,o,M,s),l(u,o,I,s),l(u,o,M,o.notifyWith))):(a!==M&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){k.Deferred.exceptionHook&&k.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==I&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(k.Deferred.getStackHook&&(t.stackTrace=k.Deferred.getStackHook()),C.setTimeout(t))}}return k.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:M,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:M)),o[2][3].add(l(0,e,m(n)?n:I))}).promise()},promise:function(e){return null!=e?k.extend(e,a):a}},s={};return k.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+\"With\"](this===s?void 0:this,arguments),this},s[t[0]+\"With\"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=k.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(W(e,o.done(a(t)).resolve,o.reject,!n),\"pending\"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)W(i[t],a(t),o.reject);return o.promise()}});var $=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;k.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&$.test(e.name)&&C.console.warn(\"jQuery.Deferred exception: \"+e.message,e.stack,t)},k.readyException=function(e){C.setTimeout(function(){throw e})};var F=k.Deferred();function B(){E.removeEventListener(\"DOMContentLoaded\",B),C.removeEventListener(\"load\",B),k.ready()}k.fn.ready=function(e){return F.then(e)[\"catch\"](function(e){k.readyException(e)}),this},k.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--k.readyWait:k.isReady)||(k.isReady=!0)!==e&&0<--k.readyWait||F.resolveWith(E,[k])}}),k.ready.then=F.then,\"complete\"===E.readyState||\"loading\"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(k.ready):(E.addEventListener(\"DOMContentLoaded\",B),C.addEventListener(\"load\",B));var _=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if(\"object\"===w(n))for(s in i=!0,n)_(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(k(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},z=/^-ms-/,U=/-([a-z])/g;function X(e,t){return t.toUpperCase()}function V(e){return e.replace(z,\"ms-\").replace(U,X)}var G=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function Y(){this.expando=k.expando+Y.uid++}Y.uid=1,Y.prototype={cache:function(e){var t=e[this.expando];return t||(t={},G(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if(\"string\"==typeof t)i[V(t)]=n;else for(r in t)i[V(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][V(t)]},access:function(e,t,n){return void 0===t||t&&\"string\"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(V):(t=V(t))in r?[t]:t.match(R)||[]).length;while(n--)delete r[t[n]]}(void 0===t||k.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!k.isEmptyObject(t)}};var Q=new Y,J=new Y,K=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,Z=/[A-Z]/g;function ee(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r=\"data-\"+t.replace(Z,\"-$&\").toLowerCase(),\"string\"==typeof(n=e.getAttribute(r))){try{n=\"true\"===(i=n)||\"false\"!==i&&(\"null\"===i?null:i===+i+\"\"?+i:K.test(i)?JSON.parse(i):i)}catch(e){}J.set(e,t,n)}else n=void 0;return n}k.extend({hasData:function(e){return J.hasData(e)||Q.hasData(e)},data:function(e,t,n){return J.access(e,t,n)},removeData:function(e,t){J.remove(e,t)},_data:function(e,t,n){return Q.access(e,t,n)},_removeData:function(e,t){Q.remove(e,t)}}),k.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=J.get(o),1===o.nodeType&&!Q.get(o,\"hasDataAttrs\"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf(\"data-\")&&(r=V(r.slice(5)),ee(o,r,i[r]));Q.set(o,\"hasDataAttrs\",!0)}return i}return\"object\"==typeof n?this.each(function(){J.set(this,n)}):_(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=J.get(o,n))?t:void 0!==(t=ee(o,n))?t:void 0;this.each(function(){J.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){J.remove(this,e)})}}),k.extend({queue:function(e,t,n){var r;if(e)return t=(t||\"fx\")+\"queue\",r=Q.get(e,t),n&&(!r||Array.isArray(n)?r=Q.access(e,t,k.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||\"fx\";var n=k.queue(e,t),r=n.length,i=n.shift(),o=k._queueHooks(e,t);\"inprogress\"===i&&(i=n.shift(),r--),i&&(\"fx\"===t&&n.unshift(\"inprogress\"),delete o.stop,i.call(e,function(){k.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+\"queueHooks\";return Q.get(e,n)||Q.access(e,n,{empty:k.Callbacks(\"once memory\").add(function(){Q.remove(e,[t+\"queue\",n])})})}}),k.fn.extend({queue:function(t,n){var e=2;return\"string\"!=typeof t&&(n=t,t=\"fx\",e--),arguments.length<e?k.queue(this[0],t):void 0===n?this:this.each(function(){var e=k.queue(this,t,n);k._queueHooks(this,t),\"fx\"===t&&\"inprogress\"!==e[0]&&k.dequeue(this,t)})},dequeue:function(e){return this.each(function(){k.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||\"fx\",[])},promise:function(e,t){var n,r=1,i=k.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};\"string\"!=typeof e&&(t=e,e=void 0),e=e||\"fx\";while(a--)(n=Q.get(o[a],e+\"queueHooks\"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var te=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,ne=new RegExp(\"^(?:([+-])=|)(\"+te+\")([a-z%]*)$\",\"i\"),re=[\"Top\",\"Right\",\"Bottom\",\"Left\"],ie=E.documentElement,oe=function(e){return k.contains(e.ownerDocument,e)},ae={composed:!0};ie.getRootNode&&(oe=function(e){return k.contains(e.ownerDocument,e)||e.getRootNode(ae)===e.ownerDocument});var se=function(e,t){return\"none\"===(e=t||e).style.display||\"\"===e.style.display&&oe(e)&&\"none\"===k.css(e,\"display\")},ue=function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];for(o in i=n.apply(e,r||[]),t)e.style[o]=a[o];return i};function le(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return k.css(e,t,\"\")},u=s(),l=n&&n[3]||(k.cssNumber[t]?\"\":\"px\"),c=e.nodeType&&(k.cssNumber[t]||\"px\"!==l&&+u)&&ne.exec(k.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)k.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,k.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ce={};function fe(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?(\"none\"===n&&(l[c]=Q.get(r,\"display\")||null,l[c]||(r.style.display=\"\")),\"\"===r.style.display&&se(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ce[s])||(o=a.body.appendChild(a.createElement(s)),u=k.css(o,\"display\"),o.parentNode.removeChild(o),\"none\"===u&&(u=\"block\"),ce[s]=u)))):\"none\"!==n&&(l[c]=\"none\",Q.set(r,\"display\",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}k.fn.extend({show:function(){return fe(this,!0)},hide:function(){return fe(this)},toggle:function(e){return\"boolean\"==typeof e?e?this.show():this.hide():this.each(function(){se(this)?k(this).show():k(this).hide()})}});var pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i,he=/^$|^module$|\\/(?:java|ecma)script/i,ge={option:[1,\"<select multiple='multiple'>\",\"</select>\"],thead:[1,\"<table>\",\"</table>\"],col:[2,\"<table><colgroup>\",\"</colgroup></table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:[0,\"\",\"\"]};function ve(e,t){var n;return n=\"undefined\"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):\"undefined\"!=typeof e.querySelectorAll?e.querySelectorAll(t||\"*\"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Q.set(e[n],\"globalEval\",!t||Q.get(t[n],\"globalEval\"))}ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;var me,xe,be=/<|&#?\\w+;/;function we(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if(\"object\"===w(o))k.merge(p,o.nodeType?[o]:o);else if(be.test(o)){a=a||f.appendChild(t.createElement(\"div\")),s=(de.exec(o)||[\"\",\"\"])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+k.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;k.merge(p,a.childNodes),(a=f.firstChild).textContent=\"\"}else p.push(t.createTextNode(o));f.textContent=\"\",d=0;while(o=p[d++])if(r&&-1<k.inArray(o,r))i&&i.push(o);else if(l=oe(o),a=ve(f.appendChild(o),\"script\"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||\"\")&&n.push(o)}return f}me=E.createDocumentFragment().appendChild(E.createElement(\"div\")),(xe=E.createElement(\"input\")).setAttribute(\"type\",\"radio\"),xe.setAttribute(\"checked\",\"checked\"),xe.setAttribute(\"name\",\"t\"),me.appendChild(xe),y.checkClone=me.cloneNode(!0).cloneNode(!0).lastChild.checked,me.innerHTML=\"<textarea>x</textarea>\",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==(\"focus\"===t)}function Ae(e,t,n,r,i,o){var a,s;if(\"object\"==typeof t){for(s in\"string\"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&(\"string\"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return\"undefined\"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||\"\").match(R)||[\"\"]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(\".\")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||\"\").match(R)||[\"\"]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&(\"**\"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,\"handle events\")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,\"events\")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t<arguments.length;t++)u[t]=arguments[t];if(s.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,s)){a=k.event.handlers.call(this,s,l),t=0;while((i=a[t++])&&!s.isPropagationStopped()){s.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!s.isImmediatePropagationStopped())s.rnamespace&&!1!==o.namespace&&!s.rnamespace.test(o.namespace)||(s.handleObj=o,s.data=o.data,void 0!==(r=((k.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,u))&&!1===(s.result=r)&&(s.preventDefault(),s.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,s),s.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!(\"click\"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&(\"click\"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+\" \"]&&(a[i]=r.needsContext?-1<k(i,this).index(l):k.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(k.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[k.expando]?e:new k.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,\"input\")&&De(t,\"click\",ke),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,\"input\")&&De(t,\"click\"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,\"input\")&&Q.get(t,\"click\")||A(t,\"a\")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},k.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},k.Event=function(e,t){if(!(this instanceof k.Event))return new k.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?ke:Se,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&k.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[k.expando]=!0},k.Event.prototype={constructor:k.Event,isDefaultPrevented:Se,isPropagationStopped:Se,isImmediatePropagationStopped:Se,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=ke,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=ke,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=ke,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},k.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,\"char\":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&Te.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&Ce.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},k.event.addProp),k.each({focus:\"focusin\",blur:\"focusout\"},function(e,t){k.event.special[e]={setup:function(){return De(this,e,Ne),!1},trigger:function(){return De(this,e),!0},delegateType:t}}),k.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(e,i){k.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||k.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),k.fn.extend({on:function(e,t,n,r){return Ae(this,e,t,n,r)},one:function(e,t,n,r){return Ae(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,k(e.delegateTarget).off(r.namespace?r.origType+\".\"+r.namespace:r.origType,r.selector,r.handler),this;if(\"object\"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&\"function\"!=typeof t||(n=t,t=void 0),!1===n&&(n=Se),this.each(function(){k.event.remove(this,e,n,t)})}});var je=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)[^>]*)\\/>/gi,qe=/<script|<style|<link/i,Le=/checked\\s*(?:[^=]|=\\s*.checked.)/i,He=/^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;function Oe(e,t){return A(e,\"table\")&&A(11!==t.nodeType?t:t.firstChild,\"tr\")&&k(e).children(\"tbody\")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute(\"type\"))+\"/\"+e.type,e}function Re(e){return\"true/\"===(e.type||\"\").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute(\"type\"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n<r;n++)k.event.add(t,i,l[i][n]);J.hasData(e)&&(s=J.access(e),u=k.extend({},s),J.set(t,u))}}function Ie(n,r,i,o){r=g.apply([],r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&\"string\"==typeof d&&!y.checkClone&&Le.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Ie(t,r,i,o)});if(f&&(t=(e=we(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=k.map(ve(e,\"script\"),Pe)).length;c<f;c++)u=e,c!==p&&(u=k.clone(u,!0,!0),s&&k.merge(a,ve(u,\"script\"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,k.map(a,Re),c=0;c<s;c++)u=a[c],he.test(u.type||\"\")&&!Q.access(u,\"globalEval\")&&k.contains(l,u)&&(u.src&&\"module\"!==(u.type||\"\").toLowerCase()?k._evalUrl&&!u.noModule&&k._evalUrl(u.src,{nonce:u.nonce||u.getAttribute(\"nonce\")}):b(u.textContent.replace(He,\"\"),u,l))}return n}function We(e,t,n){for(var r,i=t?k.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||k.cleanData(ve(r)),r.parentNode&&(n&&oe(r)&&ye(ve(r,\"script\")),r.parentNode.removeChild(r));return e}k.extend({htmlPrefilter:function(e){return e.replace(je,\"<$1></$2>\")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,\"input\"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:\"input\"!==l&&\"textarea\"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Me(o[r],a[r]);else Me(e,c);return 0<(a=ve(c,\"script\")).length&&ye(a,!f&&ve(e,\"script\")),c},cleanData:function(e){for(var t,n,r,i=k.event.special,o=0;void 0!==(n=e[o]);o++)if(G(n)){if(t=n[Q.expando]){if(t.events)for(r in t.events)i[r]?k.event.remove(n,r):k.removeEvent(n,r,t.handle);n[Q.expando]=void 0}n[J.expando]&&(n[J.expando]=void 0)}}}),k.fn.extend({detach:function(e){return We(this,e,!0)},remove:function(e){return We(this,e)},text:function(e){return _(this,function(e){return void 0===e?k.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Ie(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Oe(this,e).appendChild(e)})},prepend:function(){return Ie(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Oe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(k.cleanData(ve(e,!1)),e.textContent=\"\");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return k.clone(this,e,t)})},html:function(e){return _(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if(\"string\"==typeof e&&!qe.test(e)&&!ge[(de.exec(e)||[\"\",\"\"])[1].toLowerCase()]){e=k.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(k.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Ie(this,arguments,function(e){var t=this.parentNode;k.inArray(this,n)<0&&(k.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),k.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(e,a){k.fn[e]=function(e){for(var t,n=[],r=k(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),k(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var $e=new RegExp(\"^(\"+te+\")(?!px)[a-z%]+$\",\"i\"),Fe=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},Be=new RegExp(re.join(\"|\"),\"i\");function _e(e,t,n){var r,i,o,a,s=e.style;return(n=n||Fe(e))&&(\"\"!==(a=n.getPropertyValue(t)||n[t])||oe(e)||(a=k.style(e,t)),!y.pixelBoxStyles()&&$e.test(a)&&Be.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+\"\":a}function ze(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(u){s.style.cssText=\"position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0\",u.style.cssText=\"position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%\",ie.appendChild(s).appendChild(u);var e=C.getComputedStyle(u);n=\"1%\"!==e.top,a=12===t(e.marginLeft),u.style.right=\"60%\",o=36===t(e.right),r=36===t(e.width),u.style.position=\"absolute\",i=12===t(u.offsetWidth/3),ie.removeChild(s),u=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s=E.createElement(\"div\"),u=E.createElement(\"div\");u.style&&(u.style.backgroundClip=\"content-box\",u.cloneNode(!0).style.backgroundClip=\"\",y.clearCloneStyle=\"content-box\"===u.style.backgroundClip,k.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),a},scrollboxSize:function(){return e(),i}}))}();var Ue=[\"Webkit\",\"Moz\",\"ms\"],Xe=E.createElement(\"div\").style,Ve={};function Ge(e){var t=k.cssProps[e]||Ve[e];return t||(e in Xe?e:Ve[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Ue.length;while(n--)if((e=Ue[n]+t)in Xe)return e}(e)||e)}var Ye=/^(none|table(?!-c[ea]).+)/,Qe=/^--/,Je={position:\"absolute\",visibility:\"hidden\",display:\"block\"},Ke={letterSpacing:\"0\",fontWeight:\"400\"};function Ze(e,t,n){var r=ne.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||\"px\"):t}function et(e,t,n,r,i,o){var a=\"width\"===t?1:0,s=0,u=0;if(n===(r?\"border\":\"content\"))return 0;for(;a<4;a+=2)\"margin\"===n&&(u+=k.css(e,n+re[a],!0,i)),r?(\"content\"===n&&(u-=k.css(e,\"padding\"+re[a],!0,i)),\"margin\"!==n&&(u-=k.css(e,\"border\"+re[a]+\"Width\",!0,i))):(u+=k.css(e,\"padding\"+re[a],!0,i),\"padding\"!==n?u+=k.css(e,\"border\"+re[a]+\"Width\",!0,i):s+=k.css(e,\"border\"+re[a]+\"Width\",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e[\"offset\"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function tt(e,t,n){var r=Fe(e),i=(!y.boxSizingReliable()||n)&&\"border-box\"===k.css(e,\"boxSizing\",!1,r),o=i,a=_e(e,t,r),s=\"offset\"+t[0].toUpperCase()+t.slice(1);if($e.test(a)){if(!n)return a;a=\"auto\"}return(!y.boxSizingReliable()&&i||\"auto\"===a||!parseFloat(a)&&\"inline\"===k.css(e,\"display\",!1,r))&&e.getClientRects().length&&(i=\"border-box\"===k.css(e,\"boxSizing\",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+et(e,t,n||(i?\"border\":\"content\"),o,r,a)+\"px\"}function nt(e,t,n,r,i){return new nt.prototype.init(e,t,n,r,i)}k.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=_e(e,\"opacity\");return\"\"===n?\"1\":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=V(t),u=Qe.test(t),l=e.style;if(u||(t=Ge(s)),a=k.cssHooks[t]||k.cssHooks[s],void 0===n)return a&&\"get\"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];\"string\"===(o=typeof n)&&(i=ne.exec(n))&&i[1]&&(n=le(e,t,i),o=\"number\"),null!=n&&n==n&&(\"number\"!==o||u||(n+=i&&i[3]||(k.cssNumber[s]?\"\":\"px\")),y.clearCloneStyle||\"\"!==n||0!==t.indexOf(\"background\")||(l[t]=\"inherit\"),a&&\"set\"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=V(t);return Qe.test(t)||(t=Ge(s)),(a=k.cssHooks[t]||k.cssHooks[s])&&\"get\"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=_e(e,t,r)),\"normal\"===i&&t in Ke&&(i=Ke[t]),\"\"===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),k.each([\"height\",\"width\"],function(e,u){k.cssHooks[u]={get:function(e,t,n){if(t)return!Ye.test(k.css(e,\"display\"))||e.getClientRects().length&&e.getBoundingClientRect().width?tt(e,u,n):ue(e,Je,function(){return tt(e,u,n)})},set:function(e,t,n){var r,i=Fe(e),o=!y.scrollboxSize()&&\"absolute\"===i.position,a=(o||n)&&\"border-box\"===k.css(e,\"boxSizing\",!1,i),s=n?et(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e[\"offset\"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-et(e,u,\"border\",!1,i)-.5)),s&&(r=ne.exec(t))&&\"px\"!==(r[3]||\"px\")&&(e.style[u]=t,t=k.css(e,u)),Ze(0,t,s)}}}),k.cssHooks.marginLeft=ze(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(_e(e,\"marginLeft\"))||e.getBoundingClientRect().left-ue(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+\"px\"}),k.each({margin:\"\",padding:\"\",border:\"Width\"},function(i,o){k.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r=\"string\"==typeof e?e.split(\" \"):[e];t<4;t++)n[i+re[t]+o]=r[t]||r[t-2]||r[0];return n}},\"margin\"!==i&&(k.cssHooks[i+o].set=Ze)}),k.fn.extend({css:function(e,t){return _(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Fe(e),i=t.length;a<i;a++)o[t[a]]=k.css(e,t[a],!1,r);return o}return void 0!==n?k.style(e,t,n):k.css(e,t)},e,t,1<arguments.length)}}),((k.Tween=nt).prototype={constructor:nt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||k.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(k.cssNumber[n]?\"\":\"px\")},cur:function(){var e=nt.propHooks[this.prop];return e&&e.get?e.get(this):nt.propHooks._default.get(this)},run:function(e){var t,n=nt.propHooks[this.prop];return this.options.duration?this.pos=t=k.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):nt.propHooks._default.set(this),this}}).init.prototype=nt.prototype,(nt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=k.css(e.elem,e.prop,\"\"))&&\"auto\"!==t?t:0},set:function(e){k.fx.step[e.prop]?k.fx.step[e.prop](e):1!==e.elem.nodeType||!k.cssHooks[e.prop]&&null==e.elem.style[Ge(e.prop)]?e.elem[e.prop]=e.now:k.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=nt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},k.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:\"swing\"},k.fx=nt.prototype.init,k.fx.step={};var rt,it,ot,at,st=/^(?:toggle|show|hide)$/,ut=/queueHooks$/;function lt(){it&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(lt):C.setTimeout(lt,k.fx.interval),k.fx.tick())}function ct(){return C.setTimeout(function(){rt=void 0}),rt=Date.now()}function ft(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i[\"margin\"+(n=re[r])]=i[\"padding\"+n]=e;return t&&(i.opacity=i.width=e),i}function pt(e,t,n){for(var r,i=(dt.tweeners[t]||[]).concat(dt.tweeners[\"*\"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function dt(o,e,t){var n,a,r=0,i=dt.prefilters.length,s=k.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=rt||ct(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:k.extend({},e),opts:k.extend(!0,{specialEasing:{},easing:k.easing._default},t),originalProperties:e,originalOptions:t,startTime:rt||ct(),duration:t.duration,tweens:[],createTween:function(e,t){var n=k.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=V(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=k.cssHooks[r])&&\"expand\"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=dt.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(k._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return k.map(c,pt,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),k.fx.timer(k.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}k.Animation=k.extend(dt,{tweeners:{\"*\":[function(e,t){var n=this.createTween(e,t);return le(n.elem,e,ne.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=[\"*\"]):e=e.match(R);for(var n,r=0,i=e.length;r<i;r++)n=e[r],dt.tweeners[n]=dt.tweeners[n]||[],dt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f=\"width\"in t||\"height\"in t,p=this,d={},h=e.style,g=e.nodeType&&se(e),v=Q.get(e,\"fxshow\");for(r in n.queue||(null==(a=k._queueHooks(e,\"fx\")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,k.queue(e,\"fx\").length||a.empty.fire()})})),t)if(i=t[r],st.test(i)){if(delete t[r],o=o||\"toggle\"===i,i===(g?\"hide\":\"show\")){if(\"show\"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||k.style(e,r)}if((u=!k.isEmptyObject(t))||!k.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Q.get(e,\"display\")),\"none\"===(c=k.css(e,\"display\"))&&(l?c=l:(fe([e],!0),l=e.style.display||l,c=k.css(e,\"display\"),fe([e]))),(\"inline\"===c||\"inline-block\"===c&&null!=l)&&\"none\"===k.css(e,\"float\")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l=\"none\"===c?\"\":c)),h.display=\"inline-block\")),n.overflow&&(h.overflow=\"hidden\",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?\"hidden\"in v&&(g=v.hidden):v=Q.access(e,\"fxshow\",{display:l}),o&&(v.hidden=!g),g&&fe([e],!0),p.done(function(){for(r in g||fe([e]),Q.remove(e,\"fxshow\"),d)k.style(e,r,d[r])})),u=pt(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?dt.prefilters.unshift(e):dt.prefilters.push(e)}}),k.speed=function(e,t,n){var r=e&&\"object\"==typeof e?k.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return k.fx.off?r.duration=0:\"number\"!=typeof r.duration&&(r.duration in k.fx.speeds?r.duration=k.fx.speeds[r.duration]:r.duration=k.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue=\"fx\"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&k.dequeue(this,r.queue)},r},k.fn.extend({fadeTo:function(e,t,n,r){return this.filter(se).css(\"opacity\",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=k.isEmptyObject(t),o=k.speed(e,n,r),a=function(){var e=dt(this,k.extend({},t),o);(i||Q.get(this,\"finish\"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return\"string\"!=typeof i&&(o=e,e=i,i=void 0),e&&!1!==i&&this.queue(i||\"fx\",[]),this.each(function(){var e=!0,t=null!=i&&i+\"queueHooks\",n=k.timers,r=Q.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&ut.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||k.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||\"fx\"),this.each(function(){var e,t=Q.get(this),n=t[a+\"queue\"],r=t[a+\"queueHooks\"],i=k.timers,o=n?n.length:0;for(t.finish=!0,k.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),k.each([\"toggle\",\"show\",\"hide\"],function(e,r){var i=k.fn[r];k.fn[r]=function(e,t,n){return null==e||\"boolean\"==typeof e?i.apply(this,arguments):this.animate(ft(r,!0),e,t,n)}}),k.each({slideDown:ft(\"show\"),slideUp:ft(\"hide\"),slideToggle:ft(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(e,r){k.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),k.timers=[],k.fx.tick=function(){var e,t=0,n=k.timers;for(rt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||k.fx.stop(),rt=void 0},k.fx.timer=function(e){k.timers.push(e),k.fx.start()},k.fx.interval=13,k.fx.start=function(){it||(it=!0,lt())},k.fx.stop=function(){it=null},k.fx.speeds={slow:600,fast:200,_default:400},k.fn.delay=function(r,e){return r=k.fx&&k.fx.speeds[r]||r,e=e||\"fx\",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},ot=E.createElement(\"input\"),at=E.createElement(\"select\").appendChild(E.createElement(\"option\")),ot.type=\"checkbox\",y.checkOn=\"\"!==ot.value,y.optSelected=at.selected,(ot=E.createElement(\"input\")).value=\"t\",ot.type=\"radio\",y.radioValue=\"t\"===ot.value;var ht,gt=k.expr.attrHandle;k.fn.extend({attr:function(e,t){return _(this,k.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){k.removeAttr(this,e)})}}),k.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return\"undefined\"==typeof e.getAttribute?k.prop(e,t,n):(1===o&&k.isXMLDoc(e)||(i=k.attrHooks[t.toLowerCase()]||(k.expr.match.bool.test(t)?ht:void 0)),void 0!==n?null===n?void k.removeAttr(e,t):i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+\"\"),n):i&&\"get\"in i&&null!==(r=i.get(e,t))?r:null==(r=k.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&\"radio\"===t&&A(e,\"input\")){var n=e.value;return e.setAttribute(\"type\",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(R);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),ht={set:function(e,t,n){return!1===t?k.removeAttr(e,n):e.setAttribute(n,n),n}},k.each(k.expr.match.bool.source.match(/\\w+/g),function(e,t){var a=gt[t]||k.find.attr;gt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=gt[o],gt[o]=r,r=null!=a(e,t,n)?o:null,gt[o]=i),r}});var vt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;function mt(e){return(e.match(R)||[]).join(\" \")}function xt(e){return e.getAttribute&&e.getAttribute(\"class\")||\"\"}function bt(e){return Array.isArray(e)?e:\"string\"==typeof e&&e.match(R)||[]}k.fn.extend({prop:function(e,t){return _(this,k.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[k.propFix[e]||e]})}}),k.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&k.isXMLDoc(e)||(t=k.propFix[t]||t,i=k.propHooks[t]),void 0!==n?i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&\"get\"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=k.find.attr(e,\"tabindex\");return t?parseInt(t,10):vt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{\"for\":\"htmlFor\",\"class\":\"className\"}}),y.optSelected||(k.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),k.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){k.propFix[this.toLowerCase()]=this}),k.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).addClass(t.call(this,e,xt(this)))});if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&\" \"+mt(i)+\" \"){a=0;while(o=e[a++])r.indexOf(\" \"+o+\" \")<0&&(r+=o+\" \");i!==(s=mt(r))&&n.setAttribute(\"class\",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).removeClass(t.call(this,e,xt(this)))});if(!arguments.length)return this.attr(\"class\",\"\");if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&\" \"+mt(i)+\" \"){a=0;while(o=e[a++])while(-1<r.indexOf(\" \"+o+\" \"))r=r.replace(\" \"+o+\" \",\" \");i!==(s=mt(r))&&n.setAttribute(\"class\",s)}return this},toggleClass:function(i,t){var o=typeof i,a=\"string\"===o||Array.isArray(i);return\"boolean\"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){k(this).toggleClass(i.call(this,e,xt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=k(this),r=bt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&\"boolean\"!==o||((e=xt(this))&&Q.set(this,\"__className__\",e),this.setAttribute&&this.setAttribute(\"class\",e||!1===i?\"\":Q.get(this,\"__className__\")||\"\"))})},hasClass:function(e){var t,n,r=0;t=\" \"+e+\" \";while(n=this[r++])if(1===n.nodeType&&-1<(\" \"+mt(xt(n))+\" \").indexOf(t))return!0;return!1}});var wt=/\\r/g;k.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,k(this).val()):n)?t=\"\":\"number\"==typeof t?t+=\"\":Array.isArray(t)&&(t=k.map(t,function(e){return null==e?\"\":e+\"\"})),(r=k.valHooks[this.type]||k.valHooks[this.nodeName.toLowerCase()])&&\"set\"in r&&void 0!==r.set(this,t,\"value\")||(this.value=t))})):t?(r=k.valHooks[t.type]||k.valHooks[t.nodeName.toLowerCase()])&&\"get\"in r&&void 0!==(e=r.get(t,\"value\"))?e:\"string\"==typeof(e=t.value)?e.replace(wt,\"\"):null==e?\"\":e:void 0}}),k.extend({valHooks:{option:{get:function(e){var t=k.find.attr(e,\"value\");return null!=t?t:mt(k.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a=\"select-one\"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,\"optgroup\"))){if(t=k(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=k.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<k.inArray(k.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),k.each([\"radio\",\"checkbox\"],function(){k.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<k.inArray(k(e).val(),t)}},y.checkOn||(k.valHooks[this].get=function(e){return null===e.getAttribute(\"value\")?\"on\":e.value})}),y.focusin=\"onfocusin\"in C;var Tt=/^(?:focusinfocus|focusoutblur)$/,Ct=function(e){e.stopPropagation()};k.extend(k.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,\"type\")?e.type:e,h=v.call(e,\"namespace\")?e.namespace.split(\".\"):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!Tt.test(d+k.event.triggered)&&(-1<d.indexOf(\".\")&&(d=(h=d.split(\".\")).shift(),h.sort()),u=d.indexOf(\":\")<0&&\"on\"+d,(e=e[k.expando]?e:new k.Event(d,\"object\"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join(\".\"),e.rnamespace=e.namespace?new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:k.makeArray(t,[e]),c=k.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,Tt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Q.get(o,\"events\")||{})[e.type]&&Q.get(o,\"handle\"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&G(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!G(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),k.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,Ct),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,Ct),k.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=k.extend(new k.Event,n,{type:e,isSimulated:!0});k.event.trigger(r,null,t)}}),k.fn.extend({trigger:function(e,t){return this.each(function(){k.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return k.event.trigger(e,t,n,!0)}}),y.focusin||k.each({focus:\"focusin\",blur:\"focusout\"},function(n,r){var i=function(e){k.event.simulate(r,e.target,k.event.fix(e))};k.event.special[r]={setup:function(){var e=this.ownerDocument||this,t=Q.access(e,r);t||e.addEventListener(n,i,!0),Q.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this,t=Q.access(e,r)-1;t?Q.access(e,r,t):(e.removeEventListener(n,i,!0),Q.remove(e,r))}}});var Et=C.location,kt=Date.now(),St=/\\?/;k.parseXML=function(e){var t;if(!e||\"string\"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,\"text/xml\")}catch(e){t=void 0}return t&&!t.getElementsByTagName(\"parsererror\").length||k.error(\"Invalid XML: \"+e),t};var Nt=/\\[\\]$/,At=/\\r?\\n/g,Dt=/^(?:submit|button|image|reset|file)$/i,jt=/^(?:input|select|textarea|keygen)/i;function qt(n,e,r,i){var t;if(Array.isArray(e))k.each(e,function(e,t){r||Nt.test(n)?i(n,t):qt(n+\"[\"+(\"object\"==typeof t&&null!=t?e:\"\")+\"]\",t,r,i)});else if(r||\"object\"!==w(e))i(n,e);else for(t in e)qt(n+\"[\"+t+\"]\",e[t],r,i)}k.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+\"=\"+encodeURIComponent(null==n?\"\":n)};if(null==e)return\"\";if(Array.isArray(e)||e.jquery&&!k.isPlainObject(e))k.each(e,function(){i(this.name,this.value)});else for(n in e)qt(n,e[n],t,i);return r.join(\"&\")},k.fn.extend({serialize:function(){return k.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=k.prop(this,\"elements\");return e?k.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!k(this).is(\":disabled\")&&jt.test(this.nodeName)&&!Dt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=k(this).val();return null==n?null:Array.isArray(n)?k.map(n,function(e){return{name:t.name,value:e.replace(At,\"\\r\\n\")}}):{name:t.name,value:n.replace(At,\"\\r\\n\")}}).get()}});var Lt=/%20/g,Ht=/#.*$/,Ot=/([?&])_=[^&]*/,Pt=/^(.*?):[ \\t]*([^\\r\\n]*)$/gm,Rt=/^(?:GET|HEAD)$/,Mt=/^\\/\\//,It={},Wt={},$t=\"*/\".concat(\"*\"),Ft=E.createElement(\"a\");function Bt(o){return function(e,t){\"string\"!=typeof e&&(t=e,e=\"*\");var n,r=0,i=e.toLowerCase().match(R)||[];if(m(t))while(n=i[r++])\"+\"===n[0]?(n=n.slice(1)||\"*\",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function _t(t,i,o,a){var s={},u=t===Wt;function l(e){var r;return s[e]=!0,k.each(t[e]||[],function(e,t){var n=t(i,o,a);return\"string\"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s[\"*\"]&&l(\"*\")}function zt(e,t){var n,r,i=k.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&k.extend(!0,e,r),e}Ft.href=Et.href,k.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Et.href,type:\"GET\",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Et.protocol),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":$t,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":JSON.parse,\"text xml\":k.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,k.ajaxSettings),t):zt(k.ajaxSettings,e)},ajaxPrefilter:Bt(It),ajaxTransport:Bt(Wt),ajax:function(e,t){\"object\"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=k.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?k(y):k.event,x=k.Deferred(),b=k.Callbacks(\"once memory\"),w=v.statusCode||{},a={},s={},u=\"canceled\",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Pt.exec(p))n[t[1].toLowerCase()+\" \"]=(n[t[1].toLowerCase()+\" \"]||[]).concat(t[2])}t=n[e.toLowerCase()+\" \"]}return null==t?null:t.join(\", \")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Et.href)+\"\").replace(Mt,Et.protocol+\"//\"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||\"*\").toLowerCase().match(R)||[\"\"],null==v.crossDomain){r=E.createElement(\"a\");try{r.href=v.url,r.href=r.href,v.crossDomain=Ft.protocol+\"//\"+Ft.host!=r.protocol+\"//\"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&\"string\"!=typeof v.data&&(v.data=k.param(v.data,v.traditional)),_t(It,v,t,T),h)return T;for(i in(g=k.event&&v.global)&&0==k.active++&&k.event.trigger(\"ajaxStart\"),v.type=v.type.toUpperCase(),v.hasContent=!Rt.test(v.type),f=v.url.replace(Ht,\"\"),v.hasContent?v.data&&v.processData&&0===(v.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&(v.data=v.data.replace(Lt,\"+\")):(o=v.url.slice(f.length),v.data&&(v.processData||\"string\"==typeof v.data)&&(f+=(St.test(f)?\"&\":\"?\")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Ot,\"$1\"),o=(St.test(f)?\"&\":\"?\")+\"_=\"+kt+++o),v.url=f+o),v.ifModified&&(k.lastModified[f]&&T.setRequestHeader(\"If-Modified-Since\",k.lastModified[f]),k.etag[f]&&T.setRequestHeader(\"If-None-Match\",k.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader(\"Content-Type\",v.contentType),T.setRequestHeader(\"Accept\",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+(\"*\"!==v.dataTypes[0]?\", \"+$t+\"; q=0.01\":\"\"):v.accepts[\"*\"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u=\"abort\",b.add(v.complete),T.done(v.success),T.fail(v.error),c=_t(Wt,v,t,T)){if(T.readyState=1,g&&m.trigger(\"ajaxSend\",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort(\"timeout\")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,\"No Transport\");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||\"\",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while(\"*\"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader(\"Content-Type\"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+\" \"+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if(\"*\"===o)o=u;else if(\"*\"!==u&&u!==o){if(!(a=l[u+\" \"+o]||l[\"* \"+o]))for(i in l)if((s=i.split(\" \"))[1]===o&&(a=l[u+\" \"+s[0]]||l[\"* \"+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e[\"throws\"])t=a(t);else try{t=a(t)}catch(e){return{state:\"parsererror\",error:a?e:\"No conversion from \"+u+\" to \"+o}}}return{state:\"success\",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader(\"Last-Modified\"))&&(k.lastModified[f]=u),(u=T.getResponseHeader(\"etag\"))&&(k.etag[f]=u)),204===e||\"HEAD\"===v.type?l=\"nocontent\":304===e?l=\"notmodified\":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l=\"error\",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+\"\",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?\"ajaxSuccess\":\"ajaxError\",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger(\"ajaxComplete\",[T,v]),--k.active||k.event.trigger(\"ajaxStop\")))}return T},getJSON:function(e,t,n){return k.get(e,t,n,\"json\")},getScript:function(e,t){return k.get(e,void 0,t,\"script\")}}),k.each([\"get\",\"post\"],function(e,i){k[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),k.ajax(k.extend({url:e,type:i,dataType:r,data:t,success:n},k.isPlainObject(e)&&e))}}),k._evalUrl=function(e,t){return k.ajax({url:e,type:\"GET\",dataType:\"script\",cache:!0,async:!1,global:!1,converters:{\"text script\":function(){}},dataFilter:function(e){k.globalEval(e,t)}})},k.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=k(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){k(this).wrapInner(n.call(this,e))}):this.each(function(){var e=k(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){k(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not(\"body\").each(function(){k(this).replaceWith(this.childNodes)}),this}}),k.expr.pseudos.hidden=function(e){return!k.expr.pseudos.visible(e)},k.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},k.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var Ut={0:200,1223:204},Xt=k.ajaxSettings.xhr();y.cors=!!Xt&&\"withCredentials\"in Xt,y.ajax=Xt=!!Xt,k.ajaxTransport(function(i){var o,a;if(y.cors||Xt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e[\"X-Requested-With\"]||(e[\"X-Requested-With\"]=\"XMLHttpRequest\"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,\"abort\"===e?r.abort():\"error\"===e?\"number\"!=typeof r.status?t(0,\"error\"):t(r.status,r.statusText):t(Ut[r.status]||r.status,r.statusText,\"text\"!==(r.responseType||\"text\")||\"string\"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o(\"error\"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o(\"abort\");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),k.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),k.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(e){return k.globalEval(e),e}}}),k.ajaxPrefilter(\"script\",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type=\"GET\")}),k.ajaxTransport(\"script\",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=k(\"<script>\").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on(\"load error\",i=function(e){r.remove(),i=null,e&&t(\"error\"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\\?(?=&|$)|\\?\\?/;k.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var e=Gt.pop()||k.expando+\"_\"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter(\"json jsonp\",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?\"url\":\"string\"==typeof e.data&&0===(e.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&Yt.test(e.data)&&\"data\");if(a||\"jsonp\"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,\"$1\"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?\"&\":\"?\")+e.jsonp+\"=\"+r),e.converters[\"script json\"]=function(){return o||k.error(r+\" was not called\"),o[0]},e.dataTypes[0]=\"json\",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),\"script\"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument(\"\").body).innerHTML=\"<form></form><form></form>\",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return\"string\"!=typeof e?[]:(\"boolean\"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument(\"\")).createElement(\"base\")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(\" \");return-1<s&&(r=mt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&\"object\"==typeof t&&(i=\"POST\"),0<a.length&&k.ajax({url:e,type:i||\"GET\",dataType:\"html\",data:t}).done(function(e){o=arguments,a.html(r?k(\"<div>\").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,\"position\"),c=k(e),f={};\"static\"===l&&(e.style.position=\"relative\"),s=c.offset(),o=k.css(e,\"top\"),u=k.css(e,\"left\"),(\"absolute\"===l||\"fixed\"===l)&&-1<(o+u).indexOf(\"auto\")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),\"using\"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if(\"fixed\"===k.css(r,\"position\"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&\"static\"===k.css(e,\"position\"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,\"borderTopWidth\",!0),i.left+=k.css(e,\"borderLeftWidth\",!0))}return{top:t.top-i.top-k.css(r,\"marginTop\",!0),left:t.left-i.left-k.css(r,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&\"static\"===k.css(e,\"position\"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(t,i){var o=\"pageYOffset\"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each([\"top\",\"left\"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+\"px\":t})}),k.each({Height:\"height\",Width:\"width\"},function(a,s){k.each({padding:\"inner\"+a,content:s,\"\":\"outer\"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||\"boolean\"!=typeof e),i=r||(!0===e||!0===t?\"margin\":\"border\");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf(\"outer\")?e[\"inner\"+a]:e.document.documentElement[\"client\"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body[\"scroll\"+a],r[\"scroll\"+a],e.body[\"offset\"+a],r[\"offset\"+a],r[\"client\"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each(\"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu\".split(\" \"),function(e,n){k.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}}),k.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),k.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)}}),k.proxy=function(e,t){var n,r,i;if(\"string\"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||k.guid++,i},k.holdReady=function(e){e?k.readyWait++:k.ready(!0)},k.isArray=Array.isArray,k.parseJSON=JSON.parse,k.nodeName=A,k.isFunction=m,k.isWindow=x,k.camelCase=V,k.type=w,k.now=Date.now,k.isNumeric=function(e){var t=k.type(e);return(\"number\"===t||\"string\"===t)&&!isNaN(e-parseFloat(e))},\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return k});var Qt=C.jQuery,Jt=C.$;return k.noConflict=function(e){return C.$===k&&(C.$=Jt),e&&C.jQuery===k&&(C.jQuery=Qt),k},e||(C.jQuery=C.$=k),k});\n/*\n * jQuery throttle / debounce - v1.1 - 3/7/2010\n * http://benalman.com/projects/jquery-throttle-debounce-plugin/\n * \n * Copyright (c) 2010 \"Cowboy\" Ben Alman\n * Dual licensed under the MIT and GPL licenses.\n * http://benalman.com/about/license/\n */\n(function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!==\"boolean\"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this);\n/*!\n * imagesLoaded PACKAGED v4.1.0\n * JavaScript is all like \"You images are done yet or what?\"\n * MIT License\n */\n!function(t,e){\"function\"==typeof define&&define.amd?define(\"ev-emitter/ev-emitter\",e):\"object\"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}(this,function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var i=this._events=this._events||{},n=i[t]=i[t]||[];return-1==n.indexOf(e)&&n.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var i=this._onceEvents=this._onceEvents||{},n=i[t]=i[t]||[];return n[e]=!0,this}},e.off=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=i.indexOf(e);return-1!=n&&i.splice(n,1),this}},e.emitEvent=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=0,o=i[n];e=e||[];for(var r=this._onceEvents&&this._onceEvents[t];o;){var s=r&&r[o];s&&(this.off(t,o),delete r[o]),o.apply(this,e),n+=s?0:1,o=i[n]}return this}},t}),function(t,e){\"use strict\";\"function\"==typeof define&&define.amd?define([\"ev-emitter/ev-emitter\"],function(i){return e(t,i)}):\"object\"==typeof module&&module.exports?module.exports=e(t,require(\"ev-emitter\")):t.imagesLoaded=e(t,t.EvEmitter)}(window,function(t,e){function i(t,e){for(var i in e)t[i]=e[i];return t}function n(t){var e=[];if(Array.isArray(t))e=t;else if(\"number\"==typeof t.length)for(var i=0;i<t.length;i++)e.push(t[i]);else e.push(t);return e}function o(t,e,r){return this instanceof o?(\"string\"==typeof t&&(t=document.querySelectorAll(t)),this.elements=n(t),this.options=i({},this.options),\"function\"==typeof e?r=e:i(this.options,e),r&&this.on(\"always\",r),this.getImages(),h&&(this.jqDeferred=new h.Deferred),void setTimeout(function(){this.check()}.bind(this))):new o(t,e,r)}function r(t){this.img=t}function s(t,e){this.url=t,this.element=e,this.img=new Image}var h=t.jQuery,a=t.console;o.prototype=Object.create(e.prototype),o.prototype.options={},o.prototype.getImages=function(){this.images=[],this.elements.forEach(this.addElementImages,this)},o.prototype.addElementImages=function(t){\"IMG\"==t.nodeName&&this.addImage(t),this.options.background===!0&&this.addElementBackgroundImages(t);var e=t.nodeType;if(e&&d[e]){for(var i=t.querySelectorAll(\"img\"),n=0;n<i.length;n++){var o=i[n];this.addImage(o)}if(\"string\"==typeof this.options.background){var r=t.querySelectorAll(this.options.background);for(n=0;n<r.length;n++){var s=r[n];this.addElementBackgroundImages(s)}}}};var d={1:!0,9:!0,11:!0};return o.prototype.addElementBackgroundImages=function(t){var e=getComputedStyle(t);if(e)for(var i=/url\\((['\"])?(.*?)\\1\\)/gi,n=i.exec(e.backgroundImage);null!==n;){var o=n&&n[2];o&&this.addBackground(o,t),n=i.exec(e.backgroundImage)}},o.prototype.addImage=function(t){var e=new r(t);this.images.push(e)},o.prototype.addBackground=function(t,e){var i=new s(t,e);this.images.push(i)},o.prototype.check=function(){function t(t,i,n){setTimeout(function(){e.progress(t,i,n)})}var e=this;return this.progressedCount=0,this.hasAnyBroken=!1,this.images.length?void this.images.forEach(function(e){e.once(\"progress\",t),e.check()}):void this.complete()},o.prototype.progress=function(t,e,i){this.progressedCount++,this.hasAnyBroken=this.hasAnyBroken||!t.isLoaded,this.emitEvent(\"progress\",[this,t,e]),this.jqDeferred&&this.jqDeferred.notify&&this.jqDeferred.notify(this,t),this.progressedCount==this.images.length&&this.complete(),this.options.debug&&a&&a.log(\"progress: \"+i,t,e)},o.prototype.complete=function(){var t=this.hasAnyBroken?\"fail\":\"done\";if(this.isComplete=!0,this.emitEvent(t,[this]),this.emitEvent(\"always\",[this]),this.jqDeferred){var e=this.hasAnyBroken?\"reject\":\"resolve\";this.jqDeferred[e](this)}},r.prototype=Object.create(e.prototype),r.prototype.check=function(){var t=this.getIsImageComplete();return t?void this.confirm(0!==this.img.naturalWidth,\"naturalWidth\"):(this.proxyImage=new Image,this.proxyImage.addEventListener(\"load\",this),this.proxyImage.addEventListener(\"error\",this),this.img.addEventListener(\"load\",this),this.img.addEventListener(\"error\",this),void(this.proxyImage.src=this.img.src))},r.prototype.getIsImageComplete=function(){return this.img.complete&&void 0!==this.img.naturalWidth},r.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent(\"progress\",[this,this.img,e])},r.prototype.handleEvent=function(t){var e=\"on\"+t.type;this[e]&&this[e](t)},r.prototype.onload=function(){this.confirm(!0,\"onload\"),this.unbindEvents()},r.prototype.onerror=function(){this.confirm(!1,\"onerror\"),this.unbindEvents()},r.prototype.unbindEvents=function(){this.proxyImage.removeEventListener(\"load\",this),this.proxyImage.removeEventListener(\"error\",this),this.img.removeEventListener(\"load\",this),this.img.removeEventListener(\"error\",this)},s.prototype=Object.create(r.prototype),s.prototype.check=function(){this.img.addEventListener(\"load\",this),this.img.addEventListener(\"error\",this),this.img.src=this.url;var t=this.getIsImageComplete();t&&(this.confirm(0!==this.img.naturalWidth,\"naturalWidth\"),this.unbindEvents())},s.prototype.unbindEvents=function(){this.img.removeEventListener(\"load\",this),this.img.removeEventListener(\"error\",this)},s.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent(\"progress\",[this,this.element,e])},o.makeJQueryPlugin=function(e){e=e||t.jQuery,e&&(h=e,h.fn.imagesLoaded=function(t,e){var i=new o(this,t,e);return i.jqDeferred.promise(h(this))})},o.makeJQueryPlugin(),o});\n/*! lz-string-1.3.3-min.js | (c) 2013 Pieroxy | Licensed under a WTFPL license */\nvar LZString={_keyStr:\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\",_f:String.fromCharCode,compressToBase64:function(e){if(e==null)return\"\";var t=\"\";var n,r,i,s,o,u,a;var f=0;e=LZString.compress(e);while(f<e.length*2){if(f%2==0){n=e.charCodeAt(f/2)>>8;r=e.charCodeAt(f/2)&255;if(f/2+1<e.length)i=e.charCodeAt(f/2+1)>>8;else i=NaN}else{n=e.charCodeAt((f-1)/2)&255;if((f+1)/2<e.length){r=e.charCodeAt((f+1)/2)>>8;i=e.charCodeAt((f+1)/2)&255}else r=i=NaN}f+=3;s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+LZString._keyStr.charAt(s)+LZString._keyStr.charAt(o)+LZString._keyStr.charAt(u)+LZString._keyStr.charAt(a)}return t},decompressFromBase64:function(e){if(e==null)return\"\";var t=\"\",n=0,r,i,s,o,u,a,f,l,c=0,h=LZString._f;e=e.replace(/[^A-Za-z0-9\\+\\/\\=]/g,\"\");while(c<e.length){u=LZString._keyStr.indexOf(e.charAt(c++));a=LZString._keyStr.indexOf(e.charAt(c++));f=LZString._keyStr.indexOf(e.charAt(c++));l=LZString._keyStr.indexOf(e.charAt(c++));i=u<<2|a>>4;s=(a&15)<<4|f>>2;o=(f&3)<<6|l;if(n%2==0){r=i<<8;if(f!=64){t+=h(r|s)}if(l!=64){r=o<<8}}else{t=t+h(r|i);if(f!=64){r=s<<8}if(l!=64){t+=h(r|o)}}n+=3}return LZString.decompress(t)},compressToUTF16:function(e){if(e==null)return\"\";var t=\"\",n,r,i,s=0,o=LZString._f;e=LZString.compress(e);for(n=0;n<e.length;n++){r=e.charCodeAt(n);switch(s++){case 0:t+=o((r>>1)+32);i=(r&1)<<14;break;case 1:t+=o(i+(r>>2)+32);i=(r&3)<<13;break;case 2:t+=o(i+(r>>3)+32);i=(r&7)<<12;break;case 3:t+=o(i+(r>>4)+32);i=(r&15)<<11;break;case 4:t+=o(i+(r>>5)+32);i=(r&31)<<10;break;case 5:t+=o(i+(r>>6)+32);i=(r&63)<<9;break;case 6:t+=o(i+(r>>7)+32);i=(r&127)<<8;break;case 7:t+=o(i+(r>>8)+32);i=(r&255)<<7;break;case 8:t+=o(i+(r>>9)+32);i=(r&511)<<6;break;case 9:t+=o(i+(r>>10)+32);i=(r&1023)<<5;break;case 10:t+=o(i+(r>>11)+32);i=(r&2047)<<4;break;case 11:t+=o(i+(r>>12)+32);i=(r&4095)<<3;break;case 12:t+=o(i+(r>>13)+32);i=(r&8191)<<2;break;case 13:t+=o(i+(r>>14)+32);i=(r&16383)<<1;break;case 14:t+=o(i+(r>>15)+32,(r&32767)+32);s=0;break}}return t+o(i+32)},decompressFromUTF16:function(e){if(e==null)return\"\";var t=\"\",n,r,i=0,s=0,o=LZString._f;while(s<e.length){r=e.charCodeAt(s)-32;switch(i++){case 0:n=r<<1;break;case 1:t+=o(n|r>>14);n=(r&16383)<<2;break;case 2:t+=o(n|r>>13);n=(r&8191)<<3;break;case 3:t+=o(n|r>>12);n=(r&4095)<<4;break;case 4:t+=o(n|r>>11);n=(r&2047)<<5;break;case 5:t+=o(n|r>>10);n=(r&1023)<<6;break;case 6:t+=o(n|r>>9);n=(r&511)<<7;break;case 7:t+=o(n|r>>8);n=(r&255)<<8;break;case 8:t+=o(n|r>>7);n=(r&127)<<9;break;case 9:t+=o(n|r>>6);n=(r&63)<<10;break;case 10:t+=o(n|r>>5);n=(r&31)<<11;break;case 11:t+=o(n|r>>4);n=(r&15)<<12;break;case 12:t+=o(n|r>>3);n=(r&7)<<13;break;case 13:t+=o(n|r>>2);n=(r&3)<<14;break;case 14:t+=o(n|r>>1);n=(r&1)<<15;break;case 15:t+=o(n|r);i=0;break}s++}return LZString.decompress(t)},compress:function(e){if(e==null)return\"\";var t,n,r={},i={},s=\"\",o=\"\",u=\"\",a=2,f=3,l=2,c=\"\",h=0,p=0,d,v=LZString._f;for(d=0;d<e.length;d+=1){s=e.charAt(d);if(!Object.prototype.hasOwnProperty.call(r,s)){r[s]=f++;i[s]=true}o=u+s;if(Object.prototype.hasOwnProperty.call(r,o)){u=o}else{if(Object.prototype.hasOwnProperty.call(i,u)){if(u.charCodeAt(0)<256){for(t=0;t<l;t++){h=h<<1;if(p==15){p=0;c+=v(h);h=0}else{p++}}n=u.charCodeAt(0);for(t=0;t<8;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}else{n=1;for(t=0;t<l;t++){h=h<<1|n;if(p==15){p=0;c+=v(h);h=0}else{p++}n=0}n=u.charCodeAt(0);for(t=0;t<16;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}delete i[u]}else{n=r[u];for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}r[o]=f++;u=String(s)}}if(u!==\"\"){if(Object.prototype.hasOwnProperty.call(i,u)){if(u.charCodeAt(0)<256){for(t=0;t<l;t++){h=h<<1;if(p==15){p=0;c+=v(h);h=0}else{p++}}n=u.charCodeAt(0);for(t=0;t<8;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}else{n=1;for(t=0;t<l;t++){h=h<<1|n;if(p==15){p=0;c+=v(h);h=0}else{p++}n=0}n=u.charCodeAt(0);for(t=0;t<16;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}delete i[u]}else{n=r[u];for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}}n=2;for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}while(true){h=h<<1;if(p==15){c+=v(h);break}else p++}return c},decompress:function(e){if(e==null)return\"\";if(e==\"\")return null;var t=[],n,r=4,i=4,s=3,o=\"\",u=\"\",a,f,l,c,h,p,d,v=LZString._f,m={string:e,val:e.charCodeAt(0),position:32768,index:1};for(a=0;a<3;a+=1){t[a]=a}l=0;h=Math.pow(2,2);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}switch(n=l){case 0:l=0;h=Math.pow(2,8);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}d=v(l);break;case 1:l=0;h=Math.pow(2,16);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}d=v(l);break;case 2:return\"\"}t[3]=d;f=u=d;while(true){if(m.index>m.string.length){return\"\"}l=0;h=Math.pow(2,s);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}switch(d=l){case 0:l=0;h=Math.pow(2,8);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}t[i++]=v(l);d=i-1;r--;break;case 1:l=0;h=Math.pow(2,16);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}t[i++]=v(l);d=i-1;r--;break;case 2:return u}if(r==0){r=Math.pow(2,s);s++}if(t[d]){o=t[d]}else{if(d===i){o=f+f.charAt(0)}else{return null}}u+=o;t[i++]=f+o.charAt(0);r--;f=o;if(r==0){r=Math.pow(2,s);s++}}}};if(typeof module!==\"undefined\"&&module!=null){module.exports=LZString}\n/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */\nvar saveAs=saveAs||navigator.msSaveBlob&&navigator.msSaveBlob.bind(navigator)||function(e){\"use strict\";var t=e.document,n=function(){return e.URL||e.webkitURL||e},r=e.URL||e.webkitURL||e,i=t.createElementNS(\"http://www.w3.org/1999/xhtml\",\"a\"),s=\"download\"in i,o=function(n){var r=t.createEvent(\"MouseEvents\");r.initMouseEvent(\"click\",true,false,e,0,0,0,0,0,false,false,false,false,0,null);n.dispatchEvent(r)},u=e.webkitRequestFileSystem,a=e.requestFileSystem||u||e.mozRequestFileSystem,f=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},l=\"application/octet-stream\",c=0,h=[],p=function(){var e=h.length;while(e--){var t=h[e];if(typeof t===\"string\"){r.revokeObjectURL(t)}else{t.remove()}}h.length=0},d=function(e,t,n){t=[].concat(t);var r=t.length;while(r--){var i=e[\"on\"+t[r]];if(typeof i===\"function\"){try{i.call(e,n||e)}catch(s){f(s)}}}},v=function(t,r){var f=this,p=t.type,v=false,m,g,y=function(){var e=n().createObjectURL(t);h.push(e);return e},b=function(){d(f,\"writestart progress write writeend\".split(\" \"))},w=function(){if(v||!m){m=y(t)}if(g){g.location.href=m}else{window.open(m,\"_blank\")}f.readyState=f.DONE;b()},E=function(e){return function(){if(f.readyState!==f.DONE){return e.apply(this,arguments)}}},S={create:true,exclusive:false},x;f.readyState=f.INIT;if(!r){r=\"download\"}if(s){m=y(t);i.href=m;i.download=r;o(i);f.readyState=f.DONE;b();return}if(e.chrome&&p&&p!==l){x=t.slice||t.webkitSlice;t=x.call(t,0,t.size,l);v=true}if(u&&r!==\"download\"){r+=\".download\"}if(p===l||u){g=e}if(!a){w();return}c+=t.size;a(e.TEMPORARY,c,E(function(e){e.root.getDirectory(\"saved\",S,E(function(e){var n=function(){e.getFile(r,S,E(function(e){e.createWriter(E(function(n){n.onwriteend=function(t){g.location.href=e.toURL();h.push(e);f.readyState=f.DONE;d(f,\"writeend\",t)};n.onerror=function(){var e=n.error;if(e.code!==e.ABORT_ERR){w()}};\"writestart progress write abort\".split(\" \").forEach(function(e){n[\"on\"+e]=f[\"on\"+e]});n.write(t);f.abort=function(){n.abort();f.readyState=f.DONE};f.readyState=f.WRITING}),w)}),w)};e.getFile(r,{create:false},E(function(e){e.remove();n()}),E(function(e){if(e.code===e.NOT_FOUND_ERR){n()}else{w()}}))}),w)}),w)},m=v.prototype,g=function(e,t){return new v(e,t)};m.abort=function(){var e=this;e.readyState=e.DONE;d(e,\"abort\")};m.readyState=m.INIT=0;m.WRITING=1;m.DONE=2;m.error=m.onwritestart=m.onprogress=m.onwrite=m.onabort=m.onerror=m.onwriteend=null;e.addEventListener(\"unload\",p,false);return g}(self)\n/*! seedrandom.js v2.3.3 | (c) 2013 David Bau, all rights reserved. | Licensed under a BSD-style license */\n!function(a,b,c,d,e,f,g,h,i){function j(a){var b,c=a.length,e=this,f=0,g=e.i=e.j=0,h=e.S=[];for(c||(a=[c++]);d>f;)h[f]=f++;for(f=0;d>f;f++)h[f]=h[g=r&g+a[f%c]+(b=h[f])],h[g]=b;(e.g=function(a){for(var b,c=0,f=e.i,g=e.j,h=e.S;a--;)b=h[f=r&f+1],c=c*d+h[r&(h[f]=h[g=r&g+b])+(h[g]=b)];return e.i=f,e.j=g,c})(d)}function k(a,b){var c,d=[],e=typeof a;if(b&&\"object\"==e)for(c in a)try{d.push(k(a[c],b-1))}catch(f){}return d.length?d:\"string\"==e?a:a+\"\\0\"}function l(a,b){for(var c,d=a+\"\",e=0;e<d.length;)b[r&e]=r&(c^=19*b[r&e])+d.charCodeAt(e++);return n(b)}function m(c){try{return a.crypto.getRandomValues(c=new Uint8Array(d)),n(c)}catch(e){return[+new Date,a,(c=a.navigator)&&c.plugins,a.screen,n(b)]}}function n(a){return String.fromCharCode.apply(0,a)}var o=c.pow(d,e),p=c.pow(2,f),q=2*p,r=d-1,s=c[\"seed\"+i]=function(a,f,g){var h=[],r=l(k(f?[a,n(b)]:null==a?m():a,3),h),s=new j(h);return l(n(s.S),b),(g||function(a,b,d){return d?(c[i]=a,b):a})(function(){for(var a=s.g(e),b=o,c=0;p>a;)a=(a+c)*d,b*=d,c=s.g(1);for(;a>=q;)a/=2,b/=2,c>>>=1;return(a+c)/b},r,this==c)};l(c[i](),b),g&&g.exports?g.exports=s:h&&h.amd&&h(function(){return s})}(this,[],Math,256,6,52,\"object\"==typeof module&&module,\"function\"==typeof define&&define,\"random\");\n/*! console_hack.js | (c) 2015 Thomas Michael Edwards | Licensed under SugarCube's Simple BSD license */\n!function(){for(var methods=[\"assert\",\"clear\",\"count\",\"debug\",\"dir\",\"dirxml\",\"error\",\"exception\",\"group\",\"groupCollapsed\",\"groupEnd\",\"info\",\"log\",\"markTimeline\",\"profile\",\"profileEnd\",\"table\",\"time\",\"timeEnd\",\"timeline\",\"timelineEnd\",\"timeStamp\",\"trace\",\"warn\"],length=methods.length,noop=function(){},console=window.console=window.console||{};length--;){var method=methods[length];console[method]||(console[method]=noop)}}();\n}else{document.documentElement.setAttribute(\"data-init\", \"lacking\");}\n</script>\n<style id=\"style-normalize\" type=\"text/css\">/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\n\n/**\n * 1. Set default font family to sans-serif.\n * 2. Prevent iOS and IE text size adjust after device orientation change,\n *    without disabling user zoom.\n */\n\nhtml {\n  font-family: sans-serif; /* 1 */\n  -ms-text-size-adjust: 100%; /* 2 */\n  -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/**\n * Remove default margin.\n */\n\nbody {\n  margin: 0;\n}\n\n/* HTML5 display definitions\n   ========================================================================== */\n\n/**\n * Correct `block` display not defined for any HTML5 element in IE 8/9.\n * Correct `block` display not defined for `details` or `summary` in IE 10/11\n * and Firefox.\n * Correct `block` display not defined for `main` in IE 11.\n */\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\n\n/**\n * 1. Correct `inline-block` display not defined in IE 8/9.\n * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n */\n\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block; /* 1 */\n  vertical-align: baseline; /* 2 */\n}\n\n/**\n * Prevent modern browsers from displaying `audio` without controls.\n * Remove excess height in iOS 5 devices.\n */\n\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n\n/**\n * Address `[hidden]` styling not present in IE 8/9/10.\n * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.\n */\n\n[hidden],\ntemplate {\n  display: none;\n}\n\n/* Links\n   ========================================================================== */\n\n/**\n * Remove the gray background color from active links in IE 10.\n */\n\na {\n  background-color: transparent;\n}\n\n/**\n * Improve readability of focused elements when they are also in an\n * active/hover state.\n */\n\na:active,\na:hover {\n  outline: 0;\n}\n\n/* Text-level semantics\n   ========================================================================== */\n\n/**\n * Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n */\n\nabbr[title] {\n  border-bottom: 1px dotted;\n}\n\n/**\n * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n */\n\nb,\nstrong {\n  font-weight: bold;\n}\n\n/**\n * Address styling not present in Safari and Chrome.\n */\n\ndfn {\n  font-style: italic;\n}\n\n/**\n * Address variable `h1` font-size and margin within `section` and `article`\n * contexts in Firefox 4+, Safari, and Chrome.\n */\n\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\n/**\n * Address styling not present in IE 8/9.\n */\n\nmark {\n  background: #ff0;\n  color: #000;\n}\n\n/**\n * Address inconsistent and variable font size in all browsers.\n */\n\nsmall {\n  font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` affecting `line-height` in all browsers.\n */\n\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\n/* Embedded content\n   ========================================================================== */\n\n/**\n * Remove border when inside `a` element in IE 8/9/10.\n */\n\nimg {\n  border: 0;\n}\n\n/**\n * Correct overflow not hidden in IE 9/10/11.\n */\n\nsvg:not(:root) {\n  overflow: hidden;\n}\n\n/* Grouping content\n   ========================================================================== */\n\n/**\n * Address margin not present in IE 8/9 and Safari.\n */\n\nfigure {\n  margin: 1em 40px;\n}\n\n/**\n * Address differences between Firefox and other browsers.\n */\n\nhr {\n  box-sizing: content-box;\n  height: 0;\n}\n\n/**\n * Contain overflow in all browsers.\n */\n\npre {\n  overflow: auto;\n}\n\n/**\n * Address odd `em`-unit font size rendering in all browsers.\n */\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\n\n/* Forms\n   ========================================================================== */\n\n/**\n * Known limitation: by default, Chrome and Safari on OS X allow very limited\n * styling of `select`, unless a `border` property is set.\n */\n\n/**\n * 1. Correct color not being inherited.\n *    Known issue: affects color of disabled elements.\n * 2. Correct font properties not being inherited.\n * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit; /* 1 */\n  font: inherit; /* 2 */\n  margin: 0; /* 3 */\n}\n\n/**\n * Address `overflow` set to `hidden` in IE 8/9/10/11.\n */\n\nbutton {\n  overflow: visible;\n}\n\n/**\n * Address inconsistent `text-transform` inheritance for `button` and `select`.\n * All other form control elements do not inherit `text-transform` values.\n * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n * Correct `select` style inheritance in Firefox.\n */\n\nbutton,\nselect {\n  text-transform: none;\n}\n\n/**\n * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n *    and `video` controls.\n * 2. Correct inability to style clickable `input` types in iOS.\n * 3. Improve usability and consistency of cursor style between image-type\n *    `input` and others.\n */\n\nbutton,\nhtml input[type=\"button\"], /* 1 */\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button; /* 2 */\n  cursor: pointer; /* 3 */\n}\n\n/**\n * Re-set default cursor for disabled elements.\n */\n\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\n\n/**\n * Remove inner padding and border in Firefox 4+.\n */\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\n\n/**\n * Address Firefox 4+ setting `line-height` on `input` using `!important` in\n * the UA stylesheet.\n */\n\ninput {\n  line-height: normal;\n}\n\n/**\n * It's recommended that you don't attempt to style these elements.\n * Firefox's implementation doesn't respect box-sizing, padding, or width.\n *\n * 1. Address box sizing set to `content-box` in IE 8/9/10.\n * 2. Remove excess padding in IE 8/9/10.\n */\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Fix the cursor style for Chrome's increment/decrement buttons. For certain\n * `font-size` values of the `input`, it causes the cursor style of the\n * decrement button to change from `default` to `text`.\n */\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\n/**\n * 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.\n */\n\ninput[type=\"search\"] {\n  -webkit-appearance: textfield; /* 1 */\n  box-sizing: content-box; /* 2 */\n}\n\n/**\n * Remove inner padding and search cancel button in Safari and Chrome on OS X.\n * Safari (but not Chrome) clips the cancel button when the search input has\n * padding (and `textfield` appearance).\n */\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n/**\n * Define consistent border, margin, and padding.\n */\n\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\n\n/**\n * 1. Correct `color` not being inherited in IE 8/9/10/11.\n * 2. Remove padding so people aren't caught out if they zero out fieldsets.\n */\n\nlegend {\n  border: 0; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Remove default vertical scrollbar in IE 8/9/10/11.\n */\n\ntextarea {\n  overflow: auto;\n}\n\n/**\n * Don't inherit the `font-weight` (applied by a rule above).\n * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n */\n\noptgroup {\n  font-weight: bold;\n}\n\n/* Tables\n   ========================================================================== */\n\n/**\n * Remove most spacing between table cells.\n */\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\ntd,\nth {\n  padding: 0;\n}\n</style>\n<style id=\"style-init-screen\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/init-screen.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n@-webkit-keyframes init-loading-spin {\n\t0%   { -webkit-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); }\n}\n\n@-o-keyframes init-loading-spin {\n\t0%   { -o-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -o-transform: rotate(360deg); transform: rotate(360deg); }\n}\n\n@keyframes init-loading-spin {\n\t0%   { -webkit-transform: rotate(0deg); -o-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -webkit-transform: rotate(360deg); -o-transform: rotate(360deg); transform: rotate(360deg); }\n}\n#init-screen {\n\tdisplay: none;\n\tz-index: 500000;\n\tposition: fixed;\n\ttop: 0px;\n\tleft: 0px;\n\theight: 100%;\n\twidth: 100%;\n\tfont: 28px/1 Helmet, Freesans, sans-serif;\n\tfont-weight: bold;\n\tcolor: #eee;\n\tbackground-color: #111;\n\ttext-align: center;\n}\n#init-screen > div {\n\tdisplay: none;\n\tposition: relative;\n\tmargin: 0 auto;\n\tmax-width: 1136px;\n\ttop: 25%;\n}\nhtml[data-init=\"no-js\"] #init-screen, html[data-init=\"lacking\"] #init-screen, html[data-init=\"loading\"] #init-screen {\n\tdisplay: block;\n}\nhtml[data-init=\"no-js\"] #init-no-js, html[data-init=\"lacking\"] #init-lacking {\n\tdisplay: block;\n\tpadding: 0 1em;\n}\nhtml[data-init=\"no-js\"] #init-no-js {\n\tcolor: red;\n}\nhtml[data-init=\"loading\"] #init-loading {\n\tdisplay: block;\n\tborder: 24px solid transparent;\n\tborder-radius: 50%;\n\tborder-top-color: #7f7f7f;\n\tborder-bottom-color: #7f7f7f;\n\twidth: 100px;\n\theight: 100px;\n\t-webkit-animation: init-loading-spin 2s linear infinite;\n\t     -o-animation: init-loading-spin 2s linear infinite;\n\t        animation: init-loading-spin 2s linear infinite;\n}\nhtml[data-init=\"loading\"] #init-loading > div {\n\ttext-indent: 9999em;\n\toverflow: hidden;\n\twhite-space: nowrap;\n}\nhtml[data-init=\"loading\"] #ui-bar, html[data-init=\"loading\"] #passages {\n\tdisplay: none;\n}\n</style>\n<style id=\"style-font\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/font.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n@font-face {\n\t/*\n\t\ttme-fa-icons (2020-03-27)\n\n\t\t`tme-fa-icons` is a subset of the Font Awesome font v4.7.0 by Dave Gandy (http://fontawesome.com)\n\t\tand is licensed under the SIL OFL 1.1 (http://scripts.sil.org/OFL).\n\t*/\n\tfont-family: \"tme-fa-icons\";\n\tsrc: url('data:application/octet-stream;base64,d09GRgABAAAAADLAAA8AAAAAWHgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABWAAAADsAAABUIIslek9TLzIAAAGUAAAAQwAAAFY+IEkIY21hcAAAAdgAAAG8AAAF3rob9jFjdnQgAAADlAAAABMAAAAgBtX/BGZwZ20AAAOoAAAFkAAAC3CKkZBZZ2FzcAAACTgAAAAIAAAACAAAABBnbHlmAAAJQAAAI6gAADv+gJOpzGhlYWQAACzoAAAAMwAAADYY1IZaaGhlYQAALRwAAAAgAAAAJAfCBClobXR4AAAtPAAAAJEAAAFMBfb/0WxvY2EAAC3QAAAAqAAAAKhjiHI5bWF4cAAALngAAAAgAAAAIAFjDA9uYW1lAAAumAAAAY0AAAL94+zEpHBvc3QAADAoAAACHAAAA11cG/YjcHJlcAAAMkQAAAB6AAAAhuVBK7x4nGNgZGBg4GIwYLBjYHJx8wlh4MtJLMljkGJgYYAAkDwymzEnMz2RgQPGA8qxgGkOIGaDiAIAJjsFSAB4nGNgZNZgnMDAysDAVMW0h4GBoQdCMz5gMGRkAooysDIzYAUBaa4pDA4vGF4EMgf9z2KIYg5imAYUZgTJAQDSIQumAHic7dTVbltRAETR7dpNCikzQ8rMzMxt/M39mHnsU1/TfZz5jFpaV7pXJunMDLAZmOqaZjD5y4Tx+uPTyeL5lG2L5zN+L94zG8+ztr7ulXH1fra4bvK9M79xiWW2sNXPbWeFHexkF7vZw172sZ8DHOQQhznCUY5xnBOc5BSnOcNZVjnHeS5wkUtc5gpX/f3r3OAmt7jNHe5yj/s84CGPeMwTnvKM57zgJa94zRve8o73fOAjn/jMF77yje/84Ce/WGPun1zi/2tlXKbp3Xyc44bFyZanSWokJDXOOjXSk/LUSXn+pEwCKTNBaqQqZU5IjX+XMjukTBEp80TKZJEyY6RMGylzR8oEkjKLpEwlKfNJyqSSMrOkTC8pc0zKRJMy26RMOSnzTsrkk7IDpGwDKXtByoaQsiukbA0p+0PKJpGyU6RsFyl7RmosQcrukbKFpOwjKZtJyo6Ssq2k7C0pG0zKLpOy1aTsNymbTsrOk7L9pNwBUi4CKbeBlCtByr0g5XKQckNIuSak3BVSLgwpt4aUq0PK/SHlEpFyk0i5TqTcKVIuFim3i5QrRso9I+WykXLjXOYNzP8BuAPUwHicY2BAAxIQyBz0PwuEARJsA90AeJytVml300YUHXlJnIQsJQstamHExGmwRiZswYAJQbJjIF2crZWgixQ76b7xid/gX/Nk2nPoN35a7xsvJJC053Cak6N3583VzNtlElqS2AvrkZSbL8XU1iaN7DwJ6YZNy1F8KDt7IWWKyd8FURCtltq3HYdERCJQta6wRBD7HlmaZHzoUUbLtqRXTcotPekuW+NBvVXffho6yrE7oaRmM3RoPbIlVRhVokimPVLSpmWo+itJK7y/wsxXzVDCiE4iabwZxtBI3htntMpoNbbjKIpsstwoUiSa4UEUeZTVEufkigkMygfNkPLKpxHlw/yIrNijnFawS7bT/L4vead3OT+xX29RtuRAH8iO7ODsdCVfhFtbYdy0k+0oVBF213dCbNnsVP9mj/KaRgO3KzK90IxgqXyFECs/ocz+IVktnE/5kkejWrKRE0HrZU7sSz6B1uOIKXHNGFnQ3dEJEdT9kjMM9pg+Hvzx3imWCxMCeBzLekclnAgTKWFzNEnaMHJgJWWLKqn1rpg45XVaxFvCfu3a0ZfOaONQd2I8Ww8dWzlRyfFoUqeZTJ3aSc2jKQ2ilHQmeMyvAyg/oklebWM1iZVH0zhmxoREIgIt3EtTQSw7saQpBM2jGb25G6a5di1apMkD9dyj9/TmVri501PaDvSzRn9Wp2I62AvT6WnkL/Fp2uUiRen66Rl+TOJB1gIykS02w5SDB2/9DtLL15YchdcG2O7t8yuofdZE8KQB+xvQHk/VKQlMhZhViFZAYq1rWZbJ1awWqcjUd0OaVr6s0wSKchwXx76Mcf1fMzOWmBK+34nTsyMuPXPtSwjTHHybdT2a16nFcgFxZnlOp1mW7+s0x/IDneZZntfpCEtbp6MsP9RpgeVHOh1jeUELmnTfwZCLMOQCDpAwhKUDQ1hegiEsFQxhuQhDWBZhCMslGMLyYxjCchmGsLysZdXUU0nj2plYBmxCYGKOHrnMReVqKrlUQrtoVGpDnhJulVQUz6p/ZaBePPKGObAWSJfIml8xzpWPRuX41hUtbxo7V8Cx6m8fjvY58VLWi4U/Bf/V1lQlvWLNw5Or8BuGnmwnqjapeHRNl89VPbr+X1RUWAv0G0iFWCjKsmxwZyKEjzqdhmqglUPMbMw8tOt1y5qfw/03MUIWUP34NxQaC9yDTllJWe3grNXX27LcO4NyOBMsSTE38/pW+CIjs9J+kVnKno98HnAFjEpl2GoDrRW82ScxD5neJM8EcVtRNkja2M4EiQ0c84B5850EJmHqqg3kTuGGDfgFYW7BeSdconqjLIfuRezzKKT8W6fiRPaoaIzAs9kbYa/vQspvcQwkNPmlfgxUFaGpGDUV0DRSbqgGX8bZum1Cxg70Iyp2w7Ks4sPHFveVkm0ZhHykiNWjo5/WXqJOqtx+ZhSX752+BcEgNTF/e990cZDKu1rJMkdtA1O3GpVT15pD41WH6uZR9b3j7BM5a5puuiceel/TqtvBxVwssPZtDtJSJhfU9WGFDaLLxaVQ6mU0Se+4BxgWGNDvUIqN/6v62HyeK1WF0XEk307Ut9HnYAz8D9h/R/UD0Pdj6HINLs/3mhOfbvThbJmuohfrp+g3MGutuVm6BtzQdAPiIUetjrjKDXynBnF6pLkc6SHgY90V4gHAJoDF4BPdtYzmUwCj+Yw5PsDnzGHQZA6DLeYw2GbOGsAOcxjsMofBHnMYfMGcdYAvmcMgZA6DiDkMnjAnAHjKHAZfMYfB18xh8A1z7gN8yxwGMXMYJMxhsK/p1jDMLV7QXaC2QVWgA1NPWNzD4lBTZcj+jheG/b1BzP7BIKb+qOn2kPoTLwz1Z4OY+otBTP1V050h9TdeGOrvBjH1D4OY+ky/GMtlBr+MfJcKB5RdbD7n74n3D9vFQLkAAQAB//8AD3icrXsLcFzlleZ//v+++nb37dfte/VotVrdrW5JltuKpO6WJVluPyXbsmOEbGRjO4KVjWPZlsM4QIU4IYGlgCE2yxqKIQkJg2GreKQCTCZb1CZkiswjzOwOmSTATNVWTZLdDUwSMrVDsomD23vOf69assFAqgbk+773P4//nPOdc/5mwNjFl8WjosbaWblmxiOmIlTGYXzb11M7Z2ohAMbZCcZ5iG9prZl4whfwGju05xtttitUdwXYEUgkbQtWga5lC+XBaqJI285qpb8dVEc8Gnm5L5QM/f58yAlB399a7dD0mWAmdAqaMvBmKPKX9TdDwSjod9yhx03FAPcvI6Gk2lV33XoXUtKgL8C6Wa0WSzXbVjhg6JoqIPShCK0FOvOuE48K1V4B1VUQAVevugmP7Fz2CmTzW5/8+ZGP/+Kp7h/8oI4MuOZ7M5B9IvujH2Wf+PnCAjzn8ZK6AieMKRcvXnxWWSWCzGARlPcqtqs21WZzEBFgYIVDAYWzVJIrXBlH+hXGlWNM00GAJmYZ8sKBzTJFVZVppijqDFMVdTIWLa0o5JrdaHusPZGIG1IjFhQGK2mAZEe56kJnR1bTY7ZT7eivFGODBTdma3pHtlCNDVbwmgMHx/aO4R8ffeet5/ZCG6TfuV03IaSJU3oIzKsGO9+5PV+BwU5xqnOQx1aO8fW71yvD9fPn55/fA22PmsaFvfSgwZ8wzPiFvZ2DUMnzJ2hHVDMmHucPsSRrq7UQo4DMAV/AW7CANw/Zru3NIx20bBEpXwukArlxxOPReibaG63/SyQyiftzcBy3k1HuOHgjEgFHnkYfh4VodDJC4138Ff8hv5PlWbrWmm2O6grNEgGNCWGnbFtRm1Z04gzQPPWvkqMWF4eWU8DB267Df+gNe84bBvfRpfNI5Ny5yAmHDh5/PPLuByMlekDS9DsRR73nWHetwBShSO5PqCBQONO4E2wGlSvYZG6gMzeQ09SWFZC0tWION3oOVVXGTbGM+hrAzQj0O25yoN8R8YzzRsaZdzLwhpsGPEm783hAJ9+kq286eDX5pn/VydDjvk7i8EuchU21JJ3DNOqFzeABmywPcNXxhu/wB+3whrqwVw7Cn1j8vPfdDH6O7PR3fDV/Cb85wua/waSit309grZJHHOhHEQ9CA7zTGVCUb0ZvXzc1lrRe5Af+4An0aSL9op0IU9y6vRFtAYGKy7KJGFbQrdg2dXqGAwWilld0zUy9xLqd6A/zeFuy7gzYFmBOwOhZ6NNhZakm8YTI7S1pyM1mM032V26qevXGlzZ8+TKvROlB/BBkO9ACDalB7OZuBnuC5tRcAItpalENNOfhajVH1A2a1HjbHZ4N4r54oWLz4qPoe4jrMo2sonapm5QRQBQ3XycKVxwRRxjQuVCnWc6mrzOZ5FvBiraOmia5FubYRpok8n0ioRTKOQMNbWiszxYWAFZrQ1sB+dDJTFYghzyiBN3oB857ndIAha4Se/+YGUtjAkXXUO2xPE2eoe3TWPeMOXmzNi+j9w1HghvVbSAmu4c6nFac6MgbzXFU2baDr1241+98TfHtU/9t7df+MzU4msmfPYj06Wbw8Gqohda0/FkSyiyvtPGG/FsMKq1pLqmPvndkye/+y+08eYIHEJZpFmJra2Nop/VWuKcCwPvgRhnGlOFps6iIdAEmFVAKh53jblZyBU6nAFdbfX03tGwioZ9oGnEyDSWTQCyFzhoR+s/jdjgWLmc3L2K21zEmXCsM5aDm4g9Ny5v0PZVb+dY9Rcd/sl5eTiPj0nTaeiU+BhhW2qbuzJcUy2Nc2gCrjBkxWCqZiArGgOuwSzjAlDb5L91XfpvfYbpij6ZRIUWYoVcLqC2+UqNLddsMrekY3GZztVl2uQjpl4xjedIM+Uybc/r5viShuHgcgXuwQtpuoMHz8utCe/s8S+Y/7xMaYu2DX1yDrez3lp3cyyKdop+HLcLi878Uh9SKOSlj73cOIUFRVKVKHhaSS9JP452RCcYoJ3w85bz8Ckp9VN4xeZj9atpH4FnPCV4OtiDNIVYCrWwsbauK81VxUlaQnA+riFBisoUsiU0LbQpASCmmRAwg1MNJoH19uQ6WpriUV1jIQjphA5QjosiTfiy1tF+kPJKMTFYpAu6lkx40odnTv7VjYtC/QtTJyGH9HmMnKamGrcaqmaagRsMUwR9WeLmwsQREvIRevSvYa8uVFXo9Sc0w5A8/Rp5+jcxhXLuYAOIx/pbY+ggFp0FV8lNoLNAEQvyDkwBZR9T1ZC6xR0qFgsybix3DJcR7iIGwCsCHHQM0nYKVSBXQZPnqG7KDZiqrn8K524gpN9ghAx42k4GsvF3nohnA0kbnglkC9mrl7h4Db2TommKcVE1QOPRd97K5WJxsKO5nIjHbHtx/og3kK8iWys1he/EkKlqCbFOB6iKQp5Q5Yp6DB0AsjmPvHEFSGsoFraPaVpI2zLc2lmudErjJ/eeQwbKPoRBZulcwhwXYc6i1SdiEpiCF+KrFOIrAzKaHdhQ79tw4MAGuJv4rt8sQQu80jloGnnDfNVJBa+vn1WjSg1d8NHrg44FbTgdJ5+T77yy/gDI5wY7633yTbI7+CdyMDyEL2paDd0BvZjyfIYXH2/H+aqjDfXUisgnk3rFYMePoyZBegWanQpM5hKdlUSU1JnoQH2iG1d90IYADi0JPV2/oxMEeB7apm+aBngFw/ObMjzHzv7dgzyOh48fHZnmO9c8Wv+2RAGwHiP20UNnzx46mvYxyaMixDpZX22lQqQgRDqG4kYcMo92cpypAOo0Ti+iSYXJRGc5l8wvQhPfqpE0SYa7nDwkeQyh26OOlbecqVumoCwJ8+mDm+9/5T4eOyOt+4wk8WjavYTIG+7nD5Li2cWv8zGkMYoz51q2u3Y1JQSwfcumSn9JUxW0CZIWQ5isqKCo8zoGFPybx/lyHD2w4AaCBw7Ap1HIxAaHyZlr1tXG1owMt7h5Ox5QmxF4Iv6vDhaQoTFAYADuYIlnLa7b7RwtiOBDtVK1dbyCMXXxn5azOIIKfLFKaQP9K3HKIMYEQosvhkIWH23TQ9wIpCq9M4WxycnJsQIUYrEJ/bPGuOZohfHVzdmMaAmHm418c7DU3xdoyYPebFktPJtpHu7fefjw4R0VHiNTa06ZUTPe09a1sdTUVNrYtbo3nth11VW7tBa1d/U1a1t71rdG2u1IJNkWDYdbUs0pnnFT+OloWzISsdsjqVpvy9prqrNjed41POfPx2+J7TIXaWP5Wgf5bvToBEvpppQYOXPOJoda4gTQE6TsNK8sAvUSSHBFygfnfM9wL+8aK/Bddv0tZ8SufyKZ7ml7s20iCWdsPpPu4YVaXuur/2M6WX8riReTE21vtPUAnn4iyTxdf0vJ+/QM0pwsUL4D5BmUBQEeXpaU4W6RtExzN1In7eT9qHPpIoUdqAzSrdyHIPo1JNRps1uioCWJyIm2U/JG8oO4aZMXozF8b4RupRd5JJv7Nn8ZeUyxjlrakhJHcwO2gHMUDgGLR0MmS0GrIoMRWos0K81LUnPZYgmkw6sM8HtCoQTaT9y0Wu3f/MZuCYfijhMPhUVQNdL2hY8kMroS/8UvEqqeSfC/xzPV07k3vsqyrL+2ykYnhJjEz45OLIdbu4ncrbrWhImzltU7oqqaXAEdMWiHxPsSdvuF70K6/xf6FejjL13YBvFVP+UXrkwnyelZjBcltoLypQIoEmsoiDUw4C2QFS/I/J6yx5ybWOOqaMad0kJlKo+ElAdLqvRTMqOsgucuM64j3hgHU1H1mIkQ084Oje3eXT1lZwL1nwaD0BZMNfFTcHpv+sf7v6LEo4oZMlRbFNqH9tb60nEN0UkQ0mYawZNpR878eFuD1lWsl/Jb9J5iMbPlDKnkh3raBmS66U1M9Jm5rKUmMel1dKLOcxrVSgf5dJqU4o0g0pJyTlV37x4bytpCATOG8VUT4+m9cPoURiakE34ZMes/wbB0Roun+2p7h9oLSlwzQqZq2eIr+xe2/Rhp5QF8hHn5Hh/FfM9ibs32UrNG+l22ZbrnJ8N+fERAcD6YCp6nuPc2Aq/vWXiMfzKaye/BDfzTLPwe33MT8ns4P/y0uiLBdyZw3qRvNvGZegjF6H+escXvreOnkD7zm7IkADTbJEkU4sdw1jmwzpTj42smHLB82ijenjfx9YsXkccR+B5+I1azGtQk+4maTpnLlsBL75E7O1IPea+mzfPmUwQt00FJoG+nPxN/zruZzZprTljyx2GpXiHdYWBZtcINeB+2xVP16/GT9euDwf00TbqgK5gK7QvCmfp/wPn15WDa3BcM1l/Hy8F9wZQ31nf4Q2IjjrXyG+BnzXnMmqXiTuB5CLa01gINjvb8mesSTwHuSAEtzm8anp+uvwbdprkfhUs0wCNIxH6TP1l/vf6aPDThK0TXI5I+tjj+SX/8wIcaPxWX4y+CqsCiEIiAIzhsKrgfh+6qv+4L4RETPl6/zqMKukki9AA96OseZb3Zk7UKVKxZKt65tpR1J9p1sTGgP5Z4ah+KEzl73R/xEfr+I8H5fchlN/Jr0n0c3fSGkrz+vbhd5m2ZWltThDeKUaKh3WTZXWauS+WomBdMkjGvOCRuT9YfcIZxk0x24/5cT3q8redxe8TpTsLn03b9LIaFo/I0eQ7uxtjQm6rffI4elnTcJfbwX/qRFyG+Vw+SaJdyFIpugk0WXCcnaZFo1323viNAWHZPvk1+ugfjTf2sbcPR5LDT442bhwPj6Z5z9qi9wr8B85Ji51yXb3tISxlpSUtaZEYnFX8ZbHI6C8vk4ll2h5/YdRQbM0CUbSmXHsd5rH5zWz7fBnc/5iA1NLANwyQZ2+5JjiYfQ4mle+BxJA1prT9g+770dv4zTz9RnTPp+JlY4DJKoroOucmyT4fnsGIeFC3H9EtmB+qnGyP6413tPvs4BhIwipskDKakeIg+KKTgbl92JBkkHn1J3c8t+9ia2vBKhMFkGBJtEjrGDIzKE1SeAgTJiDAVRYpKmSGwMlksJor5gUWgjKlXYS0gurS4neaYflXJnaWBUjDKNAVhkWoF1WhHz7uJ2PapE8NHJkulySPD62/qVmLapMq10a997JqvnphQarc8dO3UQ2smYr38pfOWszK6fTs+eBKfHy4j8t2uWNrWnbDx5CNfe+TkxrHVE/EEW4ynxM9H2FhtpAeE2tnGFUH1J4xXChxD5hACLNXbLgOA3WU353rI37Y44SipbwdxwED/mEC0rOmuIzmlGkw7SBzNxZ6NN3519+zXRhV1Uosp3TdtGD68s4eXJo8uzHVtjyXc85gC9MYmRh+euuaRk+vhAG43Tm3RLGW7Clp52Oesq3N7dKVjnW9KxCdWjyFvi/nUs+Ja5CnPxtn+2t4NnVwLrELw76JqDMz1MacMGJoR0I5RVsA1lR/DLEdonLJLQWnOMcSamKlrszLnWWZ3mzcVOjsrnYWynTfVNmQ6aQFxrWtL9SQtgjqsojbxf5lp+qquSF1rVGyk02qZZEEKRkPdlv9ff3LVQ6MTFMas8xSft3fNVbd+vqg1KaF5w7RwBsirUye24UVXDS3oIcj/nz+56mF6qQlUAQ++gGoNytcxFG7P98DWMXMoHIL/6l/Z7p1riv8ko2oiyiru129WsSrmUjO1XdtWc0Pr7miOoWOV9YUQ07WQPmsCisWYDge5puAUAI3NIk6EQACmaQ+BGRaAwOSemV1TH90+vnlDrZBNFOi/nEUlLL96lYx5VZLqB5zDQLFQzGm6KuUX89L6YqxRuaPsCwXYTlJE1EVJt9ycWTo8bereoW7Wv38ewfOzmgI/N42Kn53LatjTxUCv85zbEyg+Y5hTcDddq99M2ysc8/51lABfjZ++8KvSxvUlnpCj7U+mIG3vR8yhXSbXEbaB3cDmatdds4lrhi9Z8hskNo2hkI+RQHWN6fMIUwKGFZiNhDmCNq6BoR1gejCoTzNdD86woB6cPDh33YFr91w99dHJLePr1tp525NylKZkzJtthLplN+ADzhOxjpiN1trRPwb/vhKfqIcMg8Mr3DDqd38o4cM36y9KWa+Tsn7v4/ocj134Vcg2TZsf/ABFKH4tYwrtObZYYxoF3QiQC+PjATwUho5+W8MkQlOOqUDxnlMNjZpsfB8zjJCxZe2afKeTjXeuboqT2XcOlsACB6XROFhWch7AeNy/VsZfx4fO5Aj8EjTVRPjLdtrmTS1NX7Azce6kmjZnnHf+1iuBiG0duzsmQTiZPzfjEoTGAqZ7xqt/nmmai8gXOWb0/sG9z8vyyPNOZjKDf9DlRgmQR93keVlHOU/9RTkfH8W8ieTQzWpsc21DGRM0Xw4soAUWDEDPtMB0oS9I5qeXC0PhMySPyTWjuYFctn9JEgWLp6FSXdz71TeSgzuQBmnXVHPXGqWhIhXkF+H2lQXxVqiSO5OthN9CQQSazmBOhdycwSgoZRJvQ28Yz8SVltDiwd3PUxMLN9De1dWehinH5783RvA9xhpyoHgnWAfGvE3sqtqOFT25rGIoMB4GBa0NAaepg2KYyiwVijQqFKGtopEeUFFYgQCboj0jZ8cCk7U1Q2W3MBBLjMRi0SCKxO0od6gD6Muon6Q35JGLDZS9DEpfLNZTA4aqrmrD0rwHCAO8Cs/Ur4a3J0Lql9WU4RfBJiYySfg+cviqaczLvipt59LuhbjXflPdSuRLUUd/9VV422jRv6SF/NbehYrcQ1p2AZ6jd80L5+kSRwE3WV+OVGTs9GvnU6yLDbJsrZ2aE+iijskqPtuHgTAktgz0r+xtaUaslZRRH6FKlRJrBwO9bK+lef8YXipg7j8GSJjM+GRPmSApRv6n//T4VrH3qqbRaNxoqoxSNMfwD6MV18yPulftrX+xZ7gXeka7vMCPgf2aQ8+N4bPuaKz7lg2LIGjjTT3x4T4jvubPYKL+cFtPTxscwm0DA+yVNaMjbFNt/cE9k+sUpoxgas8Gu1qjhG7GqUu+oAFel8B2gTDcgt+54If2XXv1VVsmVvRkM4m4TnnrYCGLtt5foc4F2rWO/NrIbxENvBHUy0WJBYqEg8hbyklAxoATvupfHMCZ3wAHaASEAFz/Y7pUPh+ZumWK7z65G1KGftgMJro0NbIzrOvbm1sCuhL9tBGKtrof1aLaZkdRjS4zYhzSDTDVw4bldnrPGtubWgKGiH0adR1JuR9VI/qErSgB72HMk0emp2+anr6F7kfTydZ+zdKSO0EdDRuTqaip3xAIjapaLa1aWqg/kmqNQEiXzza3ZFbqId3euezR4Iiqbkj5j7ZEIeTX7X4n9vLvLmKL2mAXILVUp0WPoyLCVJVGQ+/yNlGhjP8PNLq4y9vNy9rPrn+eW36OaPmdX0nTF7EIpu9XPlvW1XMgOiHbSHIL1ji1nsbpBdbAyXtlTRwjSHuCqyJvkjfAVEiMe317oeLEURlNKa/CI7tfVLxLp5qb4tFwUFVYJ3R6/STHqy1Xi1R9RLvvd6lSPIba14rZoo6zwa3w/7L18OGzRwC+N7B52+HD2zYPfA8OP3iIH9kyjkd4Fdwj9x85skUPzfXhQd9cSN96mB+97yjgoYUXvZ7kxYu/UW7mL7Eo+rwKK9byTKWsSWWz6N8VBaZxB5ShgDJZHerscm0J6L1at2fNGPH4CqQNZ+gAGTeaPZVNBB52IJ7nt/uI3N/B0707Do+8vmEH37rpdTLX8eEDd47Xr564Y3aIj+67azM8Q4dwYHjpHbJoOu1/8OkH++lk4s59Y2Lo+tsevG1ukA/N3uHb9f9TbkFebNRET61I/GEuOEtdCkxKcdfISpPptmSn01kdVNF4Y4NjHF1rWnh0cxWZKImsJdKcKPPIkZR5RIoYkcJ7dh665dDOHqV/4jgc2ILXkYz77zgwypGsH1zKst/L+ir6nJVsPdtR2zaC4aQTZC9CR4p0jigDQ6gmexJcUeeXdbS0xY7WslzDdpPF8uryAPX0L+tqoVNFD5QrFi7rbKGXwYnkJGCpwra4XMZe1th6JZcOCL0VgV445HepqL+l5jVdKMHP1VeH89a/WtYaK2/9Z/g4noyFYduzjf6WpSS0FIKDRovrC4aaQ9ZArQ9b1r/K58P0Yhi/4Msl4WPhFbUuzCTBb1OitsjmCVsAn+Qs3eokTJ1FeEQlI1nGXNlfnbS8tcc/sYz4wU8vsbd+lr/UII5u7mncOYBJ+WKc+5jsETe/L03AXCfmN4IlTVnCOYiVSxyWr5h45up7d/Lpu568c7ey4zRcu6yjzk9P3Xvu3im5qb9yaf98ab2AwZIsy0Zrq6nXxkG22zi121ScGiC71IoiZwcZqlAmzUCmvaU5GgkkzaQfoNCjlKimWnxvGhtR5b4r0roYFX59BZLFsvVB5NMRIVAGQ65bJoBsRuaFbLJM/0n3nZCLlZaWYKj+efWy88WezKv+yiG5dKnN23mX2uUJbi5bY+Rc4XgxBrHXGnlYb637gwLPEuXVBmD1ViiIyzgRfl5f9NddvfoB9NDxw0clWD9KV0FbdhMMjzfc+H7uJXEG8fo6Ns4O1q5fU+KCCq16PhXG3JuJcczFw6GwEaLSBXkQwNwF4DgLs1AgHDqA2FToAXEgCDpj+jTudDaDgUmnGsaG9bWx1UOVctJGzBlDf2HJWgZyh1HHkeV53RK5WC6Gc8fr45AzKSByxwlWHShTsxydSgfVLhALUZsXOiS8w0TlVOdJ006bC4ZayA43j7cN9WCqeCgYDTvGJzKnKG0Jn7ou6KSC18Frs8FUk2Jch1frv65/kWLdMMbf2fWfDKac4HFdaYpb8HY9ZDXZhnEylEgHP7t2L6YMcO46M22b111HA113zoFBDJQUpy/WLx6B36K+MxQdmlHBKerm0BIJKqUu68GgoLY0VSpexdChJiDC1WpC9qwK1cQYpS7U0BW0JAzeMrX6P+hRI2Dy4z/hqqmb4gS3jG8GLT77P1Ue5E4wfOFTFoioAS8NYVYZhv9umJapaPV6hct6wHdkHiowcqVYnvUivt5Qa+3vK/X2dBXy2Uy6pclBE4pR4XkwxWHTtq93vH+tv0l2U6pFvbNRePWrv51uBFbBWmgHbw/upXv+0LnRc1AxL/RjLrVgmvx/yP0Fq1KJxarV2A+PHct2HDvWwbvxJIYX60/THfzHrcdGH7shQm/iC2l6E/fXRumtaPU/ybeyx+p34UkVL0LJv9PAUHOomzL1w8q9uZaYoV3SIOoujHBKKii60eKMxhJHXUMgTQW0InVqqErq22AbYN6BHOMkFCMtlpWLDDc/0NM23tYLZ1uGMX5ZrWfPtkQj+chQ61lZiH+gZSiai0Sbz4JhDbeswXd2PSVr8E/twqtr8KXdu690Q2KpI6jHMMuhBjdRdbG9iQslEae6YVhDV7gBdOiHgK4iKtSERkv4yOpAP8ZMpimmNqtSRuUFG50FDD2AeaYRNrasGS0P2LTwuGDncpRJNtZ5Fpev85SVhMY6T3ewBJrtjAFIs8XZi95eSXOXLJkW75wKaXmE7afkst1TsjBDJxP3v3I//kG6Z9R+ce7WnfcfrvHRo6fPnT46CpteTMJZ7yXKMb2XTlHieMpspgUYLz+k3UsJV/LFTWNH7vvT08eHlfWHHtx+69yLSbZMRhHWhDn2SG0oYCC3qE/B0qAKuZqPg+b5XkErlwWmYkKlMkNY2eLmUAqF3OJinmKjrPIhuK1/W/IJ6z8kh5K1D2aK+/UTWqOzkz1fC4xVOgKKKqgjZqKV9nhTGGOgUGnZjiK4Mq8jJFKOMwJ0UxSLdlO/Ymvrtq8H3/UG+nBNcG0e7Vh79xt/yOf37KklDMPYaeyc3LZ1y8hwT671KoP8BApooL9agOqYUm2FATeRptTcdeQGxexmC3pWyw2u5ZSr4l9xsLCKW+DaaeqxVskXZql+XdTggY9NDrcHk331MoTzqZSj3fGlCe3GxJQT6IsGjeBkQOGQO53v+VKSb9E1EVMQ5vKs2/R7axiimWAmiVCh4/MZ1eYrecvvMWx9oa71KppmNkVhBs6G6m+veHkw8amOFi0QFY4pTI7RrikRxSd1jgBaCeytDEHmYSsUN/HTEEyqQVQ6ppY4937ER/nPmMXaWK6W8TvQy1cj+s28wcIlS70LHqQsSoS5rB18abP70ubwv0VMqrRhJALnb2SJXZ76vg7pAPc9++oF2+s8XzLyZUMt/3ajhy35encPGy4n+lIy4Xvvou1JERMJFmTa8zqHldSwlaBa9k6VC63heDzM/3cYttfndDMiKlbIwCN7eV2F8FS61toUNZhCzHltUoKChwg/yah6WVnr8jIXJer+ultoizj14CWn/GfvvEU5uIjTdtnx8nw86K1TlzWF5QsXBhYXGlw+3rLk/5IB/G8+gzZuYUagPa8ByoUaWfiRIuA35I4CrJOMVariLtOCaKD+Ryq3gvWTwSDci1AAfVtQi7zzsmWE4F5Vq/+RPKDe8714vX5SVSVGuXjxa2K/iCyN42qyOkbLkXwt6FIjmt5sRsHC11VB2yANZQl1HL+GWjFC9Em4Vx7Q2oKTeB2+oKkeL3xEkBU015zWlri4VEBrpICIlwZ7Eso2mgSVKs8GLeJN5YsLnmn7Lh7/45KS6ncSg5I/Por8NcaWi7UW27Te2JeyTGPqPg3VS9j2CzJyeznjn1qaGXCrpsq8ro655n7+1zi3WwkBRkGuRl5e3eMyi6L0TvDJcnYwTnM14fWG5Xyh5nXVLya56BmNJRUi25oYoiGRJBGXdaO+Rb1Y9R861mlZYzodsf21K8/wZ1mC8I75Hr9viTsF+fsW5BzxTSO1IFQNz6DJvnC/lPv9L6Ab4KcvfJU6gC94y9NfMP31s7i5XY5RIn6LJqKRxjAKDuOVppiQA65ycUhaEvVeQya8dVuF6uCYKClVFADVGd5FyGt9RTWAAgg50ahiNFm2YkcCarHv3QTW/6Jna0TY0VA0FEpnMkbciKJ0RGSrrMN/XzzKfy7p3saOsq21cUl7FVQ2Dboqxg8D38S4hnxooL2bGRU1qurqAtP1Q1M7xzd3Sd4MKlx9aN7cxtWq/1OQAi25ohrK0s0ilVHwbgmKVNGWD1T/IMmcmd2u68h5MhPsLpW6Mf7ZEUPfceC+0zfhdXy9uTm5cQffujnZrMQFzmZdv+n0HyDOnl33Z4RjOcFoIL338N50IIpBxBEd9+2+7fV+vGGHQ5Y18NCTDw1EwkITYRu/JwZe9fPMI+IfxFUsyjbSqvKhAcwt168pdedsTBbTzZxTnRzRxQyV/if8uggP8y2VcpqWw7iyTmgJOy3GuEu5oK35P5xC0L6GZFag308hopD9/6r3KyoE7rKG5Tqi3D9z8s6TM/3+7mEeeCxiPDanxdWDjxmRxwKIeebmVFVePajGtTl5VaWLcGDdLdMVpbTvxD0n9pWUyvQtew1RfioQFOU/1vU/Lotg4KmyMEz9nnuM2OINTVu8ETPuuUeXPuNZUcFYEmd9rFRbYSxfVUjLiN9dFerqyvd2yKWFBEEB548Fup3m1PWnBQHUERnjyKYur0O1v1pBfvl30u2Hnj4EwydOw/CBOyd23vd4+YefpuUbvHb84elmO9HXD1P3Tq1f48YM5VZ17msH5/d1fPtmWQndeOwTd1EnZNeXbtwsoBRbcbJ29T3T0GbGDO+3J95aen6KxViWDVCHL8i5wsPAxPLfE1FDb55RmQnmCYgrEoijOyX+6KeDoE66Tt5ONjkSgheKBA9LqL6qpqchU0E7QaSYtJ3+irSVimrrmpLJU3ej0gsK6vTRXbdlEXtnb9u17Z9B+Un9m9Hg5rmoE93YF4zCPwZ31H9b/6f6b3cEgzvAgAIYO4IwfMe64Q03nOX3fXzD8Lo7brzrLtiCz85tCkajwb6N0b9LJD738MOfSxTs2x7mj3yGsEgjzzBYB9Xw2hGCYAZOzYWG2uR6nFlvxlJeEZfO732ziNsX84be4ffMGz7/gRmQb1dyTX8Q/dtArU8Hb8Wybmgod53NBlQOilxbg9mPCIstK3sTAzE7O5BMJuTKkvJgwfulBskXM0CBMymXLQrpkSoDMVmJ6aA2QjGG4SJkRk38g5sd61dtYGoQ4St+jHY+U23r4aVWOEjtseoMnDgvfwCEm2+hp6r/X91AK4zYkU3HMVEaxnR3qBfqPzn+/wHPnsOreJxjYGRgYABi1vIsoXh+m68M3MwvgCIMt5YoxkDp2P9f/2exVDAHAbkcDEwgUQAz1Qu/AHicY2BkYGAO+p/FwMBS9v/r/68sFQxAERQQDACh8QbyeJxdT0sVwzAMy49AkAxAkbT3UQiAITGAISmAYQiA9th4ttUs7Q568UeSlVidiwSkB3PUPg+ESd6ZD/+8v7HyrtzwghY89ZB6BcyrYqc6RZhw48YhaA1Wc/v1PQtdeXJ/HppUmFM597nvBVK7D+Z+E8/uQZLBgDyaz3Llvxx02S3c/Hv813JrznryZP4F+6lSfQAAAAAAAAAAUAC2ATABaAGyAfoCJAKwAzYDmgQSBFwExgUyBbQF/AZOBvwHRAe2B/YISgigCPIJGglCCWQJignACgAKQAp2CroLAAtGC4oL8gxcDPINng5iDuYPag/6EF4RIBGGEeQSShKYEyQTbhOyFAoUYhS+FVoVphYoFooXHBeGGFoYnhjGGOwZChlOGXgZrBneGhwaWhqgGtIbLhvyHHQc2B1QHZ4d/wABAAAAUwBtAAYAAAAAAAIAIAAwAHMAAAB2C3AAAAAAeJx1kN9q2zAUh39q0441YxcbjN3tXJWWEcc1lEGvWkLbXZeSu8JUV/6T2VKQlY48w95ifYa9zt6jd/vFESUUYiP5O5/O8ZEE4AP+QWH9nHKsWeEdozXv4A0uIu/Sf488IN9G3sMQPyLv0/+MfICv+BV5iI/4wz+owVtGM/yNrPBZfYm8g/fqW+Rd+svIA/Jd5D18UovI+/S/Ix9gqp4iD3GoniduvvR1WQU5mhxLlmap3C/FUdVWN6IXoXK+k3MpnA2maVySuza0ZlToUZ07292YctFov6k2eWp8VzsrJ0m6qa+NNV4H87Dq1j2WWQiFFN61chX7yNy7mclDUoUwPxuPN/tjAoc5lvCoUaJCgOCI9pjfDGk/BPfMEGaus2pYaDQ0GgtWVP1Kx/ico2BkaQ0zGnKCnHNL09KNuK451721rLqhLfmfht5vzdrmp7Sr3nUfC07YL92afU1r+wrd7/Dh5WwdHrmLjDawanUK3+9acPXqPML7Wq3NaHL6pL+1QHuGMd8t5/8PvPGO3QAAAHicbZLnlpswEIV9DRiwvZtseu89Ib333vvmBWRZYMVC0pHEEufpg8BO/kTncOfTaLgMOtPr97o17P1/baKPACEiDBAjQYohRhhjDevYhu3YwA7sxC7sxh7sxT7sxwEcxCEcxhEcxTEcxwmcxCmcxhmcxTmcxwVcxCVkuIwruIpruI4buIlbuI07uIt7uI8HeIhHeIwneIpneI4XeIlXeI03eIt3eI8P+IhP+Iwv+Ipv+I5N/OiF1hEz9JKxUrtFrDl1lWF9NR9QIikToRaVjUouKxvOmNBjLxnlhgo2DbnM1djLKrNGnGPScSUzItzGv93yPP2bSQSX84z9cqFQdJ56yZRmMhW8mLlJJSaBI0XYPDaZKDUviZmvr6DrNjJMi0WcK1MTM02mqpbZlJtEsNx5SI238jSodJtoS7qv+BpPw67IY9xU+dg5TXjROTWwdGrIOzWhT+uA0jolxqjaZrSOnCF2Nmq16651EYpMm1fakAul9SJQeR5QVYQlk1VkZ8SwoVNFIVjWnKQrlBGdMToftdoZjrs77DajqXKrS02YEFxbbtdWkG0x44JJVUS5aBqKSlJwmhDrmOF2Hv9Wqsy4TNqoKhfmSrrQKuNSL5nvPG6p0s0AkEWkSWVZMy1Kx3ljk03qLuZ14lTmB8gNGmByGrGfjLrhlhJV2f7SaIneNF1ypQNbybBUSgZswQaWEUNngeay1/sD4l/60HicY/DewXAiKGIjI2Nf5AbGnRwMHAzJBRsZWJ02MTAyaIEYm7mYGDkgLD4GMIvNaRfTAaA0J5DN7rSLwQHCZmZw2ajC2BEYscGhI2Ijc4rLRjUQbxdHAwMji0NHckgESEkkEGzmYWLk0drB+L91A0vvRiYGFwAMdiP0AAA=') format('woff');\n}\n</style>\n<style id=\"style-core\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\nhtml {\n\t/*\n\t\tWe define the base font size and line height here as they affect the layout\n\t\tof the base page elements (i.e. `#ui-bar`, `#ui-dialog`, and `#story`).\n\t*/\n\tfont: 16px/1 Helmet, Freesans, sans-serif;\n}\n\n/* Story data styling. */\n#store-area, tw-storydata {\n\tdisplay: none !important;\n\tz-index: 0;\n}\n\n/* Special no transition styling. */\n.no-transition {\n\t-o-transition: none !important;\n\ttransition: none !important;\n}\n\n\n/*\n\tFullscreen appearance styles.\n*/\n*:-webkit-full-screen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\n*:-moz-full-screen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\n*:-ms-fullscreen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\n*:fullscreen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\nbody::-ms-backdrop { /* Prevent IE 11 from hiding the `body` element's background. */\n\tbackground: none;\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n*:focus {\n\toutline: thin dotted;\n}\n*:disabled {\n\tcursor: not-allowed !important;\n}\nbody {\n\tcolor: #eee;\n\tbackground-color: #111;\n\toverflow: auto;\n}\na {\n\tcursor: pointer;\n\tcolor: #68d;\n\ttext-decoration: none;\n\t-o-transition-duration: 200ms;\n\t   transition-duration: 200ms;\n}\na:hover {\n\tcolor: #8af;\n\ttext-decoration: underline;\n}\na.link-broken {\n\tcolor: #c22;\n}\na.link-broken:hover {\n\tcolor: #e44;\n}\na[disabled], span.link-disabled {\n\tcolor: #aaa;\n\tcursor: not-allowed !important;\n\t/*\n\t\tNOTE: Do not use `pointer-events` here as it disables\n\t\tthe display of a cursor in some browsers.\n\n\t\tpointer-events: none;\n\t*/\n\ttext-decoration: none;\n}\narea {\n\tcursor: pointer;\n}\nbutton {\n\tcursor: pointer;\n\tcolor: #eee;\n\tbackground-color: #35a;\n\tborder: 1px solid #57c;\n\tline-height: normal;\n\tpadding: 0.4em;\n\t-o-transition-duration: 200ms;\n\t   transition-duration: 200ms;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\nbutton:hover {\n\tbackground-color: #57c;\n\tborder-color: #79e;\n}\nbutton:disabled {\n\tbackground-color: #444;\n\tborder: 1px solid #666;\n}\ninput, select, textarea {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tpadding: 0.4em;\n}\nselect {\n\tpadding: 0.34em 0.4em;\n}\ninput[type=\"text\"] {\n\tmin-width: 18em;\n}\ntextarea {\n\tmin-width: 30em;\n\tresize: vertical;\n}\ninput[type=\"checkbox\"], input[type=\"file\"], input[type=\"radio\"], select {\n\tcursor: pointer;\n}\n/* BEGIN: input[type=\"range\"] */\ninput[type=\"range\"] {\n\t-webkit-appearance: none;\n\tmin-height: 1.2em;\n}\ninput[type=\"range\"]:focus {\n\toutline: none;\n}\ninput[type=\"range\"]::-webkit-slider-runnable-track {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: 100%;\n}\ninput[type=\"range\"]::-webkit-slider-thumb {\n\t-webkit-appearance: none;\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 18px;\n\t/*\n\t\tNOTE: Ideally, `margin-top` should be `0` for Edge/Spartan (ca. v17), but\n\t\treal WebKit/Blink-based browsers need it.  Since there's more of them and\n\t\tEdge is co-opting the prefix anyway, we cater to them.  Edge will simply\n\t\thave to look ever so slightly off.\n\t*/\n\tmargin-top: -5px;\n\twidth: 33px;\n}\ninput[type=\"range\"]:focus::-webkit-slider-runnable-track {\n\tbackground: #222;\n}\ninput[type=\"range\"]::-moz-range-track {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: 100%;\n}\ninput[type=\"range\"]::-moz-range-thumb {\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 18px;\n\twidth: 33px;\n}\ninput[type=\"range\"]::-ms-track {\n\tbackground: transparent;\n\tborder-color: transparent;\n\tcolor: transparent;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: calc(100% - 1px);\n}\ninput[type=\"range\"]::-ms-fill-lower {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n}\ninput[type=\"range\"]::-ms-fill-upper {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n}\ninput[type=\"range\"]::-ms-thumb {\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 16px;\n\twidth: 33px;\n}\n/* END: input[type=\"range\"] */\ninput:not(:disabled):focus, select:not(:disabled):focus, textarea:not(:disabled):focus,\ninput:not(:disabled):hover, select:not(:disabled):hover, textarea:not(:disabled):hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\nhr {\n\tdisplay: block;\n\theight: 1px;\n\tborder: none;\n\tborder-top: 1px solid #eee;\n\tmargin: 1em 0;\n\tpadding: 0;\n}\naudio, canvas, progress, video {\n\tmax-width: 100%;\n\tvertical-align: middle;\n}\n\n.error-view {\n\tbackground-color: #511;\n\tborder-left: 0.5em solid #c22;\n\tdisplay: inline-block;\n\tmargin: 0.1em;\n\tmax-width: 100%;\n\tpadding: 0 0.25em;\n\tposition: relative;\n}\n.error-view > .error-toggle {\n\tbackground-color: transparent;\n\tborder: none;\n\tline-height: inherit;\n\tleft: 0;\n\tpadding: 0;\n\tposition: absolute;\n\ttop: 0;\n\twidth: 1.75em;\n}\n.error-view > .error {\n\tdisplay: inline-block;\n\tmargin-left: 0.25em;\n}\n.error-view > .error-toggle + .error {\n\tmargin-left: 1.5em;\n}\n.error-view > .error-source[hidden] {\n\tdisplay: none;\n}\n.error-view > .error-source:not([hidden]) {\n\tbackground-color: rgba(0, 0, 0, 0.2);\n\tdisplay: block;\n\tmargin: 0 0 0.25em;\n\toverflow-x: auto;\n\tpadding: 0.25em;\n}\n\n.highlight, .marked {\n\tcolor: yellow;\n\tfont-weight: bold;\n\tfont-style: italic;\n}\n.nobr {\n\twhite-space: nowrap;\n}\n\n[data-icon]:before,\n[data-icon-before]:before,\n[data-icon-after]:after,\n.error-view > .error-toggle:before,\n.error-view > .error:before,\na.link-external:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n[data-icon]:before {\n\tcontent: attr(data-icon);\n}\n[data-icon-before]:before {\n\tcontent: attr(data-icon-before) \"\\00a0\";\n}\n[data-icon-after]:after {\n\tcontent: \"\\00a0\" attr(data-icon-after);\n}\n.error-view > .error-toggle:before {\n\tcontent: \"\\e81a\";\n}\n.error-view > .error-toggle.enabled:before {\n\tcontent: \"\\e818\";\n}\n.error-view > .error:before {\n\tcontent: \"\\e80d\\00a0\\00a0\";\n}\na.link-external:after {\n\tcontent: \"\\00a0\\e80e\";\n}\n</style>\n<style id=\"style-core-display\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-display.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\n#story {\n\tz-index: 10;\n\tmargin: 2.5em;\n}\n@media screen and (max-width: 1136px) {\n\t#story {\n\t\tmargin-right: 1.5em;\n\t}\n}\n#passages {\n\tmax-width: 54em;\n\tmargin: 0 auto;\n}\n</style>\n<style id=\"style-core-passage\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-passage.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault appearance styles.\n*/\n.passage {\n\tline-height: 1.75;\n\ttext-align: left;\n\t-o-transition: opacity 400ms ease-in;\n\ttransition: opacity 400ms ease-in;\n}\n.passage-in {\n\topacity: 0;\n}\n.passage ul, .passage ol {\n\tmargin-left: 0.5em;\n\tpadding-left: 1.5em;\n}\n.passage table {\n\tmargin: 1em 0;\n\tborder-collapse: collapse;\n\tfont-size: 100%;\n}\n.passage tr, .passage th, .passage td, .passage caption {\n\tpadding: 3px;\n}\n</style>\n<style id=\"style-core-macro\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-macro.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault appearance styles.\n*/\n.macro-linkappend-insert,\n.macro-linkprepend-insert,\n.macro-linkreplace-insert,\n.macro-append-insert,\n.macro-prepend-insert,\n.macro-replace-insert,\n.macro-repeat-insert,\n.macro-timed-insert {\n\t-o-transition: opacity 400ms ease-in;\n\ttransition: opacity 400ms ease-in;\n}\n.macro-linkappend-in,\n.macro-linkprepend-in,\n.macro-linkreplace-in,\n.macro-append-in,\n.macro-prepend-in,\n.macro-replace-in,\n.macro-repeat-in,\n.macro-timed-in {\n\topacity: 0;\n}\n</style>\n<style id=\"style-ui-dialog\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-dialog.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tPatches to the core styles.\n*/\nhtml[data-dialog] body {\n\toverflow: hidden;\n}\n\n\n/*\n\tDefault structural styles.\n*/\n#ui-overlay.open {\n\tvisibility: visible;\n\t-o-transition: opacity 200ms ease-in;\n\ttransition: opacity 200ms ease-in;\n}\n#ui-overlay:not(.open) {\n\t-o-transition: visibility 200ms step-end, opacity 200ms ease-in;\n\ttransition: visibility 200ms step-end, opacity 200ms ease-in;\n}\n#ui-overlay {\n\tvisibility: hidden;\n\topacity: 0;\n\tz-index: 100000;\n\tposition: fixed;\n\t/*\n\ttop: -50vh;\n\tleft: -50vw;\n\theight: 200vh;\n\twidth: 200vw;\n\t*/\n\ttop: -50%;\n\tleft: -50%;\n\theight: 200%;\n\twidth: 200%;\n}\n#ui-dialog.open {\n\tdisplay: block;\n\t-o-transition: opacity 200ms ease-in;\n\ttransition: opacity 200ms ease-in;\n}\n/*\n\tWe do not animate `#ui-dialog:not(.open)` for various reasons.  Chief among\n\tthem, however, is so that the dialog isn't in the middle of its animation\n\twhen other page updates happen.\n\n\te.g. The restoration of `overflow` on `body` would cause the still animating\n\t     dialog to jump around a little if a scrollbar were to pop in.\n\n\t     Any dialog action which performs a task which has its own animations\n\t     (e.g. passage display) or causes the page to reload in addition to\n\t     closing the dialog could cause display shenanigans.\n*/\n#ui-dialog {\n\tdisplay: none;\n\topacity: 0;\n\tz-index: 100100;\n\tposition: fixed;\n\ttop: 50px;\n\tmargin: 0;\n\tpadding: 0;\n}\n#ui-dialog > * {\n\tbox-sizing: border-box;\n}\n#ui-dialog-titlebar {\n\tposition: relative;\n}\n#ui-dialog-close {\n\tdisplay: block;\n\tposition: absolute;\n\tright: 0;\n\ttop: 0;\n\twhite-space: nowrap;\n}\n#ui-dialog-body {\n\toverflow: auto;\n\tmin-width: 280px;\n\theight: 92%; /* fallback for browsers without support for calc() */\n\theight: calc(100% - 2.1em); /* parent - title(2.1em) */\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n#ui-overlay {\n\tbackground-color: #000;\n}\n#ui-overlay.open {\n\topacity: 0.8;\n}\n#ui-dialog {\n\tmax-width: 66em;\n}\n#ui-dialog.open {\n\topacity: 1;\n}\n#ui-dialog-titlebar {\n\tbackground-color: #444;\n\tmin-height: 24px;\n}\n#ui-dialog-title {\n\tmargin: 0;\n\tpadding: 0.2em 3.5em 0.2em 0.5em;\n\tfont-size: 1.5em;\n\ttext-align: center;\n\ttext-transform: uppercase;\n}\n#ui-dialog-close {\n\tcursor: pointer;\n\tfont-size: 120%;\n\tmargin: 0;\n\tpadding: 0;\n\twidth: 3.6em;\n\theight: 92%;\n\tbackground-color: transparent;\n\tborder: 1px solid transparent;\n\t-o-transition-duration: 200ms;\n\t   transition-duration: 200ms;\n}\n#ui-dialog-close:hover {\n\tbackground-color: #b44;\n\tborder-color: #d66;\n}\n#ui-dialog-body {\n\tbackground-color: #111;\n\tborder: 1px solid #444;\n\ttext-align: left;\n\tline-height: 1.5;\n\tpadding: 1em;\n}\n#ui-dialog-body > *:first-child {\n\tmargin-top: 0;\n}\n#ui-dialog-body hr {\n\tbackground-color: #444;\n}\n\n/* Default dialog button bar styling. */\n#ui-dialog-body ul.buttons {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n#ui-dialog-body ul.buttons li {\n\tdisplay: inline-block;\n\tmargin: 0;\n\tpadding: 0.4em 0.4em 0 0;\n}\n#ui-dialog-body ul.buttons > li + li > button {\n\tmargin-left: 1em;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-dialog-close {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-dialog-close {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n</style>\n<style id=\"style-ui\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\n/* Settings dialog styling. */\n#ui-dialog-body.settings [id|=\"setting-body\"] > div:first-child {\n\tdisplay: table;\n\twidth: 100%;\n}\n#ui-dialog-body.settings [id|=\"setting-label\"] {\n\tdisplay: table-cell;\n\tpadding: 0.4em 2em 0.4em 0;\n}\n#ui-dialog-body.settings [id|=\"setting-label\"] + div {\n\tdisplay: table-cell;\n\tmin-width: 8em;\n\ttext-align: right;\n\tvertical-align: middle;\n\twhite-space: nowrap;\n}\n\n\n/*\n\tBuilt-in dialog appearance styles.\n*/\n/* List-based dialog styling (primarily for the Jumpto & Share dialogs). */\n#ui-dialog-body.list {\n\tpadding: 0;\n}\n#ui-dialog-body.list ul {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n\tborder: 1px solid transparent;\n}\n#ui-dialog-body.list li {\n\tmargin: 0;\n}\n#ui-dialog-body.list li:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.list li a {\n\tdisplay: block;\n\tpadding: 0.25em 0.75em;\n\tborder: 1px solid transparent;\n\tcolor: #eee;\n\ttext-decoration: none;\n}\n#ui-dialog-body.list li a:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n\n/* Saves dialog styling. */\n#ui-dialog-body.saves {\n\tpadding: 0 0 1px; /* Webkit/Blink need 1px bottom padding or they'll trigger the scroll bar */\n}\n#ui-dialog-body.saves > *:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.saves table {\n\tborder-spacing: 0;\n\twidth: 100%;\n}\n#ui-dialog-body.saves tr:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.saves td {\n\tpadding: 0.33em 0.33em;\n}\n#ui-dialog-body.saves td:first-child {\n\tmin-width: 1.5em;\n\ttext-align: center;\n}\n#ui-dialog-body.saves td:nth-child(3) {\n\tline-height: 1.2;\n}\n#ui-dialog-body.saves td:last-child {\n\ttext-align: right;\n}\n#ui-dialog-body.saves .empty {\n\tcolor: #999;\n\tspeak: none;\n\ttext-align: center;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n#ui-dialog-body.saves .datestamp {\n\tfont-size: 75%;\n\tmargin-left: 1em;\n}\n#ui-dialog-body.saves ul.buttons li {\n\tpadding: 0.4em;\n}\n#ui-dialog-body.saves ul.buttons > li + li > button {\n\tmargin-left: 0.2em;\n}\n#ui-dialog-body.saves ul.buttons li:last-child {\n\t/*\n\t\tUsing `position:absolute;right:0;` here can produce poor results,\n\t\tso we use `float:right` instead.\n\t*/\n\tfloat: right;\n}\n\n/* Settings dialog styling. */\n#ui-dialog-body.settings div[id|=\"header-body\"] {\n\tmargin: 1em 0;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"]:first-child {\n\tmargin-top: 0;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"]:not(:first-child) {\n\tborder-top: 1px solid #444;\n\tpadding-top: 1em;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"] > * {\n\tmargin: 0;\n}\n#ui-dialog-body.settings h2[id|=\"header-heading\"] {\n\tfont-size: 1.375em;\n}\n#ui-dialog-body.settings p[id|=\"header-desc\"],\n#ui-dialog-body.settings p[id|=\"setting-desc\"] {\n\tfont-size: 87.5%;\n\tmargin: 0 0 0 0.5em;\n}\n#ui-dialog-body.settings div[id|=\"setting-body\"] + div[id|=\"setting-body\"] {\n\tmargin: 1em 0;\n}\n#ui-dialog-body.settings [id|=\"setting-control\"] {\n\twhite-space: nowrap;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"] {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tpadding: 0.4em;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"]:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled {\n\tbackground-color: #282;\n\tborder-color: #4a4;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:hover {\n\tbackground-color: #4a4;\n\tborder-color: #6c6;\n}\n#ui-dialog-body.settings input[type=\"range\"][id|=\"setting-control\"] {\n\tmax-width: 35vw;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-dialog-body.list a,\n#ui-dialog-body.settings span[id|=\"setting-input\"] {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-dialog-body.saves button[id=\"saves-export\"]:before,\n#ui-dialog-body.saves button[id=\"saves-import\"]:before,\n#ui-dialog-body.saves button[id=\"saves-clear\"]:before,\n#ui-dialog-body.settings button[id|=\"setting-control\"]:after,\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#ui-dialog-body.saves button[id=\"saves-export\"]:before {\n\tcontent: \"\\e829\\00a0\";\n}\n#ui-dialog-body.saves button[id=\"saves-import\"]:before {\n\tcontent: \"\\e82a\\00a0\";\n}\n#ui-dialog-body.saves button[id=\"saves-clear\"]:before {\n\tcontent: \"\\e827\\00a0\";\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"]:after {\n\tcontent: \"\\00a0\\00a0\\e830\";\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:after {\n\tcontent: \"\\00a0\\00a0\\e831\";\n}\n</style>\n<style id=\"style-ui-bar\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-bar.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tPatches to the core styles.\n*/\n#story {\n\tmargin-left: 20em;\n\t-o-transition: margin-left 200ms ease-in;\n\ttransition: margin-left 200ms ease-in;\n}\n#ui-bar.stowed ~ #story {\n\tmargin-left: 4.5em;\n}\n@media screen and (max-width: 1136px) {\n\t#story {\n\t\tmargin-left: 19em;\n\t}\n\t#ui-bar.stowed ~ #story {\n\t\tmargin-left: 3.5em;\n\t}\n}\n/*\n\tAt very narrow viewport widths, set `#story{margin-left}` equal to the value\n\tof `#ui-bar.stowed~#story{margin-left}`, so that `#ui-bar` will side over top\n\tof `#story` when unstowed, rather than shoving it over.\n*/\n@media screen and (max-width: 768px) {\n\t#story {\n\t\tmargin-left: 3.5em;\n\t}\n}\n\n\n/*\n\tDefault structural styles.\n*/\n#ui-bar {\n\tposition: fixed;\n\tz-index: 50;\n\ttop: 0;\n\tleft: 0;\n\twidth: 17.5em;\n\theight: 100%;\n\tmargin: 0;\n\tpadding: 0;\n\t-o-transition: left 200ms ease-in;\n\ttransition: left 200ms ease-in;\n}\n#ui-bar.stowed {\n\tleft: -15.5em;\n}\n#ui-bar-tray {\n\tposition: absolute;\n\ttop: 0.2em;\n\tleft: 0;\n\tright: 0;\n}\n#ui-bar-body {\n\theight: 90%; /* fallback for browsers without support for calc() */\n\theight: calc(100% - 2.5em);\n\tmargin: 2.5em 0;\n\tpadding: 0 1.5em;\n}\n#ui-bar.stowed #ui-bar-history,\n#ui-bar.stowed #ui-bar-body {\n\tvisibility: hidden;\n\t-o-transition: visibility 200ms step-end;\n\ttransition: visibility 200ms step-end;\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n#ui-bar {\n\tbackground-color: #222;\n\tborder-right: 1px solid #444;\n\ttext-align: center;\n}\n#ui-bar a {\n\ttext-decoration: none;\n}\n#ui-bar hr {\n\tborder-color: #444;\n}\n#ui-bar-toggle,\n#ui-bar-history [id|=\"history\"] {\n\tfont-size: 1.2em;\n\tline-height: inherit;\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n}\n#ui-bar-toggle {\n\tdisplay: block;\n\tposition: absolute;\n\ttop: 0;\n\tright: 0;\n\tborder-right: none;\n\tpadding: 0.3em 0.45em 0.25em;\n}\n#ui-bar.stowed #ui-bar-toggle {\n\tpadding: 0.3em 0.35em 0.25em 0.55em;\n}\n#ui-bar-toggle:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n#ui-bar-history {\n\tmargin: 0 auto;\n}\n#ui-bar-history [id|=\"history\"] {\n\tpadding: 0.2em 0.45em 0.35em;\n}\n#ui-bar-history #history-jumpto {\n\tpadding: 0.2em 0.665em 0.35em;\n}\n#ui-bar-history [id|=\"history\"]:not(:first-child) {\n\tmargin-left: 1.2em;\n}\n#ui-bar-history [id|=\"history\"]:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n#ui-bar-history [id|=\"history\"]:disabled {\n\tcolor: #444;\n\tbackground-color: transparent;\n\tborder-color: #444;\n}\n#ui-bar-body {\n\tline-height: 1.5;\n\toverflow: auto;\n}\n#ui-bar-body > :not(:first-child) {\n\tmargin-top: 2em;\n}\n#story-title {\n\tmargin: 0;\n\tfont-size: 162.5%;\n}\n#story-author {\n\tmargin-top: 2em;\n\tfont-weight: bold;\n}\n#menu ul {\n\tmargin: 1em 0 0;\n\tpadding: 0;\n\tlist-style: none;\n\tborder: 1px solid #444;\n}\n#menu ul:empty {\n\tdisplay: none;\n}\n#menu li {\n\tmargin: 0;\n}\n#menu li:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#menu li a {\n\tdisplay: block;\n\tpadding: 0.25em 0.75em;\n\tborder: 1px solid transparent;\n\tcolor: #eee;\n\ttext-transform: uppercase;\n}\n#menu li a:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-bar-history [id|=\"history\"],\n#ui-bar-toggle,\n#menu a {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-bar-toggle:before,\n#ui-bar-history [id|=\"history\"],\n#menu-core li[id|=\"menu-item\"] a:before {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#ui-bar-toggle:before {\n\tcontent: \"\\e81d\";\n}\n#ui-bar.stowed #ui-bar-toggle:before {\n\tcontent: \"\\e81e\";\n}\n#menu-item-saves a:before {\n\tcontent: \"\\e82b\\00a0\";\n}\n#menu-item-settings a:before {\n\tcontent: \"\\e82d\\00a0\";\n}\n#menu-item-restart a:before {\n\tcontent: \"\\e82c\\00a0\";\n}\n#menu-item-share a:before {\n\tcontent: \"\\e82f\\00a0\";\n}\n</style>\n<style id=\"style-ui-debug\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-debug.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault debug bar styles.\n*/\n#debug-bar {\n\tbackground-color: #222;\n\tborder-left: 1px solid #444;\n\tborder-top: 1px solid #444;\n\tbottom: 0;\n\tmargin: 0;\n\tmax-height: 75%;\n\t/* max-width: 28em;\n\tmin-width: 22em; */\n\tpadding: 0.5em;\n\tposition: fixed;\n\tright: 0;\n\tz-index: 99900;\n}\n#debug-bar > div:not([id]) + div {\n\tmargin-top: 0.5em;\n}\n#debug-bar > div > label {\n\tmargin-right: 0.5em;\n}\n#debug-bar > div > input[type=\"text\"] {\n\tmin-width: 0;\n\twidth: 8em;\n}\n#debug-bar > div > select {\n\twidth: 15em;\n}\n\n#debug-bar-toggle {\n\tcolor: #eee;\n\tbackground-color: #222;\n\tborder: 1px solid #444;\n\theight: 101%; /* fallback for browsers without support for calc() */\n\theight: calc(100% + 1px);\n\tleft: -2em; /* fallback for browsers without support for calc() */\n\tleft: calc(-2em - 1px);\n\tposition: absolute;\n\ttop: -1px;\n\twidth: 2em;\n}\n#debug-bar-toggle:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n\n#debug-bar-hint {\n\tbottom: 0.175em;\n\tfont-size: 4.5em;\n\topacity: 0.33;\n\tpointer-events: none;\n\tposition: fixed;\n\tright: 0.6em;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n\twhite-space: nowrap;\n}\n\n#debug-bar-watch {\n\tbackground-color: #222;\n\tborder-left: 1px solid #444;\n\tborder-top: 1px solid #444;\n\tbottom: 102%; /* fallback for browsers without support for calc() */\n\tbottom: calc(100% + 1px);\n\tfont-size: 0.9em;\n\tleft: -1px;\n\tmax-height: 650%; /* fallback for browsers without support for vh units */\n\tmax-height: 65vh;\n\tposition: absolute;\n\toverflow-x: hidden;\n\toverflow-y: scroll;\n\tright: 0;\n\tz-index: 99800;\n}\n#debug-bar-watch[hidden] {\n\tdisplay: none;\n}\n#debug-bar-watch div {\n\tcolor: #999;\n\tfont-style: italic;\n\tmargin: 1em auto;\n\ttext-align: center;\n}\n#debug-bar-watch table {\n\twidth: 100%;\n}\n#debug-bar-watch tr:nth-child(2n) {\n\tbackground-color: rgba(127, 127, 127, 0.15);\n}\n#debug-bar-watch td {\n\tpadding: 0.2em 0;\n}\n#debug-bar-watch td:first-child + td {\n\tpadding: 0.2em 0.3em 0.2em 0.1em;\n}\n#debug-bar-watch .watch-delete {\n\tbackground-color: transparent;\n\tborder: none;\n\tcolor: #c00;\n}\n#debug-bar-watch-all,\n#debug-bar-watch-none {\n\tmargin-left: 0.5em;\n}\n#debug-bar-watch-toggle,\n#debug-bar-views-toggle {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tmargin-right: 1em;\n\tpadding: 0.4em;\n}\n#debug-bar-watch-toggle:hover,\n#debug-bar-views-toggle:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle,\nhtml[data-debug-view] #debug-bar-views-toggle {\n\tbackground-color: #282;\n\tborder-color: #4a4;\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle:hover,\nhtml[data-debug-view] #debug-bar-views-toggle:hover {\n\tbackground-color: #4a4;\n\tborder-color: #6c6;\n}\n\n#debug-bar-toggle:before,\n#debug-bar-hint:after,\n#debug-bar-watch .watch-delete:before,\n#debug-bar-watch-add:before,\n#debug-bar-watch-all:before,\n#debug-bar-watch-none:before,\n#debug-bar-watch-toggle:after,\n#debug-bar-views-toggle:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#debug-bar-toggle:before {\n\tcontent: \"\\e838\";\n}\n#debug-bar-hint:after {\n\tcontent: \"\\e838\\202f\\e822\";\n}\n#debug-bar-watch .watch-delete:before {\n\tcontent: \"\\e804\";\n}\n#debug-bar-watch-add:before {\n\tcontent: \"\\e805\";\n}\n#debug-bar-watch-all:before {\n\tcontent: \"\\e83a\";\n}\n#debug-bar-watch-none:before {\n\tcontent: \"\\e827\";\n}\n#debug-bar-watch-toggle:after,\n#debug-bar-views-toggle:after {\n\tcontent: \"\\00a0\\00a0\\e830\";\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle:after,\nhtml[data-debug-view] #debug-bar-views-toggle:after {\n\tcontent: \"\\00a0\\00a0\\e831\";\n}\n\n\n/*\n\tDefault debug view styles.\n*/\nhtml[data-debug-view] .debug {\n\tpadding: 0.25em;\n\tbackground-color: #234; /* #541, #151 */\n}\nhtml[data-debug-view] .debug[title] {\n\tcursor: help;\n}\nhtml[data-debug-view] .debug.block {\n\tdisplay: inline-block;\n\tvertical-align: middle;\n}\nhtml[data-debug-view] .debug.invalid {\n\ttext-decoration: line-through;\n}\nhtml[data-debug-view] .debug.hidden,\nhtml[data-debug-view] .debug.hidden .debug {\n\tbackground-color: #555;\n}\nhtml:not([data-debug-view]) .debug.hidden {\n\tdisplay: none;\n}\n\nhtml[data-debug-view] .debug[data-name][data-type]:before,\nhtml[data-debug-view] .debug[data-name][data-type].nonvoid:after {\n\tbackground-color: rgba(0,0,0,0.25);\n\tfont-family: monospace, monospace;\n\twhite-space: pre;\n}\nhtml[data-debug-view] .debug[data-name][data-type]:before {\n\tcontent: attr(data-name);\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"macro\"]:before {\n\tcontent: \"<<\" attr(data-name) \">>\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"macro\"].nonvoid:after {\n\tcontent: \"<</\" attr(data-name) \">>\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"html\"]:before {\n\tcontent: \"<\" attr(data-name) \">\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"html\"].nonvoid:after {\n\tcontent: \"</\" attr(data-name) \">\";\n}\nhtml[data-debug-view] .debug[data-name][data-type]:not(:empty):before {\n\tmargin-right: 0.25em;\n}\nhtml[data-debug-view] .debug[data-name][data-type].nonvoid:not(:empty):after {\n\tmargin-left: 0.25em;\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"special\"],\nhtml[data-debug-view] .debug[data-name][data-type|=\"special\"]:before {\n\tdisplay: block;\n}\n</style>\n</head>\n<body>\n\t<div id=\"init-screen\">\n\t\t<div id=\"init-no-js\"><noscript>JavaScript is required. Please enable it to continue.</noscript></div>\n\t\t<div id=\"init-lacking\">Your browser lacks required capabilities. Please upgrade it or switch to another to continue.</div>\n\t\t<div id=\"init-loading\"><div>Loading&hellip;</div></div>\n\t</div>\n\t{{STORY_DATA}}\n\t<script id=\"script-sugarcube\" type=\"text/javascript\">\n\t/*! SugarCube JS */\n\tif(document.documentElement.getAttribute(\"data-init\")===\"loading\"){window.TWINE1=false;\nwindow.DEBUG=true;\n(function (window, document, jQuery, undefined) {\n\"use strict\";\n\n/***********************************************************************************************************************\n\n\tlib/alert.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tTODO: This regular expression should be elsewhere.\n\n\tError prologs by engine/browser: (ca. 2018)\n\t\tChrome, Opera, & Vivaldi → `Uncaught \\w*Error: …`\n\t\tEdge & IE                → `…`\n\t\tFirefox                  → `Error: …`\n\t\tOpera (Presto)           → `Uncaught exception: \\w*(?:Error|Exception): …`\n\t\tSafari (ca. v5.1)        → `\\w*(?:Error|_ERR): …`\n*/\nvar errorPrologRegExp = /^(?:(?:uncaught\\s+(?:exception:\\s+)?)?\\w*(?:error|exception|_err):\\s+)+/i; // eslint-disable-line no-unused-vars, no-var\n\nvar Alert = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tError Functions.\n\t*******************************************************************************************************************/\n\tfunction _alertMesg(type, where, what, error) {\n\t\tconst isFatal = type === 'fatal';\n\t\tlet mesg = `Apologies! ${isFatal ? 'A fatal' : 'An'} error has occurred.`;\n\n\t\tif (isFatal) {\n\t\t\tmesg += ' Aborting.';\n\t\t}\n\t\telse {\n\t\t\tmesg += ' You may be able to continue, but some parts may not work properly.';\n\t\t}\n\n\t\tif (where != null || what != null) { // lazy equality for null\n\t\t\tmesg += '\\n\\nError';\n\n\t\t\tif (where != null) { // lazy equality for null\n\t\t\t\tmesg += ` [${where}]`;\n\t\t\t}\n\n\t\t\tif (what != null) { // lazy equality for null\n\t\t\t\tmesg += `: ${what.replace(errorPrologRegExp, '')}.`;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tmesg += ': unknown error.';\n\t\t\t}\n\t\t}\n\n\t\tif (typeof error === 'object' && error !== null && error.stack) {\n\t\t\tmesg += `\\n\\nStack Trace:\\n${error.stack}`;\n\t\t}\n\n\t\twindow.alert(mesg); // eslint-disable-line no-alert\n\t}\n\n\tfunction alertError(where, what, error) {\n\t\t_alertMesg(null, where, what, error);\n\t}\n\n\tfunction alertFatal(where, what, error) {\n\t\t_alertMesg('fatal', where, what, error);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tError Event.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSet up a global error handler for uncaught exceptions.\n\t*/\n\t(origOnError => {\n\t\twindow.onerror = function (what, source, lineNum, colNum, error) {\n\t\t\t// Uncaught exceptions during play may be recoverable/ignorable.\n\t\t\tif (document.readyState === 'complete') {\n\t\t\t\talertError(null, what, error);\n\t\t\t}\n\n\t\t\t// Uncaught exceptions during startup should be fatal.\n\t\t\telse {\n\t\t\t\talertFatal(null, what, error);\n\t\t\t\twindow.onerror = origOnError;\n\n\t\t\t\tif (typeof window.onerror === 'function') {\n\t\t\t\t\twindow.onerror.apply(this, arguments);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t})(window.onerror);\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\terror : { value : alertError },\n\t\tfatal : { value : alertFatal }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/patterns.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tTODO: Move all markup patterns into here.\n*/\n\nvar Patterns = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tPatterns.\n\t*******************************************************************************************************************/\n\t/*\n\t\tWhitespace patterns.\n\n\t\tSpace class (equivalent to `\\s`):\n\t\t\t[\\u0020\\f\\n\\r\\t\\v\\u00a0\\u1680\\u180e\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000\\ufeff]\n\t\tSpace class, sans line terminators:\n\t\t\t[\\u0020\\f\\t\\v\\u00a0\\u1680\\u180e\\u2000-\\u200a\\u202f\\u205f\\u3000\\ufeff]\n\t\tLine Terminator class:\n\t\t\t[\\n\\r\\u2028\\u2029]\n\t*/\n\tconst space = (() => {\n\t\t/*\n\t\t\tSome browsers still supported by SugarCube have faulty space classes (`\\s`).\n\t\t\tWe check for that lossage here and, if necessary, build our own class from\n\t\t\tthe component pieces.\n\t\t*/\n\t\tconst wsMap = new Map([\n\t\t\t['\\u0020', '\\\\u0020'],\n\t\t\t['\\f', '\\\\f'],\n\t\t\t['\\n', '\\\\n'],\n\t\t\t['\\r', '\\\\r'],\n\t\t\t['\\t', '\\\\t'],\n\t\t\t['\\v', '\\\\v'],\n\t\t\t['\\u00a0', '\\\\u00a0'],\n\t\t\t['\\u1680', '\\\\u1680'],\n\t\t\t['\\u180e', '\\\\u180e'],\n\t\t\t['\\u2000', '\\\\u2000'],\n\t\t\t['\\u2001', '\\\\u2001'],\n\t\t\t['\\u2002', '\\\\u2002'],\n\t\t\t['\\u2003', '\\\\u2003'],\n\t\t\t['\\u2004', '\\\\u2004'],\n\t\t\t['\\u2005', '\\\\u2005'],\n\t\t\t['\\u2006', '\\\\u2006'],\n\t\t\t['\\u2007', '\\\\u2007'],\n\t\t\t['\\u2008', '\\\\u2008'],\n\t\t\t['\\u2009', '\\\\u2009'],\n\t\t\t['\\u200a', '\\\\u200a'],\n\t\t\t['\\u2028', '\\\\u2028'],\n\t\t\t['\\u2029', '\\\\u2029'],\n\t\t\t['\\u202f', '\\\\u202f'],\n\t\t\t['\\u205f', '\\\\u205f'],\n\t\t\t['\\u3000', '\\\\u3000'],\n\t\t\t['\\ufeff', '\\\\ufeff']\n\t\t]);\n\t\tconst wsRe = /^\\s$/;\n\t\tlet missing = '';\n\n\t\twsMap.forEach((pat, char) => {\n\t\t\tif (!wsRe.test(char)) {\n\t\t\t\tmissing += pat;\n\t\t\t}\n\t\t});\n\n\t\treturn missing ? `[\\\\s${missing}]` : '\\\\s';\n\t})();\n\tconst spaceNoTerminator = '[\\\\u0020\\\\f\\\\t\\\\v\\\\u00a0\\\\u1680\\\\u180e\\\\u2000-\\\\u200a\\\\u202f\\\\u205f\\\\u3000\\\\ufeff]';\n\tconst lineTerminator    = '[\\\\n\\\\r\\\\u2028\\\\u2029]';\n\tconst notSpace          = space === '\\\\s' ? '\\\\S' : space.replace(/^\\[/, '[^');\n\n\t/*\n\t\tCharacter patterns.\n\t*/\n\tconst anyChar = `(?:.|${lineTerminator})`;\n\n\t/*\n\t\tLetter patterns.\n\n\t\tFIXME:\n\t\t\t1. The existing set, which is a TiddlyWiki holdover, should probably\n\t\t\t   encompass a significantly greater range of BMP code points.\n\t\t\t2. Should we include the surrogate pair code units (\\uD800-\\uDBFF &\n\t\t\t   \\uDC00-\\uDFFF) to handle non-BMP code points?  Further, should we\n\t\t\t   simply be checking for the code units themselves or checking for\n\t\t\t   properly mated pairs?\n\t*/\n\tconst anyLetter       = '[0-9A-Z_a-z\\\\-\\\\u00c0-\\\\u00d6\\\\u00d8-\\\\u00f6\\\\u00f8-\\\\u00ff\\\\u0150\\\\u0170\\\\u0151\\\\u0171]';\n\tconst anyLetterStrict = anyLetter.replace('\\\\-', ''); // anyLetter sans hyphen\n\n\t/*\n\t\tIdentifier patterns.\n\n\t\tNOTE: Since JavaScript's RegExp syntax does not support Unicode character\n\t\tclasses, the correct regular expression to match a valid identifier name,\n\t\twithin the scope of our needs, would be on the order of approximately 5–6\n\t\tor 11–16 KiB, depending on how the pattern was built.  That being the case,\n\t\tfor the moment we restrict valid TwineScript identifiers to US-ASCII.\n\n\t\tFIXME: Fix this to, at least, approximate the correct range.\n\t*/\n\tconst identifierFirstChar = '[$A-Z_a-z]';\n\tconst identifierNextChar  = '[$0-9A-Z_a-z]';\n\tconst identifier          = `${identifierFirstChar}${identifierNextChar}*`;\n\n\t// Variable patterns.\n\tconst variableSigil = '[$_]';\n\tconst variable      = variableSigil + identifier;\n\n\t// Macro name pattern.\n\tconst macroName = '[A-Za-z][\\\\w-]*|[=-]';\n\n\t// Template name pattern.\n\tconst templateName = '[A-Za-z][\\\\w-]*';\n\n\t// CSS ID or class sigil pattern.\n\tconst cssIdOrClassSigil = '[#.]';\n\n\t// CSS image transclusion template pattern.\n\t//\n\t// NOTE: The alignment syntax isn't supported, but removing it might break uses\n\t// of the template in the wild, so we leave it alone for now.\n\tconst cssImage = '\\\\[[<>]?[Ii][Mm][Gg]\\\\[(?:\\\\s|\\\\S)*?\\\\]\\\\]+';\n\n\t// Inline CSS pattern.\n\tconst inlineCss = (() => {\n\t\t/* legacy */\n\t\tconst twStyle   = `(${anyLetter}+)\\\\(([^\\\\)\\\\|\\\\n]+)\\\\):`;\n\t\t/* /legacy */\n\t\tconst cssStyle  = `${spaceNoTerminator}*(${anyLetter}+)${spaceNoTerminator}*:([^;\\\\|\\\\n]+);`;\n\t\tconst idOrClass = `${spaceNoTerminator}*((?:${cssIdOrClassSigil}${anyLetter}+${spaceNoTerminator}*)+);`;\n\n\t\t// [1,2] = style(value):\n\t\t// [3,4] = style:value;\n\t\t// [5]   = #id.className;\n\t\treturn `${twStyle}|${cssStyle}|${idOrClass}`;\n\t})();\n\n\t// URL pattern.\n\tconst url = '(?:file|https?|mailto|ftp|javascript|irc|news|data):[^\\\\s\\'\"]+';\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze({\n\t\tspace,\n\t\tspaceNoTerminator,\n\t\tlineTerminator,\n\t\tnotSpace,\n\t\tanyChar,\n\t\tanyLetter,\n\t\tanyLetterStrict,\n\t\tidentifierFirstChar,\n\t\tidentifierNextChar,\n\t\tidentifier,\n\t\tvariableSigil,\n\t\tvariable,\n\t\tmacroName,\n\t\ttemplateName,\n\t\tcssIdOrClassSigil,\n\t\tcssImage,\n\t\tinlineCss,\n\t\turl\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/extensions.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns */\n\n/*\n\tJavaScript Polyfills.\n\n\tNOTE: The ES5 and ES6 polyfills come from the vendored `es5-shim.js` and `es6-shim.js` libraries.\n*/\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tTrims whitespace from either the start or end of the given string.\n\t*/\n\tconst _trimString = (() => {\n\t\t// Whitespace regular expressions.\n\t\tconst startWSRe = new RegExp(`^${Patterns.space}${Patterns.space}*`);\n\t\tconst endWSRe   = new RegExp(`${Patterns.space}${Patterns.space}*$`);\n\n\t\tfunction trimString(str, where) {\n\t\t\tconst val = String(str);\n\n\t\t\tif (!val) {\n\t\t\t\treturn val;\n\t\t\t}\n\n\t\t\tswitch (where) {\n\t\t\tcase 'start':\n\t\t\t\treturn startWSRe.test(val) ? val.replace(startWSRe, '') : val;\n\n\t\t\tcase 'end':\n\t\t\t\treturn endWSRe.test(val) ? val.replace(endWSRe, '') : val;\n\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`_trimString called with incorrect where parameter value: \"${where}\"`);\n\t\t\t}\n\t\t}\n\n\t\treturn trimString;\n\t})();\n\n\t/*\n\t\tGenerates a pad string based upon the given string and length.\n\t*/\n\tfunction _createPadString(length, padding) {\n\t\tconst targetLength = Number.parseInt(length, 10) || 0;\n\n\t\tif (targetLength < 1) {\n\t\t\treturn '';\n\t\t}\n\n\t\tlet padString = typeof padding === 'undefined' ? '' : String(padding);\n\n\t\tif (padString === '') {\n\t\t\tpadString = ' ';\n\t\t}\n\n\t\twhile (padString.length < targetLength) {\n\t\t\tconst curPadLength    = padString.length;\n\t\t\tconst remainingLength = targetLength - curPadLength;\n\n\t\t\tpadString += curPadLength > remainingLength\n\t\t\t\t? padString.slice(0, remainingLength)\n\t\t\t\t: padString;\n\t\t}\n\n\t\tif (padString.length > targetLength) {\n\t\t\tpadString = padString.slice(0, targetLength);\n\t\t}\n\n\t\treturn padString;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPolyfills.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[ES2019] Returns a new array consisting of the source array with all sub-array elements\n\t\tconcatenated into it recursively up to the given depth.\n\t*/\n\tif (!Array.prototype.flat) {\n\t\tObject.defineProperty(Array.prototype, 'flat', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\t\t\tvalue        : (() => {\n\t\t\t\tfunction flat(/* depth */) {\n\t\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\t\tthrow new TypeError('Array.prototype.flat called on null or undefined');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst depth = arguments.length === 0 ? 1 : Number(arguments[0]) || 0;\n\n\t\t\t\t\tif (depth < 1) {\n\t\t\t\t\t\treturn Array.prototype.slice.call(this);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn Array.prototype.reduce.call(\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\t(acc, cur) => {\n\t\t\t\t\t\t\tif (cur instanceof Array) {\n\t\t\t\t\t\t\t\t// acc.push.apply(acc, flat.call(cur, depth - 1));\n\t\t\t\t\t\t\t\tacc.push(...flat.call(cur, depth - 1));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tacc.push(cur);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn acc;\n\t\t\t\t\t\t},\n\t\t\t\t\t\t[]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn flat;\n\t\t\t})()\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a new array consisting of the result of calling the given mapping function\n\t\ton every element in the source array and then concatenating all sub-array elements into it\n\t\trecursively up to a depth of `1`.  Identical to calling `<Array>.map(fn).flat()`.\n\t*/\n\tif (!Array.prototype.flatMap) {\n\t\tObject.defineProperty(Array.prototype, 'flatMap', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(/* callback [, thisArg] */) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Array.prototype.flatMap called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.map.apply(this, arguments).flat();\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2016] Returns whether the given element was found within the array.\n\t*/\n\tif (!Array.prototype.includes) {\n\t\tObject.defineProperty(Array.prototype, 'includes', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Array.prototype.includes called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tif (arguments.length === 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst length = this.length >>> 0;\n\n\t\t\t\tif (length === 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst needle = arguments[0];\n\t\t\t\tlet i = Number(arguments[1]) || 0;\n\n\t\t\t\tif (i < 0) {\n\t\t\t\t\ti = Math.max(0, length + i);\n\t\t\t\t}\n\n\t\t\t\tfor (/* empty */; i < length; ++i) {\n\t\t\t\t\tconst value = this[i];\n\n\t\t\t\t\tif (value === needle || value !== value && needle !== needle) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a new array consisting of the given object's own enumerable property/value\n\t\tpairs as `[key, value]` arrays.\n\t*/\n\tif (!Object.entries) {\n\t\tObject.defineProperty(Object, 'entries', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (typeof obj !== 'object' || obj === null) {\n\t\t\t\t\tthrow new TypeError('Object.entries object parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\treturn Object.keys(obj).map(key => [key, obj[key]]);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a new generic object consisting of the given list's key/value pairs.\n\t*/\n\tif (!Object.fromEntries) {\n\t\tObject.defineProperty(Object, 'fromEntries', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(iter) {\n\t\t\t\treturn Array.from(iter).reduce(\n\t\t\t\t\t(acc, pair) => {\n\t\t\t\t\t\tif (Object(pair) !== pair) {\n\t\t\t\t\t\t\tthrow new TypeError('Object.fromEntries iterable parameter must yield objects');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (pair[0] in acc) {\n\t\t\t\t\t\t\tObject.defineProperty(acc, pair[0], {\n\t\t\t\t\t\t\t\tconfigurable : true,\n\t\t\t\t\t\t\t\tenumerable   : true,\n\t\t\t\t\t\t\t\twritable     : true,\n\t\t\t\t\t\t\t\tvalue        : pair[1]\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tacc[pair[0]] = pair[1]; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{}\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns all own property descriptors of the given object.\n\t*/\n\tif (!Object.getOwnPropertyDescriptors) {\n\t\tObject.defineProperty(Object, 'getOwnPropertyDescriptors', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (obj == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Object.getOwnPropertyDescriptors object parameter is null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst O = Object(obj);\n\n\t\t\t\treturn Reflect.ownKeys(O).reduce(\n\t\t\t\t\t(acc, key) => {\n\t\t\t\t\t\tconst desc = Object.getOwnPropertyDescriptor(O, key);\n\n\t\t\t\t\t\tif (typeof desc !== 'undefined') {\n\t\t\t\t\t\t\tif (key in acc) {\n\t\t\t\t\t\t\t\tObject.defineProperty(acc, key, {\n\t\t\t\t\t\t\t\t\tconfigurable : true,\n\t\t\t\t\t\t\t\t\tenumerable   : true,\n\t\t\t\t\t\t\t\t\twritable     : true,\n\t\t\t\t\t\t\t\t\tvalue        : desc\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tacc[key] = desc; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{}\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a new array consisting of the given object's own enumerable property values.\n\t*/\n\tif (!Object.values) {\n\t\tObject.defineProperty(Object, 'values', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (typeof obj !== 'object' || obj === null) {\n\t\t\t\t\tthrow new TypeError('Object.values object parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\treturn Object.keys(obj).map(key => obj[key]);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a string based on concatenating the given padding, repeated as necessary,\n\t\tto the start of the string so that the given length is reached.\n\n\t\tNOTE: This pads based upon Unicode code units, rather than code points.\n\t*/\n\tif (!String.prototype.padStart) {\n\t\tObject.defineProperty(String.prototype, 'padStart', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(length, padding) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.padStart called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst baseString   = String(this);\n\t\t\t\tconst baseLength   = baseString.length;\n\t\t\t\tconst targetLength = Number.parseInt(length, 10);\n\n\t\t\t\tif (targetLength <= baseLength) {\n\t\t\t\t\treturn baseString;\n\t\t\t\t}\n\n\t\t\t\treturn _createPadString(targetLength - baseLength, padding) + baseString;\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a string based on concatenating the given padding, repeated as necessary,\n\t\tto the end of the string so that the given length is reached.\n\n\t\tNOTE: This pads based upon Unicode code units, rather than code points.\n\t*/\n\tif (!String.prototype.padEnd) {\n\t\tObject.defineProperty(String.prototype, 'padEnd', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(length, padding) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.padEnd called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst baseString   = String(this);\n\t\t\t\tconst baseLength   = baseString.length;\n\t\t\t\tconst targetLength = Number.parseInt(length, 10);\n\n\t\t\t\tif (targetLength <= baseLength) {\n\t\t\t\t\treturn baseString;\n\t\t\t\t}\n\n\t\t\t\treturn baseString + _createPadString(targetLength - baseLength, padding);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a string with all whitespace removed from the start of the string.\n\t*/\n\tif (!String.prototype.trimStart) {\n\t\tObject.defineProperty(String.prototype, 'trimStart', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimStart called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'start');\n\t\t\t}\n\t\t});\n\t}\n\n\tif (!String.prototype.trimLeft) {\n\t\tObject.defineProperty(String.prototype, 'trimLeft', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimLeft called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'start');\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a string with all whitespace removed from the end of the string.\n\t*/\n\tif (!String.prototype.trimEnd) {\n\t\tObject.defineProperty(String.prototype, 'trimEnd', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimEnd called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'end');\n\t\t\t}\n\t\t});\n\t}\n\n\tif (!String.prototype.trimRight) {\n\t\tObject.defineProperty(String.prototype, 'trimRight', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimRight called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'end');\n\t\t\t}\n\t\t});\n\t}\n})();\n\n\n/*\n\tJavaScript Extensions.\n*/\n(() => {\n\t'use strict';\n\n\tconst _nativeMathRandom = Math.random;\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a pseudo-random whole number (integer) within the given bounds.\n\t*/\n\tfunction _random(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('_random called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = arguments[0];\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = arguments[0];\n\t\t\tmax = arguments[1];\n\t\t\tbreak;\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn Math.floor(_nativeMathRandom() * (max - min + 1)) + min;\n\t}\n\n\t/*\n\t\tReturns a randomly selected index within the given length and bounds.\n\t\tBounds may be negative.\n\t*/\n\tfunction _randomIndex(length, boundsArgs) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (boundsArgs.length) {\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = length - 1;\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tmin = 0;\n\t\t\tmax = Math.trunc(boundsArgs[1]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Math.trunc(boundsArgs[1]);\n\t\t\tmax = Math.trunc(boundsArgs[2]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (Number.isNaN(min)) {\n\t\t\tmin = 0;\n\t\t}\n\t\telse if (!Number.isFinite(min) || min >= length) {\n\t\t\tmin = length - 1;\n\t\t}\n\t\telse if (min < 0) {\n\t\t\tmin = length + min;\n\n\t\t\tif (min < 0) {\n\t\t\t\tmin = 0;\n\t\t\t}\n\t\t}\n\n\t\tif (Number.isNaN(max)) {\n\t\t\tmax = 0;\n\t\t}\n\t\telse if (!Number.isFinite(max) || max >= length) {\n\t\t\tmax = length - 1;\n\t\t}\n\t\telse if (max < 0) {\n\t\t\tmax = length + max;\n\n\t\t\tif (max < 0) {\n\t\t\t\tmax = length - 1;\n\t\t\t}\n\t\t}\n\n\t\treturn _random(min, max);\n\t}\n\n\t/*\n\t\tReturns an object (`{ char, start, end }`) containing the Unicode character at\n\t\tposition `pos`, its starting position, and its ending position—surrogate pairs\n\t\tare properly handled.  If `pos` is out-of-bounds, returns an object containing\n\t\tthe empty string and start/end positions of `-1`.\n\n\t\tThis function is necessary because JavaScript strings are sequences of UTF-16\n\t\tcode units, so surrogate pairs are exposed and thus must be handled.  While the\n\t\tES6/2015 standard does improve the situation somewhat, it does not alleviate\n\t\tthe need for this function.\n\n\t\tNOTE: Will throw exceptions on invalid surrogate pairs.\n\n\t\tIDEA: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt\n\t*/\n\tfunction _getCodePointStartAndEnd(str, pos) {\n\t\tconst code = str.charCodeAt(pos);\n\n\t\t// Given position was out-of-bounds.\n\t\tif (Number.isNaN(code)) {\n\t\t\treturn { char : '', start : -1, end : -1 };\n\t\t}\n\n\t\t// Code unit is not a UTF-16 surrogate.\n\t\tif (code < 0xD800 || code > 0xDFFF) {\n\t\t\treturn {\n\t\t\t\tchar  : str.charAt(pos),\n\t\t\t\tstart : pos,\n\t\t\t\tend   : pos\n\t\t\t};\n\t\t}\n\n\t\t// Code unit is a high surrogate (D800–DBFF).\n\t\tif (code >= 0xD800 && code <= 0xDBFF) {\n\t\t\tconst nextPos = pos + 1;\n\n\t\t\t// End of string.\n\t\t\tif (nextPos >= str.length) {\n\t\t\t\tthrow new Error('high surrogate without trailing low surrogate');\n\t\t\t}\n\n\t\t\tconst nextCode = str.charCodeAt(nextPos);\n\n\t\t\t// Next code unit is not a low surrogate (DC00–DFFF).\n\t\t\tif (nextCode < 0xDC00 || nextCode > 0xDFFF) {\n\t\t\t\tthrow new Error('high surrogate without trailing low surrogate');\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tchar  : str.charAt(pos) + str.charAt(nextPos),\n\t\t\t\tstart : pos,\n\t\t\t\tend   : nextPos\n\t\t\t};\n\t\t}\n\n\t\t// Code unit is a low surrogate (DC00–DFFF) in the first position.\n\t\tif (pos === 0) {\n\t\t\tthrow new Error('low surrogate without leading high surrogate');\n\t\t}\n\n\t\tconst prevPos  = pos - 1;\n\t\tconst prevCode = str.charCodeAt(prevPos);\n\n\t\t// Previous code unit is not a high surrogate (D800–DBFF).\n\t\tif (prevCode < 0xD800 || prevCode > 0xDBFF) {\n\t\t\tthrow new Error('low surrogate without leading high surrogate');\n\t\t}\n\n\t\treturn {\n\t\t\tchar  : str.charAt(prevPos) + str.charAt(pos),\n\t\t\tstart : prevPos,\n\t\t\tend   : pos\n\t\t};\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, General.\n\t*******************************************************************************************************************/\n\t/*\n\t\tRandomly selects an element from the given array, or array-like object, and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array, 'random', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(array /* DEPRECATED: [, [min ,] max] */) {\n\t\t\tif (\n\t\t\t\t   typeof array !== 'object'\n\t\t\t\t|| array === null\n\t\t\t\t|| !Object.prototype.hasOwnProperty.call(array, 'length')\n\t\t\t) {\n\t\t\t\tthrow new TypeError('Array.random array parameter must be an array or array-lke object');\n\t\t\t}\n\n\t\t\tconst length = array.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, Array.prototype.slice.call(arguments, 1));\n\n\t\t\treturn array[index];\n\t\t}\n\t});\n\n\t/*\n\t\tConcatenates one or more unique elements to the end of the base array\n\t\tand returns the result as a new array.  Elements which are arrays will\n\t\tbe merged—i.e. their elements will be concatenated, rather than the\n\t\tarray itself.\n\t*/\n\tObject.defineProperty(Array.prototype, 'concatUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.concatUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst result = Array.from(this);\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tconst items   = Array.prototype.reduce.call(arguments, (prev, cur) => prev.concat(cur), []);\n\t\t\tconst addSize = items.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst push    = Array.prototype.push;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = items[i];\n\n\t\t\t\tif (indexOf.call(result, value) === -1) {\n\t\t\t\t\tpush.call(result, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number of times the given element was found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'count', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex ] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.count called on null or undefined');\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst needle  = arguments[0];\n\t\t\tlet pos   = Number(arguments[1]) || 0;\n\t\t\tlet count = 0;\n\n\t\t\twhile ((pos = indexOf.call(this, needle, pos)) !== -1) {\n\t\t\t\t++count;\n\t\t\t\t++pos;\n\t\t\t}\n\n\t\t\treturn count;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the given elements from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'delete', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.delete called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst needles       = Array.prototype.concat.apply([], arguments);\n\t\t\tconst needlesLength = needles.length;\n\t\t\tconst indices       = [];\n\n\t\t\tfor (let i = 0; i < length; ++i) {\n\t\t\t\tconst value = this[i];\n\n\t\t\t\tfor (let j = 0; j < needlesLength; ++j) {\n\t\t\t\t\tconst needle = needles[j];\n\n\t\t\t\t\tif (value === needle || value !== value && needle !== needle) {\n\t\t\t\t\t\tindices.push(i);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst result = [];\n\n\t\t\t// Copy the elements (in original order).\n\t\t\tfor (let i = 0, iend = indices.length; i < iend; ++i) {\n\t\t\t\tresult[i] = this[indices[i]];\n\t\t\t}\n\n\t\t\tconst splice = Array.prototype.splice;\n\n\t\t\t// Delete the elements (in reverse order).\n\t\t\tfor (let i = indices.length - 1; i >= 0; --i) {\n\t\t\t\tsplice.call(this, indices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the elements at the given indices from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'deleteAt', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* indices */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.deleteAt called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst splice     = Array.prototype.splice;\n\t\t\tconst cpyIndices = [\n\t\t\t\t...(new Set(\n\t\t\t\t\tArray.prototype.concat.apply([], arguments)\n\t\t\t\t\t\t// Map negative indices to their positive counterparts,\n\t\t\t\t\t\t// so the Set can properly filter out duplicates.\n\t\t\t\t\t\t.map(x => x < 0 ? Math.max(0, length + x) : x)\n\t\t\t\t)).values()\n\t\t\t];\n\t\t\tconst delIndices = [...cpyIndices].sort((a, b) => b - a);\n\t\t\tconst result     = [];\n\n\t\t\t// Copy the elements (in originally specified order).\n\t\t\tfor (let i = 0, iend = cpyIndices.length; i < iend; ++i) {\n\t\t\t\tresult[i] = this[cpyIndices[i]];\n\t\t\t}\n\n\t\t\t// Delete the elements (in descending numeric order).\n\t\t\tfor (let i = 0, iend = delIndices.length; i < iend; ++i) {\n\t\t\t\tsplice.call(this, delIndices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the elements that pass the test implemented\n\t\tby the given predicate function from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'deleteWith', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(predicate, thisArg) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.deleteWith called on null or undefined');\n\t\t\t}\n\t\t\tif (typeof predicate !== 'function') {\n\t\t\t\tthrow new Error('Array.prototype.deleteWith predicate parameter must be a function');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst splice  = Array.prototype.splice;\n\t\t\tconst indices = [];\n\t\t\tconst result  = [];\n\n\t\t\t// Copy the elements (in original order).\n\t\t\tfor (let i = 0; i < length; ++i) {\n\t\t\t\tif (predicate.call(thisArg, this[i], i, this)) {\n\t\t\t\t\tresult.push(this[i]);\n\t\t\t\t\tindices.push(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Delete the elements (in reverse order).\n\t\t\tfor (let i = indices.length - 1; i >= 0; --i) {\n\t\t\t\tsplice.call(this, indices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the first element from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'first', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.first called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn this[0];\n\t\t}\n\t});\n\n\t/*\n\t\tReturns whether all of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'includesAll', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.includesAll called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 1) {\n\t\t\t\tif (Array.isArray(arguments[0])) {\n\t\t\t\t\treturn Array.prototype.includesAll.apply(this, arguments[0]);\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = arguments.length; i < iend; ++i) {\n\t\t\t\tif (\n\t\t\t\t\t!Array.prototype.some.call(this, function (val) {\n\t\t\t\t\t\treturn val === this.val || val !== val && this.val !== this.val;\n\t\t\t\t\t}, { val : arguments[i] })\n\t\t\t\t) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns whether any of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'includesAny', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.includesAny called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 1) {\n\t\t\t\tif (Array.isArray(arguments[0])) {\n\t\t\t\t\treturn Array.prototype.includesAny.apply(this, arguments[0]);\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = arguments.length; i < iend; ++i) {\n\t\t\t\tif (\n\t\t\t\t\tArray.prototype.some.call(this, function (val) {\n\t\t\t\t\t\treturn val === this.val || val !== val && this.val !== this.val;\n\t\t\t\t\t}, { val : arguments[i] })\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the last element from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'last', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.last called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn this[length - 1];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly removes an element from the base array and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pluck', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* DEPRECATED: [min ,] max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pluck called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, [...arguments]);\n\n\t\t\treturn Array.prototype.splice.call(this, index, 1)[0];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly removes the given number of unique elements from the base array\n\t\tand returns the removed elements as a new array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pluckMany', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(wantSize) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pluckMany called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tlet want = Math.trunc(wantSize);\n\n\t\t\tif (!Number.isInteger(want)) {\n\t\t\t\tthrow new Error('Array.prototype.pluckMany want parameter must be an integer');\n\t\t\t}\n\n\t\t\tif (want < 1) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif (want > length) {\n\t\t\t\twant = length;\n\t\t\t}\n\n\t\t\tconst splice = Array.prototype.splice;\n\t\t\tconst result = [];\n\t\t\tlet max = length - 1;\n\n\t\t\tdo {\n\t\t\t\tresult.push(splice.call(this, _random(0, max--), 1)[0]);\n\t\t\t} while (result.length < want);\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tAppends one or more unique elements to the end of the base array and\n\t\treturns its new length.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pushUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pushUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst addSize = arguments.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn this.length >>> 0;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst push    = Array.prototype.push;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = arguments[i];\n\n\t\t\t\tif (indexOf.call(this, value) === -1) {\n\t\t\t\t\tpush.call(this, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.length >>> 0;\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly selects an element from the base array and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array.prototype, 'random', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* DEPRECATED: [min ,] max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.random called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, [...arguments]);\n\n\t\t\treturn this[index];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly selects the given number of unique elements from the base array\n\t\tand returns the selected elements as a new array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'randomMany', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(wantSize) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.randomMany called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tlet want = Math.trunc(wantSize);\n\n\t\t\tif (!Number.isInteger(want)) {\n\t\t\t\tthrow new Error('Array.prototype.randomMany want parameter must be an integer');\n\t\t\t}\n\n\t\t\tif (want < 1) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif (want > length) {\n\t\t\t\twant = length;\n\t\t\t}\n\n\t\t\tconst picked = new Map();\n\t\t\tconst result = [];\n\t\t\tconst max    = length - 1;\n\n\t\t\tdo {\n\t\t\t\tlet i;\n\t\t\t\tdo {\n\t\t\t\t\ti = _random(0, max);\n\t\t\t\t} while (picked.has(i));\n\t\t\t\tpicked.set(i, true);\n\t\t\t\tresult.push(this[i]);\n\t\t\t} while (result.length < want);\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly shuffles the array and returns it.\n\t*/\n\tObject.defineProperty(Array.prototype, 'shuffle', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.shuffle called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tfor (let i = length - 1; i > 0; --i) {\n\t\t\t\tconst j = Math.floor(_nativeMathRandom() * (i + 1));\n\n\t\t\t\tif (i === j) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// [this[i], this[j]] = [this[j], this[i]];\n\t\t\t\tconst swap = this[i];\n\t\t\t\tthis[i] = this[j];\n\t\t\t\tthis[j] = swap;\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\t});\n\n\t/*\n\t\tPrepends one or more unique elements to the beginning of the base array\n\t\tand returns its new length.\n\t*/\n\tObject.defineProperty(Array.prototype, 'unshiftUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.unshiftUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst addSize = arguments.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn this.length >>> 0;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst unshift = Array.prototype.unshift;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = arguments[i];\n\n\t\t\t\tif (indexOf.call(this, value) === -1) {\n\t\t\t\t\tunshift.call(this, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.length >>> 0;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a bound function that supplies the given arguments to the base\n\t\tfunction, followed by the arguments are supplied to the bound function,\n\t\twhenever it is called.\n\t*/\n\tObject.defineProperty(Function.prototype, 'partial', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Function.prototype.partial called on null or undefined');\n\t\t\t}\n\n\t\t\tconst slice = Array.prototype.slice;\n\t\t\tconst fn    = this;\n\t\t\tconst bound = slice.call(arguments, 0);\n\n\t\t\treturn function () {\n\t\t\t\tconst applied = [];\n\t\t\t\tlet argc = 0;\n\n\t\t\t\tfor (let i = 0; i < bound.length; ++i) {\n\t\t\t\t\tapplied.push(bound[i] === undefined ? arguments[argc++] : bound[i]);\n\t\t\t\t}\n\n\t\t\t\treturn fn.apply(this, applied.concat(slice.call(arguments, argc)));\n\t\t\t};\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the given numerical clamped to the specified bounds.\n\t*/\n\tObject.defineProperty(Math, 'clamp', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(num, min, max) {\n\t\t\tconst value = Number(num);\n\t\t\treturn Number.isNaN(value) ? NaN : value.clamp(min, max);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a decimal number eased from 0 to 1.\n\n\t\tNOTE: The magnitude of the returned value decreases if num < 0.5 or increases if num > 0.5.\n\t*/\n\tObject.defineProperty(Math, 'easeInOut', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(num) {\n\t\t\treturn 1 - (Math.cos(Number(num) * Math.PI) + 1) / 2;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number clamped to the specified bounds.\n\t*/\n\tObject.defineProperty(Number.prototype, 'clamp', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* min, max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Number.prototype.clamp called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length !== 2) {\n\t\t\t\tthrow new Error('Number.prototype.clamp called with an incorrect number of parameters');\n\t\t\t}\n\n\t\t\tlet min = Number(arguments[0]);\n\t\t\tlet max = Number(arguments[1]);\n\n\t\t\tif (min > max) {\n\t\t\t\t[min, max] = [max, min];\n\t\t\t}\n\n\t\t\treturn Math.min(Math.max(this, min), max);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the given string with all RegExp metacharacters escaped.\n\t*/\n\tif (!RegExp.escape) {\n\t\t(() => {\n\t\t\tconst _regExpMetaCharsRe    = /[\\\\^$*+?.()|[\\]{}]/g;\n\t\t\tconst _hasRegExpMetaCharsRe = new RegExp(_regExpMetaCharsRe.source); // to drop the global flag\n\n\t\t\tObject.defineProperty(RegExp, 'escape', {\n\t\t\t\tconfigurable : true,\n\t\t\t\twritable     : true,\n\n\t\t\t\tvalue(str) {\n\t\t\t\t\tconst val = String(str);\n\t\t\t\t\treturn val && _hasRegExpMetaCharsRe.test(val)\n\t\t\t\t\t\t? val.replace(_regExpMetaCharsRe, '\\\\$&')\n\t\t\t\t\t\t: val;\n\t\t\t\t}\n\t\t\t});\n\t\t})();\n\t}\n\n\t/*\n\t\tReturns a formatted string, after replacing each format item in the given\n\t\tformat string with the text equivalent of the corresponding argument's value.\n\t*/\n\t(() => {\n\t\tconst _formatRegExp    = /{(\\d+)(?:,([+-]?\\d+))?}/g;\n\t\tconst _hasFormatRegExp = new RegExp(_formatRegExp.source); // to drop the global flag\n\n\t\tObject.defineProperty(String, 'format', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(format) {\n\t\t\t\tfunction padString(str, align, pad) {\n\t\t\t\t\tif (!align) {\n\t\t\t\t\t\treturn str;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst plen = Math.abs(align) - str.length;\n\n\t\t\t\t\tif (plen < 1) {\n\t\t\t\t\t\treturn str;\n\t\t\t\t\t}\n\n\t\t\t\t\t// const padding = Array(plen + 1).join(pad);\n\t\t\t\t\tconst padding = String(pad).repeat(plen);\n\t\t\t\t\treturn align < 0 ? str + padding : padding + str;\n\t\t\t\t}\n\n\t\t\t\tif (arguments.length < 2) {\n\t\t\t\t\treturn arguments.length === 0 ? '' : format;\n\t\t\t\t}\n\n\t\t\t\tconst args = arguments.length === 2 && Array.isArray(arguments[1])\n\t\t\t\t\t? [...arguments[1]]\n\t\t\t\t\t: Array.prototype.slice.call(arguments, 1);\n\n\t\t\t\tif (args.length === 0) {\n\t\t\t\t\treturn format;\n\t\t\t\t}\n\n\t\t\t\tif (!_hasFormatRegExp.test(format)) {\n\t\t\t\t\treturn format;\n\t\t\t\t}\n\n\t\t\t\t// Possibly required by some old buggy browsers.\n\t\t\t\t_formatRegExp.lastIndex = 0;\n\n\t\t\t\treturn format.replace(_formatRegExp, (match, index, align) => {\n\t\t\t\t\tlet retval = args[index];\n\n\t\t\t\t\tif (retval == null) { // lazy equality for null\n\t\t\t\t\t\treturn '';\n\t\t\t\t\t}\n\n\t\t\t\t\twhile (typeof retval === 'function') {\n\t\t\t\t\t\tretval = retval();\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (typeof retval) {\n\t\t\t\t\tcase 'string': /* no-op */ break;\n\t\t\t\t\tcase 'object': retval = JSON.stringify(retval); break;\n\t\t\t\t\tdefault:       retval = String(retval); break;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn padString(retval, !align ? 0 : Number.parseInt(align, 10), ' ');\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t})();\n\n\t/*\n\t\tReturns whether the given string was found within the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'contains', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.contains called on null or undefined');\n\t\t\t}\n\n\t\t\treturn String.prototype.indexOf.apply(this, arguments) !== -1;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number of times the given substring was found within the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'count', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex ] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.count called on null or undefined');\n\t\t\t}\n\n\t\t\tconst needle = String(arguments[0] || '');\n\n\t\t\tif (needle === '') {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tconst indexOf = String.prototype.indexOf;\n\t\t\tconst step    = needle.length;\n\t\t\tlet pos     = Number(arguments[1]) || 0;\n\t\t\tlet count   = 0;\n\n\t\t\twhile ((pos = indexOf.call(this, needle, pos)) !== -1) {\n\t\t\t\t++count;\n\t\t\t\tpos += step;\n\t\t\t}\n\n\t\t\treturn count;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the first Unicode code point from the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'first', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.first called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn char;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the last Unicode code point from the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'last', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.last called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the last code point—may be one or two code units—and its end position.\n\t\t\tconst { char } = _getCodePointStartAndEnd(str, str.length - 1);\n\n\t\t\treturn char;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with `delCount` characters replaced with\n\t\t`replacement`, starting at `startAt`.\n\t*/\n\tObject.defineProperty(String.prototype, 'splice', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(startAt, delCount, replacement) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.splice called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tlet start = Number(startAt);\n\n\t\t\tif (!Number.isSafeInteger(start)) {\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t\telse if (start < 0) {\n\t\t\t\tstart += length;\n\n\t\t\t\tif (start < 0) {\n\t\t\t\t\tstart = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (start > length) {\n\t\t\t\tstart = length;\n\t\t\t}\n\n\t\t\tlet count = Number(delCount);\n\n\t\t\tif (!Number.isSafeInteger(count) || count < 0) {\n\t\t\t\tcount = 0;\n\t\t\t}\n\n\t\t\tlet res = this.slice(0, start);\n\n\t\t\tif (typeof replacement !== 'undefined') {\n\t\t\t\tres += replacement;\n\t\t\t}\n\n\t\t\tif (start + count < length) {\n\t\t\t\tres += this.slice(start + count);\n\t\t\t}\n\n\t\t\treturn res;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns an array of strings, split from the string, or an empty array if the\n\t\tstring is empty.\n\t*/\n\tObject.defineProperty(String.prototype, 'splitOrEmpty', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* [ separator [, limit ]] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.splitOrEmpty called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tif (String(this) === '') {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\treturn String.prototype.split.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with the first Unicode code point uppercased,\n\t\taccording to any locale-specific rules.\n\t*/\n\tObject.defineProperty(String.prototype, 'toLocaleUpperFirst', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.toLocaleUpperFirst called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char, end } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn end === -1 ? '' : char.toLocaleUpperCase() + str.slice(end + 1);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with the first Unicode code point uppercased.\n\t*/\n\tObject.defineProperty(String.prototype, 'toUpperFirst', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.toUpperFirst called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char, end } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn end === -1 ? '' : char.toUpperCase() + str.slice(end + 1);\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, JSON.\n\t*******************************************************************************************************************/\n\t/*\n\t\tDefine `toJSON()` methods on each prototype we wish to support.\n\t*/\n\tObject.defineProperty(Date.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:date)', this.toISOString()];\n\t\t}\n\t});\n\tObject.defineProperty(Function.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\t/*\n\t\t\t\tThe enclosing parenthesis here are necessary to force the function expression code\n\t\t\t\tstring, returned by `this.toString()`, to be evaluated as an expression during\n\t\t\t\trevival.  Without them, the function expression, which is likely nameless, will be\n\t\t\t\tevaluated as a function definition—which will throw a syntax error exception, since\n\t\t\t\tfunction definitions must have a name.\n\t\t\t*/\n\t\t\treturn ['(revive:eval)', `(${this.toString()})`];\n\t\t}\n\t});\n\tObject.defineProperty(Map.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:map)', [...this]];\n\t\t}\n\t});\n\tObject.defineProperty(RegExp.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:eval)', this.toString()];\n\t\t}\n\t});\n\tObject.defineProperty(Set.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:set)', [...this]];\n\t\t}\n\t});\n\n\t/*\n\t\tUtility method to allow users to easily wrap their code in the revive wrapper.\n\t*/\n\tObject.defineProperty(JSON, 'reviveWrapper', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(code, data) {\n\t\t\tif (typeof code !== 'string') {\n\t\t\t\tthrow new TypeError('JSON.reviveWrapper code parameter must be a string');\n\t\t\t}\n\n\t\t\treturn ['(revive:eval)', [code, data]];\n\t\t}\n\t});\n\n\t/*\n\t\tBackup the original `JSON.parse()` and replace it with a revive wrapper aware version.\n\t*/\n\tObject.defineProperty(JSON, '_real_parse', {\n\t\tvalue : JSON.parse\n\t});\n\tObject.defineProperty(JSON, 'parse', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(text, reviver) {\n\t\t\treturn JSON._real_parse(text, (key, val) => {\n\t\t\t\tlet value = val;\n\n\t\t\t\t/*\n\t\t\t\t\tAttempt to revive wrapped values.\n\t\t\t\t*/\n\t\t\t\tif (Array.isArray(value) && value.length === 2) {\n\t\t\t\t\tswitch (value[0]) {\n\t\t\t\t\tcase '(revive:set)':\n\t\t\t\t\t\tvalue = new Set(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:map)':\n\t\t\t\t\t\tvalue = new Map(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:date)':\n\t\t\t\t\t\tvalue = new Date(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:eval)':\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t/* eslint-disable no-eval */\n\t\t\t\t\t\t\t// For post-v2.9.0 `JSON.reviveWrapper()`.\n\t\t\t\t\t\t\tif (Array.isArray(value[1])) {\n\t\t\t\t\t\t\t\tconst $ReviveData$ = value[1][1]; // eslint-disable-line no-unused-vars\n\t\t\t\t\t\t\t\tvalue = eval(value[1][0]);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// For regular expressions, functions, and pre-v2.9.0 `JSON.reviveWrapper()`.\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tvalue = eval(value[1]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/* eslint-enable no-eval */\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* legacy */\n\t\t\t\telse if (typeof value === 'string' && value.slice(0, 10) === '@@revive@@') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvalue = eval(value.slice(10)); // eslint-disable-line no-eval\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t}\n\t\t\t\t/* /legacy */\n\n\t\t\t\t/*\n\t\t\t\t\tCall the custom reviver, if specified.\n\t\t\t\t*/\n\t\t\t\tif (typeof reviver === 'function') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvalue = reviver(key, value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t}\n\n\t\t\t\treturn value;\n\t\t\t});\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, Deprecated.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Returns whether the given element was found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'contains', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.contains called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns whether all of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'containsAll', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.containsAll called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includesAll.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns whether any of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'containsAny', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.containsAny called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includesAny.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns a new array consisting of the flattened source array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'flatten', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.flatten called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.flat.call(this, Infinity);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns an array of link titles, parsed from the string.\n\n\t\tNOTE: Unused in SugarCube, only included for compatibility.\n\t*/\n\tObject.defineProperty(String.prototype, 'readBracketedList', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.readBracketedList called on null or undefined');\n\t\t\t}\n\n\t\t\t// RegExp groups: Double-square-bracket quoted | Unquoted.\n\t\t\tconst re    = new RegExp('(?:\\\\[\\\\[((?:\\\\s|\\\\S)*?)\\\\]\\\\])|([^\"\\'\\\\s]\\\\S*)', 'gm');\n\t\t\tconst names = [];\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this)) !== null) {\n\t\t\t\tif (match[1]) { // double-square-bracket quoted\n\t\t\t\t\tnames.push(match[1]);\n\t\t\t\t}\n\t\t\t\telse if (match[2]) { // unquoted\n\t\t\t\t\tnames.push(match[2]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn names;\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/browser.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar Browser = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/* eslint-disable max-len */\n\tconst userAgent = navigator.userAgent.toLowerCase();\n\n\tconst winPhone = userAgent.includes('windows phone');\n\tconst isMobile = Object.freeze({\n\t\tAndroid    : !winPhone && userAgent.includes('android'),\n\t\tBlackBerry : /blackberry|bb10/.test(userAgent),\n\t\tiOS        : !winPhone && /ip(?:hone|ad|od)/.test(userAgent),\n\t\tOpera      : !winPhone && (typeof window.operamini === 'object' || userAgent.includes('opera mini')),\n\t\tWindows    : winPhone || /iemobile|wpdesktop/.test(userAgent),\n\n\t\tany() {\n\t\t\treturn isMobile.Android || isMobile.BlackBerry || isMobile.iOS || isMobile.Opera || isMobile.Windows;\n\t\t}\n\t});\n\n\tconst isGecko = !isMobile.Windows && !/khtml|trident|edge/.test(userAgent) && userAgent.includes('gecko');\n\n\tconst isIE      = !userAgent.includes('opera') && /msie|trident/.test(userAgent);\n\tconst ieVersion = isIE\n\t\t? (() => {\n\t\t\tconst ver = /(?:msie\\s+|rv:)(\\d+\\.\\d)/.exec(userAgent);\n\t\t\treturn ver ? Number(ver[1]) : 0;\n\t\t})()\n\t\t: null;\n\n\t// opera <= 12: \"opera/9.80 (windows nt 6.1; wow64) presto/2.12.388 version/12.16\"\n\t// opera >= 15: \"mozilla/5.0 (windows nt 6.1; wow64) applewebkit/537.36 (khtml, like gecko) chrome/28.0.1500.52 safari/537.36 opr/15.0.1147.130\"\n\tconst isOpera      = userAgent.includes('opera') || userAgent.includes(' opr/');\n\tconst operaVersion = isOpera\n\t\t? (() => {\n\t\t\tconst re  = new RegExp(`${/khtml|chrome/.test(userAgent) ? 'opr' : 'version'}\\\\/(\\\\d+\\\\.\\\\d+)`);\n\t\t\tconst ver = re.exec(userAgent);\n\t\t\treturn ver ? Number(ver[1]) : 0;\n\t\t})()\n\t\t: null;\n\n\tconst isVivaldi = userAgent.includes('vivaldi');\n\t/* eslint-enable max-len */\n\n\t// Module Exports.\n\treturn Object.freeze({\n\t\tuserAgent,\n\t\tisMobile,\n\t\tisGecko,\n\t\tisIE,\n\t\tieVersion,\n\t\tisOpera,\n\t\toperaVersion,\n\t\tisVivaldi\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/has.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser */\n\nvar Has = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tNOTE: The aggressive try/catch feature tests are necessitated by implementation\n\t\tbugs in various browsers.\n\t*/\n\n\t// Is the `HTMLAudioElement` API available?\n\tconst hasAudioElement = (() => {\n\t\ttry {\n\t\t\treturn typeof document.createElement('audio').canPlayType === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `File` API available?\n\tconst hasFile = (() => {\n\t\ttry {\n\t\t\treturn 'Blob' in window &&\n\t\t\t\t'File' in window &&\n\t\t\t\t'FileList' in window &&\n\t\t\t\t'FileReader' in window &&\n\t\t\t\t!Browser.isMobile.any() &&\n\t\t\t\t(!Browser.isOpera || Browser.operaVersion >= 15);\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `geolocation` API available?\n\tconst hasGeolocation = (() => {\n\t\ttry {\n\t\t\treturn 'geolocation' in navigator &&\n\t\t\t\ttypeof navigator.geolocation.getCurrentPosition === 'function' &&\n\t\t\t\ttypeof navigator.geolocation.watchPosition === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `MutationObserver` API available?\n\tconst hasMutationObserver = (() => {\n\t\ttry {\n\t\t\treturn 'MutationObserver' in window &&\n\t\t\t\ttypeof window.MutationObserver === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `performance` API available?\n\tconst hasPerformance = (() => {\n\t\ttry {\n\t\t\treturn 'performance' in window &&\n\t\t\t\ttypeof window.performance.now === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the platform a touch device?\n\tconst hasTouch = (() => {\n\t\ttry {\n\t\t\treturn 'ontouchstart' in window ||\n\t\t\t\t!!window.DocumentTouch &&\n\t\t\t\tdocument instanceof window.DocumentTouch ||\n\t\t\t\t!!navigator.maxTouchPoints ||\n\t\t\t\t!!navigator.msMaxTouchPoints;\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the transition end event available and by what name?\n\tconst hasTransitionEndEvent = (() => {\n\t\ttry {\n\t\t\tconst teMap = new Map([\n\t\t\t\t['transition',       'transitionend'],\n\t\t\t\t['MSTransition',     'msTransitionEnd'],\n\t\t\t\t['WebkitTransition', 'webkitTransitionEnd'],\n\t\t\t\t['MozTransition',    'transitionend']\n\t\t\t]);\n\t\t\tconst teKeys = [...teMap.keys()];\n\t\t\tconst el     = document.createElement('div');\n\n\t\t\tfor (let i = 0; i < teKeys.length; ++i) {\n\t\t\t\tif (el.style[teKeys[i]] !== undefined) {\n\t\t\t\t\treturn teMap.get(teKeys[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Module Exports.\n\treturn Object.freeze({\n\t\taudio              : hasAudioElement,\n\t\tfileAPI            : hasFile,\n\t\tgeolocation        : hasGeolocation,\n\t\tmutationObserver   : hasMutationObserver,\n\t\tperformance        : hasPerformance,\n\t\ttouch              : hasTouch,\n\t\ttransitionEndEvent : hasTransitionEndEvent\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/visibility.js\n\n\tCopyright © 2018–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar Visibility = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tThere are two versions of the Page Visibility API: First Edition and, the current,\n\t\tSecond Edition (i.e. \"Level 2\").  First Edition is mentioned here only because some\n\t\tolder browsers implement it, rather than the current specification.\n\n\t\tSEE:\n\t\t\tSecond Edition : https://www.w3.org/TR/page-visibility/\n\t\t\tFirst Edition  : https://www.w3.org/TR/2013/REC-page-visibility-20130514/\n\n\t\tNOTE: Generally, all supported browsers change the visibility state when either switching tabs\n\t\twithin the browser or minimizing the browser window.  Exceptions are noted below:\n\t\t\t* IE 9 doesn't support either version of the Page Visibility API.\n\t\t\t* Opera 12 (Presto) doesn't change the visibility state when the browser is minimized.\n\t*/\n\n\t// Vendor properties object.\n\tconst vendor = (() => {\n\t\ttry {\n\t\t\treturn Object.freeze([\n\t\t\t\t// Specification.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'hidden',          // boolean; historical in 2nd edition\n\t\t\t\t\tstateProperty  : 'visibilityState', // string, values: 'hidden', 'visible'; 1st edition had more values\n\t\t\t\t\tchangeEvent    : 'visibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `webkit` prefixed: old Blink & WebKit.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'webkitHidden',\n\t\t\t\t\tstateProperty  : 'webkitVisibilityState',\n\t\t\t\t\tchangeEvent    : 'webkitvisibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `moz` prefixed: old Gecko, maybe Seamonkey.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'mozHidden',\n\t\t\t\t\tstateProperty  : 'mozVisibilityState',\n\t\t\t\t\tchangeEvent    : 'mozvisibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `ms` prefixed: IE 10.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'msHidden',\n\t\t\t\t\tstateProperty  : 'msVisibilityState',\n\t\t\t\t\tchangeEvent    : 'msvisibilitychange'\n\t\t\t\t}\n\t\t\t].find(vnd => vnd.hiddenProperty in document));\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn undefined;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tAPI Functions.\n\t*******************************************************************************/\n\n\tfunction getVendor() {\n\t\treturn vendor;\n\t}\n\n\tfunction getVisibility() {\n\t\treturn vendor && document[vendor.stateProperty] || 'visible';\n\t}\n\n\tfunction isEnabled() {\n\t\treturn Boolean(vendor);\n\t}\n\n\tfunction isHidden() {\n\t\t// return Boolean(vendor && document[vendor.stateProperty] === 'hidden');\n\t\treturn Boolean(vendor && document[vendor.hiddenProperty]); // NOTE: Historical, but probably better for 1st edition.\n\t}\n\n\n\t/*******************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Functions.\n\t\tvendor    : { get : getVendor },\n\t\tstate     : { get : getVisibility },\n\t\tisEnabled : { value : isEnabled },\n\t\tisHidden  : { value : isHidden },\n\n\t\t// Properties.\n\t\thiddenProperty : { value : vendor && vendor.hiddenProperty },\n\t\tstateProperty  : { value : vendor && vendor.stateProperty },\n\t\tchangeEvent    : { value : vendor && vendor.changeEvent }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/fullscreen.js\n\n\tCopyright © 2018–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser */\n\nvar Fullscreen = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tSEE:\n\t\t\thttps://fullscreen.spec.whatwg.org\n\t\t\thttps://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API\n\t*/\n\n\t// Vendor properties object.\n\tconst vendor = (() => {\n\t\ttry {\n\t\t\treturn Object.freeze([\n\t\t\t\t// Specification.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'fullscreenEnabled',\n\t\t\t\t\telement     : 'fullscreenElement',\n\t\t\t\t\trequestFn   : 'requestFullscreen',\n\t\t\t\t\texitFn      : 'exitFullscreen',\n\t\t\t\t\tchangeEvent : 'fullscreenchange', // prop: onfullscreenchange\n\t\t\t\t\terrorEvent  : 'fullscreenerror'   // prop: onfullscreenerror\n\t\t\t\t},\n\n\t\t\t\t// `webkit` prefixed: old Blink, WebKit, & Edge.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'webkitFullscreenEnabled',\n\t\t\t\t\telement     : 'webkitFullscreenElement',\n\t\t\t\t\trequestFn   : 'webkitRequestFullscreen',\n\t\t\t\t\texitFn      : 'webkitExitFullscreen',\n\t\t\t\t\tchangeEvent : 'webkitfullscreenchange',\n\t\t\t\t\terrorEvent  : 'webkitfullscreenerror'\n\t\t\t\t},\n\n\t\t\t\t// `moz` prefixed: old Gecko, maybe Seamonkey.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'mozFullScreenEnabled',\n\t\t\t\t\telement     : 'mozFullScreenElement',\n\t\t\t\t\trequestFn   : 'mozRequestFullScreen',\n\t\t\t\t\texitFn      : 'mozCancelFullScreen',\n\t\t\t\t\tchangeEvent : 'mozfullscreenchange',\n\t\t\t\t\terrorEvent  : 'mozfullscreenerror'\n\t\t\t\t},\n\n\t\t\t\t// `ms` prefixed: IE 11.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'msFullscreenEnabled',\n\t\t\t\t\telement     : 'msFullscreenElement',\n\t\t\t\t\trequestFn   : 'msRequestFullscreen',\n\t\t\t\t\texitFn      : 'msExitFullscreen',\n\t\t\t\t\tchangeEvent : 'MSFullscreenChange',\n\t\t\t\t\terrorEvent  : 'MSFullscreenError'\n\t\t\t\t}\n\t\t\t].find(vnd => vnd.isEnabled in document));\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn undefined;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tFeature Detection Functions.\n\t*******************************************************************************/\n\n\t// Return whether the request and exit fullscreen methods return a `Promise`.\n\t//\n\t// NOTE: The initial result is cached for future calls.\n\tconst _returnsPromise = (function () {\n\t\t// Cache of whether the request and exit methods return a `Promise`.\n\t\tlet _hasPromise = null;\n\n\t\tfunction _returnsPromise() {\n\t\t\tif (_hasPromise !== null) {\n\t\t\t\treturn _hasPromise;\n\t\t\t}\n\n\t\t\t_hasPromise = false;\n\n\t\t\tif (vendor) {\n\t\t\t\ttry {\n\t\t\t\t\tconst value = document.exitFullscreen();\n\n\t\t\t\t\t// Silence \"Uncaught (in promise)\" console errors from Blink.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: Swallowing errors is generally bad, but in this case we know there's\n\t\t\t\t\t// going to be an error regardless, since we shouldn't be in fullscreen yet,\n\t\t\t\t\t// and we don't actually care about the error, since we just want the return\n\t\t\t\t\t// value, so we consign it to the bit bucket.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: We don't ensure that the return value is not `undefined` here because\n\t\t\t\t\t// having the attempted call to `<Promise>.catch()` on an `undefined` value throw\n\t\t\t\t\t// is acceptable, since it will be caught and `false` eventually returned.\n\t\t\t\t\tvalue.catch(() => { /* no-op */ });\n\n\t\t\t\t\t_hasPromise = value instanceof Promise;\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t}\n\n\t\t\treturn _hasPromise;\n\t\t}\n\n\t\treturn _returnsPromise;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************/\n\n\tfunction _selectElement(requestedEl) {\n\t\tlet selectedEl = requestedEl || document.documentElement;\n\n\t\t// Document element scrolling workaround for older browsers.\n\t\tif (\n\t\t\t   selectedEl === document.documentElement\n\t\t\t&& (\n\t\t\t\t   vendor.requestFn === 'msRequestFullscreen'   // IE 11\n\t\t\t\t|| Browser.isOpera && Browser.operaVersion < 15 // Opera 12 (Presto)\n\t\t\t)\n\t\t) {\n\t\t\tselectedEl = document.body;\n\t\t}\n\n\t\treturn selectedEl;\n\t}\n\n\n\t/*******************************************************************************\n\t\tAPI Functions.\n\t*******************************************************************************/\n\n\tfunction getVendor() {\n\t\treturn vendor;\n\t}\n\n\tfunction getElement() {\n\t\treturn (vendor || null) && document[vendor.element];\n\t}\n\n\tfunction isEnabled() {\n\t\treturn Boolean(vendor && document[vendor.isEnabled]);\n\t}\n\n\tfunction isFullscreen() {\n\t\treturn Boolean(vendor && document[vendor.element]);\n\t}\n\n\tfunction requestFullscreen(options, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn Promise.reject(new Error('fullscreen not supported'));\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (typeof element[vendor.requestFn] !== 'function') {\n\t\t\treturn Promise.reject(new Error('fullscreen not supported'));\n\t\t}\n\t\tif (isFullscreen()) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tif (_returnsPromise()) {\n\t\t\treturn element[vendor.requestFn](options);\n\t\t}\n\t\telse { // eslint-disable-line no-else-return\n\t\t\tconst namespace = '.Fullscreen_requestFullscreen';\n\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tjQuery(element)\n\t\t\t\t\t.off(namespace)\n\t\t\t\t\t.one(`${vendor.errorEvent}${namespace} ${vendor.changeEvent}${namespace}`, ev => {\n\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\tif (ev.type === vendor.errorEvent) {\n\t\t\t\t\t\t\treject(new Error('unknown fullscreen request error'));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\telement[vendor.requestFn](options);\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction exitFullscreen() {\n\t\tif (!vendor || typeof document[vendor.exitFn] !== 'function') {\n\t\t\treturn Promise.reject(new TypeError('fullscreen not supported'));\n\t\t}\n\t\tif (!isFullscreen()) {\n\t\t\treturn Promise.reject(new TypeError('fullscreen mode not active'));\n\t\t}\n\n\t\tif (_returnsPromise()) {\n\t\t\treturn document[vendor.exitFn]();\n\t\t}\n\t\telse { // eslint-disable-line no-else-return\n\t\t\tconst namespace = '.Fullscreen_exitFullscreen';\n\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tjQuery(document)\n\t\t\t\t\t.off(namespace)\n\t\t\t\t\t.one(`${vendor.errorEvent}${namespace} ${vendor.changeEvent}${namespace}`, ev => {\n\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\tif (ev.type === vendor.errorEvent) {\n\t\t\t\t\t\t\treject(new Error('unknown fullscreen exit error'));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tdocument[vendor.exitFn]();\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction toggleFullscreen(options, requestedEl) {\n\t\treturn isFullscreen() ? exitFullscreen() : requestFullscreen(options, requestedEl);\n\t}\n\n\tfunction onChange(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\t$(element).on(vendor.changeEvent, handlerFn);\n\t}\n\n\tfunction offChange(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (handlerFn) {\n\t\t\t$(element).off(vendor.changeEvent, handlerFn);\n\t\t}\n\t\telse {\n\t\t\t$(element).off(vendor.changeEvent);\n\t\t}\n\t}\n\n\tfunction onError(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\t$(element).on(vendor.errorEvent, handlerFn);\n\t}\n\n\tfunction offError(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (handlerFn) {\n\t\t\t$(element).off(vendor.errorEvent, handlerFn);\n\t\t}\n\t\telse {\n\t\t\t$(element).off(vendor.errorEvent);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tvendor       : { get : getVendor },\n\t\telement      : { get : getElement },\n\t\tisEnabled    : { value : isEnabled },\n\t\tisFullscreen : { value : isFullscreen },\n\t\trequest      : { value : requestFullscreen },\n\t\texit         : { value : exitFullscreen },\n\t\ttoggle       : { value : toggleFullscreen },\n\t\tonChange     : { value : onChange },\n\t\toffChange    : { value : offChange },\n\t\tonError      : { value : onError },\n\t\toffError     : { value : offError }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/helpers.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, L10n, State, Story, Util, Wikifier */\n\nvar { // eslint-disable-line no-var\n\t/* eslint-disable no-unused-vars */\n\tclone,\n\tconvertBreaks,\n\tsafeActiveElement,\n\tsetDisplayTitle,\n\tsetPageElement,\n\tthrowError,\n\ttoStringOrDefault\n\t/* eslint-enable no-unused-vars */\n} = (() => {\n\t'use strict';\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _getTextContent(source) {\n\t\tconst copy = source.cloneNode(true);\n\t\tconst frag = document.createDocumentFragment();\n\t\tlet node;\n\n\t\twhile ((node = copy.firstChild) !== null) {\n\t\t\t// Insert spaces before various elements.\n\t\t\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tswitch (node.nodeName.toUpperCase()) {\n\t\t\t\tcase 'BR':\n\t\t\t\tcase 'DIV':\n\t\t\t\tcase 'P':\n\t\t\t\t\tfrag.appendChild(document.createTextNode(' '));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfrag.appendChild(node);\n\t\t}\n\n\t\treturn frag.textContent;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tHelper Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a deep copy of the given object.\n\n\t\tNOTE:\n\t\t\t1. `clone()` does not clone functions, however, since function definitions\n\t\t\t   are immutable, the only issues are with expando properties and scope.\n\t\t\t   The former really should not be done.  The latter is problematic either\n\t\t\t   way—damned if you do, damned if you don't.\n\t\t\t2. `clone()` does not maintain referential relationships—e.g. multiple\n\t\t\t   references to the same object will, post-cloning, refer to different\n\t\t\t   equivalent objects; i.e. each reference will receive its own clone\n\t\t\t   of the original object.\n\t*/\n\tfunction clone(orig) {\n\t\t/*\n\t\t\tImmediately return the primitives and functions.\n\t\t*/\n\t\tif (typeof orig !== 'object' || orig === null) {\n\t\t\treturn orig;\n\t\t}\n\n\t\t/*\n\t\t\tUnbox instances of the primitive exemplar objects.\n\t\t*/\n\t\tif (orig instanceof String) {\n\t\t\treturn String(orig);\n\t\t}\n\t\tif (orig instanceof Number) {\n\t\t\treturn Number(orig);\n\t\t}\n\t\tif (orig instanceof Boolean) {\n\t\t\treturn Boolean(orig);\n\t\t}\n\n\t\t/*\n\t\t\tHonor native clone methods.\n\t\t*/\n\t\tif (typeof orig.clone === 'function') {\n\t\t\treturn orig.clone(true);\n\t\t}\n\t\tif (orig.nodeType && typeof orig.cloneNode === 'function') {\n\t\t\treturn orig.cloneNode(true);\n\t\t}\n\n\t\t/*\n\t\t\tCreate a copy of the original object.\n\n\t\t\tNOTE: Each non-generic object that we wish to support must be\n\t\t\texplicitly handled below.\n\t\t*/\n\t\tlet copy;\n\n\t\t// Handle instances of the core supported object types.\n\t\tif (orig instanceof Array) {\n\t\t\tcopy = new Array(orig.length);\n\t\t}\n\t\telse if (orig instanceof Date) {\n\t\t\tcopy = new Date(orig.getTime());\n\t\t}\n\t\telse if (orig instanceof Map) {\n\t\t\tcopy = new Map();\n\t\t\torig.forEach((val, key) => copy.set(key, clone(val)));\n\t\t}\n\t\telse if (orig instanceof RegExp) {\n\t\t\tcopy = new RegExp(orig);\n\t\t}\n\t\telse if (orig instanceof Set) {\n\t\t\tcopy = new Set();\n\t\t\torig.forEach(val => copy.add(clone(val)));\n\t\t}\n\n\t\t// Handle instances of unknown or generic objects.\n\t\telse {\n\t\t\t// We try to ensure that the returned copy has the same prototype as\n\t\t\t// the original, but this will probably produce less than satisfactory\n\t\t\t// results on non-generics.\n\t\t\tcopy = Object.create(Object.getPrototypeOf(orig));\n\t\t}\n\n\t\t/*\n\t\t\tDuplicate the original object's own enumerable properties, which will\n\t\t\tinclude expando properties on non-generic objects.\n\n\t\t\tNOTE: This preserves neither symbol properties nor ES5 property attributes.\n\t\t\tNeither does the delta coding or serialization code, however, so it's not\n\t\t\treally an issue at the moment.\n\t\t*/\n\t\tObject.keys(orig).forEach(name => copy[name] = clone(orig[name]));\n\n\t\treturn copy;\n\t}\n\n\t/*\n\t\tConverts <br> elements to <p> elements within the given node tree.\n\t*/\n\tfunction convertBreaks(source) {\n\t\tconst output = document.createDocumentFragment();\n\t\tlet para = document.createElement('p');\n\t\tlet node;\n\n\t\twhile ((node = source.firstChild) !== null) {\n\t\t\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tconst tagName = node.nodeName.toUpperCase();\n\n\t\t\t\tswitch (tagName) {\n\t\t\t\tcase 'BR':\n\t\t\t\t\tif (\n\t\t\t\t\t\t   node.nextSibling !== null\n\t\t\t\t\t\t&& node.nextSibling.nodeType === Node.ELEMENT_NODE\n\t\t\t\t\t\t&& node.nextSibling.nodeName.toUpperCase() === 'BR'\n\t\t\t\t\t) {\n\t\t\t\t\t\tsource.removeChild(node.nextSibling);\n\t\t\t\t\t\tsource.removeChild(node);\n\t\t\t\t\t\toutput.appendChild(para);\n\t\t\t\t\t\tpara = document.createElement('p');\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\telse if (!para.hasChildNodes()) {\n\t\t\t\t\t\tsource.removeChild(node);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'ADDRESS':\n\t\t\t\tcase 'ARTICLE':\n\t\t\t\tcase 'ASIDE':\n\t\t\t\tcase 'BLOCKQUOTE':\n\t\t\t\tcase 'CENTER':\n\t\t\t\tcase 'DIV':\n\t\t\t\tcase 'DL':\n\t\t\t\tcase 'FIGURE':\n\t\t\t\tcase 'FOOTER':\n\t\t\t\tcase 'FORM':\n\t\t\t\tcase 'H1':\n\t\t\t\tcase 'H2':\n\t\t\t\tcase 'H3':\n\t\t\t\tcase 'H4':\n\t\t\t\tcase 'H5':\n\t\t\t\tcase 'H6':\n\t\t\t\tcase 'HEADER':\n\t\t\t\tcase 'HR':\n\t\t\t\tcase 'MAIN':\n\t\t\t\tcase 'NAV':\n\t\t\t\tcase 'OL':\n\t\t\t\tcase 'P':\n\t\t\t\tcase 'PRE':\n\t\t\t\tcase 'SECTION':\n\t\t\t\tcase 'TABLE':\n\t\t\t\tcase 'UL':\n\t\t\t\t\tif (para.hasChildNodes()) {\n\t\t\t\t\t\toutput.appendChild(para);\n\t\t\t\t\t\tpara = document.createElement('p');\n\t\t\t\t\t}\n\n\t\t\t\t\toutput.appendChild(node);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpara.appendChild(node);\n\t\t}\n\n\t\tif (para.hasChildNodes()) {\n\t\t\toutput.appendChild(para);\n\t\t}\n\n\t\tsource.appendChild(output);\n\t}\n\n\t/*\n\t\tReturns `document.activeElement` or `null`.\n\t*/\n\tfunction safeActiveElement() {\n\t\t/*\n\t\t\tIE9 contains a bug where trying to access the active element of an iframe's\n\t\t\tparent document (i.e. `window.parent.document.activeElement`) will throw an\n\t\t\texception, so we must allow for an exception to be thrown.\n\n\t\t\tWe could simply return `undefined` here, but since the API's default behavior\n\t\t\tshould be to return `document.body` or `null` when there is no selection, we\n\t\t\tchoose to return `null` in all non-element cases (i.e. whether it returns\n\t\t\t`null` or throws an exception).  Just a bit of normalization.\n\t\t*/\n\t\ttry {\n\t\t\treturn document.activeElement || null;\n\t\t}\n\t\tcatch (ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/*\n\t\tSets the display title.\n\t*/\n\tfunction setDisplayTitle(title) {\n\t\tif (typeof title !== 'string') {\n\t\t\tthrow new TypeError(`story display title must be a string (received: ${Util.getType(title)})`);\n\t\t}\n\n\t\tconst render = document.createDocumentFragment();\n\t\tnew Wikifier(render, title);\n\n\t\tconst text = _getTextContent(render).trim();\n\n\t\t// if (text === '') {\n\t\t// \tthrow new Error('story display title must not render to an empty string or consist solely of whitespace');\n\t\t// }\n\n\t\tdocument.title = Config.passages.displayTitles && State.passage !== '' && State.passage !== Config.passages.start\n\t\t\t? `${State.passage} | ${text}`\n\t\t\t: text;\n\n\t\tconst storyTitle = document.getElementById('story-title');\n\n\t\tif (storyTitle !== null) {\n\t\t\tjQuery(storyTitle).empty().append(render);\n\t\t}\n\t}\n\n\t/*\n\t\tWikifies a passage into a DOM element corresponding to the passed ID and returns the element.\n\t*/\n\tfunction setPageElement(idOrElement, titles, defaultText) {\n\t\tconst el = typeof idOrElement === 'object'\n\t\t\t? idOrElement\n\t\t\t: document.getElementById(idOrElement);\n\n\t\tif (el == null) { // lazy equality for null\n\t\t\treturn null;\n\t\t}\n\n\t\tconst ids = Array.isArray(titles) ? titles : [titles];\n\n\t\tjQuery(el).empty();\n\n\t\tfor (let i = 0, iend = ids.length; i < iend; ++i) {\n\t\t\tif (Story.has(ids[i])) {\n\t\t\t\tnew Wikifier(el, Story.get(ids[i]).processText().trim());\n\t\t\t\treturn el;\n\t\t\t}\n\t\t}\n\n\t\tif (defaultText != null) { // lazy equality for null\n\t\t\tconst text = String(defaultText).trim();\n\n\t\t\tif (text !== '') {\n\t\t\t\tnew Wikifier(el, text);\n\t\t\t}\n\t\t}\n\n\t\treturn el;\n\t}\n\n\t/*\n\t\tAppends an error view to the passed DOM element.\n\t*/\n\tfunction throwError(place, message, source, stack) {\n\t\tconst $wrapper = jQuery(document.createElement('div'));\n\t\tconst $toggle  = jQuery(document.createElement('button'));\n\t\tconst $source  = jQuery(document.createElement('pre'));\n\t\tconst mesg     = `${L10n.get('errorTitle')}: ${message || 'unknown error'}`;\n\n\t\t$toggle\n\t\t\t.addClass('error-toggle')\n\t\t\t.ariaClick({\n\t\t\t\tlabel : L10n.get('errorToggle')\n\t\t\t}, () => {\n\t\t\t\tif ($toggle.hasClass('enabled')) {\n\t\t\t\t\t$toggle.removeClass('enabled');\n\t\t\t\t\t$source.attr({\n\t\t\t\t\t\t'aria-hidden' : true,\n\t\t\t\t\t\thidden        : 'hidden'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$toggle.addClass('enabled');\n\t\t\t\t\t$source.removeAttr('aria-hidden hidden');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.appendTo($wrapper);\n\t\tjQuery(document.createElement('span'))\n\t\t\t.addClass('error')\n\t\t\t.text(mesg)\n\t\t\t.appendTo($wrapper);\n\t\tjQuery(document.createElement('code'))\n\t\t\t.text(source)\n\t\t\t.appendTo($source);\n\t\t$source\n\t\t\t.addClass('error-source')\n\t\t\t.attr({\n\t\t\t\t'aria-hidden' : true,\n\t\t\t\thidden        : 'hidden'\n\t\t\t})\n\t\t\t.appendTo($wrapper);\n\t\tif (stack) {\n\t\t\tconst lines = stack.split('\\n');\n\t\t\tfor (const ll of lines) {\n\t\t\t\tconst div = document.createElement('div');\n\t\t\t\tdiv.append(ll.replace(/file:.*\\//, '<path>/'));\n\t\t\t\t$source.append(div);\n\t\t\t}\n\t\t}\n\t\t$wrapper\n\t\t\t.addClass('error-view')\n\t\t\t.appendTo(place);\n\n\t\tconsole.warn(`${mesg}\\n\\t${source.replace(/\\n/g, '\\n\\t')}`);\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tReturns the simple string representation of the passed value or, if there is none,\n\t\tthe passed default value.\n\t*/\n\tfunction toStringOrDefault(value, defValue) {\n\t\tconst tSOD = toStringOrDefault;\n\n\t\tswitch (typeof value) {\n\t\tcase 'number':\n\t\t\t// TODO: Perhaps NaN should be printed instead?\n\t\t\tif (Number.isNaN(value)) {\n\t\t\t\treturn defValue;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\tif (value === null) {\n\t\t\t\treturn defValue;\n\t\t\t}\n\t\t\telse if (Array.isArray(value)) {\n\t\t\t\treturn value.map(val => tSOD(val, defValue)).join(', ');\n\t\t\t}\n\t\t\telse if (value instanceof Set) {\n\t\t\t\treturn [...value].map(val => tSOD(val, defValue)).join(', ');\n\t\t\t}\n\t\t\telse if (value instanceof Map) {\n\t\t\t\tconst result = [...value].map(([key, val]) => `${tSOD(key, defValue)} \\u2192 ${tSOD(val, defValue)}`);\n\t\t\t\treturn `{\\u202F${result.join(', ')}\\u202F}`;\n\t\t\t}\n\t\t\telse if (value instanceof Date) {\n\t\t\t\treturn value.toLocaleString();\n\t\t\t}\n\t\t\telse if (typeof value.toString === 'function') {\n\t\t\t\treturn value.toString();\n\t\t\t}\n\t\t\treturn Object.prototype.toString.call(value);\n\n\t\tcase 'function':\n\t\tcase 'undefined':\n\t\t\treturn defValue;\n\t\t}\n\n\t\treturn String(value);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tclone             : { value : clone },\n\t\tconvertBreaks     : { value : convertBreaks },\n\t\tsafeActiveElement : { value : safeActiveElement },\n\t\tsetDisplayTitle   : { value : setDisplayTitle },\n\t\tsetPageElement    : { value : setPageElement },\n\t\tthrowError        : { value : throwError },\n\t\ttoStringOrDefault : { value : toStringOrDefault }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/jquery-plugins.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Wikifier, errorPrologRegExp, safeActiveElement */\n\n/*\n\tWAI-ARIA methods plugin.\n\n\t`<jQuery>.ariaClick([options,] handler)`\n\t    Makes the target element(s) WAI-ARIA compatible clickables.\n\n\t`<jQuery>.ariaDisabled(state)`\n\t    Changes the disabled state of the target WAI-ARIA-compatible clickable element(s).\n\n\t`<jQuery>.ariaIsDisabled()`\n\t    Checks the disabled status of the target WAI-ARIA-compatible clickable element(s).\n*/\n(() => {\n\t'use strict';\n\n\t/*\n\t\tEvent handler & utility functions.\n\n\t\tNOTE: Do not replace the anonymous functions herein with arrow functions.\n\t*/\n\tfunction onKeypressFn(ev) {\n\t\t// 13 is Enter/Return, 32 is Space.\n\t\tif (ev.which === 13 || ev.which === 32) {\n\t\t\tev.preventDefault();\n\n\t\t\t// To allow delegation, attempt to trigger the event on `document.activeElement`,\n\t\t\t// if possible, elsewise on `this`.\n\t\t\tjQuery(safeActiveElement() || this).trigger('click');\n\t\t}\n\t}\n\n\tfunction onClickFnWrapper(fn) {\n\t\treturn function () {\n\t\t\tconst $this = jQuery(this);\n\n\t\t\tconst dataPassage = $this.attr('data-passage');\n\t\t\tconst initialDataPassage = window && window.SugarCube && window.SugarCube.State && window.SugarCube.State.passage;\n\t\t\tconst savedYOffset = window.pageYOffset;\n\n\t\t\t// Toggle \"aria-pressed\" status, if the attribute exists.\n\t\t\tif ($this.is('[aria-pressed]')) {\n\t\t\t\t$this.attr('aria-pressed', $this.attr('aria-pressed') === 'true' ? 'false' : 'true');\n\t\t\t}\n\n\t\t\t// Call the true handler.\n\t\t\tfn.apply(this, arguments);\n\n\t\t\tconst doJump = function(){ window.scrollTo(0, savedYOffset); }\n\t\t\tif ( dataPassage && (window.lastDataPassageLink === dataPassage || initialDataPassage === dataPassage))\n\t\t\t\tdoJump();\n\t\t\twindow.lastDataPassageLink = dataPassage;\n\t\t};\n\t}\n\n\tfunction oneClickFnWrapper(fn) {\n\t\treturn onClickFnWrapper(function () {\n\t\t\t// Remove both event handlers (keypress & click) and the other components.\n\t\t\tjQuery(this)\n\t\t\t\t.off('.aria-clickable')\n\t\t\t\t.removeAttr('tabindex aria-controls aria-pressed')\n\t\t\t\t.not('a,button')\n\t\t\t\t.removeAttr('role')\n\t\t\t\t.end()\n\t\t\t\t.filter('button')\n\t\t\t\t.prop('disabled', true);\n\n\t\t\t// Call the true handler.\n\t\t\tfn.apply(this, arguments);\n\t\t});\n\t}\n\n\tjQuery.fn.extend({\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaClick()` method.\n\t\t*/\n\t\tariaClick(options, handler) {\n\t\t\t// Bail out if there are no target element(s) or parameters.\n\t\t\tif (this.length === 0 || arguments.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tlet opts = options;\n\t\t\tlet fn   = handler;\n\n\t\t\tif (fn == null) { // lazy equality for null\n\t\t\t\tfn   = opts;\n\t\t\t\topts = undefined;\n\t\t\t}\n\n\t\t\topts = jQuery.extend({\n\t\t\t\tnamespace : undefined,\n\t\t\t\tone       : false,\n\t\t\t\tselector  : undefined,\n\t\t\t\tdata      : undefined,\n\t\t\t\tcontrols  : undefined,\n\t\t\t\tpressed   : undefined,\n\t\t\t\tlabel     : undefined\n\t\t\t}, opts);\n\n\t\t\tif (typeof opts.namespace !== 'string') {\n\t\t\t\topts.namespace = '';\n\t\t\t}\n\t\t\telse if (opts.namespace[0] !== '.') {\n\t\t\t\topts.namespace = `.${opts.namespace}`;\n\t\t\t}\n\n\t\t\tif (typeof opts.pressed === 'boolean') {\n\t\t\t\topts.pressed = opts.pressed ? 'true' : 'false';\n\t\t\t}\n\n\t\t\t// Set `type` to `button` to suppress \"submit\" semantics, for <button> elements.\n\t\t\tthis.filter('button').prop('type', 'button');\n\n\t\t\t// Set `role` to `button`, for non-<a>/-<button> elements.\n\t\t\tthis.not('a,button').attr('role', 'button');\n\n\t\t\t// Set `tabindex` to `0` to make them focusable (unnecessary on <button> elements, but it doesn't hurt).\n\t\t\tthis.attr('tabindex', 0);\n\n\t\t\t// Set `aria-controls`.\n\t\t\tif (opts.controls != null) { // lazy equality for null\n\t\t\t\tthis.attr('aria-controls', opts.controls);\n\t\t\t}\n\n\t\t\t// Set `aria-pressed`.\n\t\t\tif (opts.pressed != null) { // lazy equality for null\n\t\t\t\tthis.attr('aria-pressed', opts.pressed);\n\t\t\t}\n\n\t\t\t// Set `aria-label` and `title`.\n\t\t\tif (opts.label != null) { // lazy equality for null\n\t\t\t\tthis.attr({\n\t\t\t\t\t'aria-label' : opts.label,\n\t\t\t\t\ttitle        : opts.label\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Set the keypress handlers, for non-<button> elements.\n\t\t\t// NOTE: For the single-use case, the click handler will also remove this handler.\n\t\t\tthis.not('button').on(\n\t\t\t\t`keypress.aria-clickable${opts.namespace}`,\n\t\t\t\topts.selector,\n\t\t\t\tonKeypressFn\n\t\t\t);\n\n\t\t\t// Set the click handlers.\n\t\t\t// NOTE: To ensure both handlers are properly removed, `one()` must not be used here.\n\t\t\tthis.on(\n\t\t\t\t`click.aria-clickable${opts.namespace}`,\n\t\t\t\topts.selector,\n\t\t\t\topts.data,\n\t\t\t\topts.one ? oneClickFnWrapper(fn) : onClickFnWrapper(fn)\n\t\t\t);\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaDisabled()` method.\n\t\t*/\n\t\tariaDisabled(disable) {\n\t\t\t// Bail out if there are no target element(s) or parameters.\n\t\t\tif (this.length === 0 || arguments.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tNOTE: We use `<jQuery>.each()` callbacks to invoke the `<Element>.setAttribute()`\n\t\t\t\tmethods in the following because the `<jQuery>.attr()` method does not allow you\n\t\t\t\tto set a content attribute without a value, which is recommended for boolean\n\t\t\t\tcontent attributes by the HTML specification.\n\t\t\t*/\n\n\t\t\tconst $nonDisableable = this.not('button,fieldset,input,menuitem,optgroup,option,select,textarea');\n\t\t\tconst $disableable    = this.filter('button,fieldset,input,menuitem,optgroup,option,select,textarea');\n\n\t\t\tif (disable) {\n\t\t\t\t// Add boolean content attribute `disabled` and set non-boolean content attribute\n\t\t\t\t// `aria-disabled` to `'true'`, for non-disableable elements.\n\t\t\t\t$nonDisableable.each(function () {\n\t\t\t\t\tthis.setAttribute('disabled', '');\n\t\t\t\t\tthis.setAttribute('aria-disabled', 'true');\n\t\t\t\t});\n\n\t\t\t\t// Set IDL attribute `disabled` to `true` and set non-boolean content attribute\n\t\t\t\t// `aria-disabled` to `'true'`, for disableable elements.\n\t\t\t\t$disableable.each(function () {\n\t\t\t\t\tthis.disabled = true;\n\t\t\t\t\tthis.setAttribute('aria-disabled', 'true');\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Remove content attributes `disabled` and `aria-disabled`, for non-disableable elements.\n\t\t\t\t$nonDisableable.each(function () {\n\t\t\t\t\tthis.removeAttribute('disabled');\n\t\t\t\t\tthis.removeAttribute('aria-disabled');\n\t\t\t\t});\n\n\t\t\t\t// Set IDL attribute `disabled` to `false` and remove content attribute `aria-disabled`,\n\t\t\t\t// for disableable elements.\n\t\t\t\t$disableable.each(function () {\n\t\t\t\t\tthis.disabled = false;\n\t\t\t\t\tthis.removeAttribute('aria-disabled');\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaIsDisabled()` method.\n\t\t*/\n\t\tariaIsDisabled() {\n\t\t\t// Check content attribute `disabled`.\n\t\t\t//\n\t\t\t// NOTE: We simply check the `disabled` content attribute for all elements\n\t\t\t// since we have to check it for non-disableable elements and it may also\n\t\t\t// be used for disableable elements since their `disabled` IDL attribute\n\t\t\t// is required to reflect the status of their `disabled` content attribute,\n\t\t\t// and vice versa, by the HTML specification.\n\t\t\t// return this.toArray().some(el => el.hasAttribute('disabled'));\n\t\t\treturn this.is('[disabled]');\n\t\t}\n\t});\n})();\n\n/*\n\tWikifier methods plugin.\n\n\t`jQuery.wikiWithOptions(options, sources…)`\n\t    Wikifies the given content source(s), as directed by the given options.\n\n\t`jQuery.wiki(sources…)`\n\t    Wikifies the given content source(s).\n\n\t`<jQuery>.wikiWithOptions(options, sources…)`\n\t    Wikifies the given content source(s) and appends the result to the target\n\t    element(s), as directed by the given options.\n\n\t`<jQuery>.wiki(sources…)`\n\t    Wikifies the given content source(s) and appends the result to the target\n\t    element(s).\n*/\n(() => {\n\t'use strict';\n\n\tjQuery.extend({\n\t\t/*\n\t\t\tExtend jQuery's static methods with a `wikiWithOptions()` method.\n\t\t*/\n\t\twikiWithOptions(options, ...sources) {\n\t\t\t// Bail out, if there are no content sources.\n\t\t\tif (sources.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Wikify the content sources into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tsources.forEach(content => new Wikifier(frag, content, options));\n\n\t\t\t// Gather the text of any error elements within the fragment…\n\t\t\tconst errors = [...frag.querySelectorAll('.error')]\n\t\t\t\t.map(errEl => errEl.textContent.replace(errorPrologRegExp, ''));\n\n\t\t\t// …and throw an exception, if there were any errors.\n\t\t\tif (errors.length > 0) {\n\t\t\t\tthrow new Error(errors.join('; '));\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's static methods with a `wiki()` method.\n\t\t*/\n\t\twiki(...sources) {\n\t\t\tthis.wikiWithOptions(undefined, ...sources);\n\t\t}\n\t});\n\n\tjQuery.fn.extend({\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with a `wikiWithOptions()` method.\n\t\t*/\n\t\twikiWithOptions(options, ...sources) {\n\t\t\t// Bail out if there are no target element(s) or content sources.\n\t\t\tif (this.length === 0 || sources.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t// Wikify the content sources into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tsources.forEach(content => new Wikifier(frag, content, options));\n\n\t\t\t// Append the fragment to the target element(s).\n\t\t\tthis.append(frag);\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with a `wiki()` method.\n\t\t*/\n\t\twiki(...sources) {\n\t\t\treturn this.wikiWithOptions(undefined, ...sources);\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/util.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Has, Scripting */\n\nvar Util = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tType Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the value yielded by `typeof` (for primitives), the `@@toStringTag`\n\t\tinternal property (for objects), and `'null'` for `null`.\n\n\t\tNOTE: In ≤ES5, returns the value of the `[[Class]]` internal slot for objects.\n\t*/\n\tfunction utilGetType(obj) {\n\t\tif (obj === null) { return 'null'; }\n\n\t\tconst baseType = typeof obj;\n\t\treturn baseType === 'object'\n\t\t\t? Object.prototype.toString.call(obj).slice(8, -1)\n\t\t\t: baseType;\n\t}\n\n\t/*\n\t\tReturns whether the passed value is a boolean or one of the strings \"true\"\n\t\tor \"false\".\n\t*/\n\tfunction utilIsBoolean(obj) {\n\t\treturn typeof obj === 'boolean' || typeof obj === 'string' && (obj === 'true' || obj === 'false');\n\t}\n\n\t/*\n\t\tReturns whether the passed value is iterable.\n\t*/\n\tfunction utilIsIterable(obj) {\n\t\treturn obj != null && typeof obj[Symbol.iterator] === 'function'; // lazy equality for null\n\t}\n\n\t/*\n\t\tReturns whether the passed value is a finite number or a numeric string which\n\t\tyields a finite number when parsed.\n\t*/\n\tfunction utilIsNumeric(obj) {\n\t\tlet num;\n\n\t\tswitch (typeof obj) {\n\t\tcase 'number':\n\t\t\tnum = obj;\n\t\t\tbreak;\n\n\t\tcase 'string':\n\t\t\tnum = Number(obj);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !Number.isNaN(num) && Number.isFinite(num);\n\t}\n\n\t/*\n\t\tReturns whether the passed values pass a SameValueZero comparison.\n\n\t\tSEE: http://ecma-international.org/ecma-262/8.0/#sec-samevaluezero\n\t*/\n\tfunction utilSameValueZero(a, b) {\n\t\t/*\n\t\t\tNOTE: This comparison could also be implemented thus:\n\n\t\t\t\t```\n\t\t\t\ta === b ||\n\t\t\t\ttypeof a === 'number' && typeof b === 'number' &&\n\t\t\t\tNumber.isNaN(a) && Number.isNaN(b)\n\t\t\t\t```\n\n\t\t\tThat's needlessly verbose, however, as `NaN` is the only value in\n\t\t\tthe language which is not reflexive.\n\t\t*/\n\t\treturn a === b || a !== a && b !== b;\n\t}\n\n\t/*\n\t\tReturns a pseudo-enumeration created from the given Array, Map, Set, or generic object.\n\t*/\n\tfunction utilToEnum(obj) {\n\t\tconst pEnum = Object.create(null);\n\n\t\tif (obj instanceof Array) {\n\t\t\tobj.forEach((val, i) => pEnum[String(val)] = i);\n\t\t}\n\t\telse if (obj instanceof Set) {\n\t\t\t// NOTE: Use `<Array>.forEach()` here rather than `<Set>.forEach()`\n\t\t\t// as the latter does not provide the indices we require.\n\t\t\tArray.from(obj).forEach((val, i) => pEnum[String(val)] = i);\n\t\t}\n\t\telse if (obj instanceof Map) {\n\t\t\tobj.forEach((val, key) => pEnum[String(key)] = val);\n\t\t}\n\t\telse if (\n\t\t\t   typeof obj === 'object'\n\t\t\t&& obj !== null\n\t\t\t&& Object.getPrototypeOf(obj) === Object.prototype\n\t\t) {\n\t\t\tObject.assign(pEnum, obj);\n\t\t}\n\t\telse {\n\t\t\tthrow new TypeError('Util.toEnum obj parameter must be an Array, Map, Set, or generic object');\n\t\t}\n\n\t\treturn Object.freeze(pEnum);\n\t}\n\n\t/*\n\t\tReturns the value of the `@@toStringTag` property of the given object.\n\n\t\tNOTE: In ≤ES5, returns the value of the `[[Class]]` internal slot.\n\t*/\n\tfunction utilToStringTag(obj) {\n\t\treturn Object.prototype.toString.call(obj).slice(8, -1);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tString Encoding Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a trimmed and encoded slug of the passed string that should be safe\n\t\tfor use as a DOM ID or class name.\n\n\t\tNOTE: The range of illegal characters consists of: C0 controls, space, exclamation,\n\t\tdouble quote, number, dollar, percent, ampersand, single quote, left paren, right\n\t\tparen, asterisk, plus, comma, hyphen, period, forward slash, colon, semi-colon,\n\t\tless-than, equals, greater-than, question, at, left bracket, backslash, right\n\t\tbracket, caret, backquote/grave, left brace, pipe/vertical-bar, right brace, tilde,\n\t\tdelete, C1 controls.\n\t*/\n\tconst _illegalSlugCharsRe = /[\\x00-\\x20!-/:-@[-^`{-\\x9f]+/g; // eslint-disable-line no-control-regex\n\t/* legacy */\n\tconst _isInvalidSlugRe = /^-*$/; // Matches the empty string or one comprised solely of hyphens.\n\t/* /legacy */\n\n\tfunction utilSlugify(str) {\n\t\tconst base = String(str).trim();\n\n\t\t/* legacy */\n\t\tconst _legacy = base\n\t\t\t.replace(/[^\\w\\s\\u2013\\u2014-]+/g, '')\n\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-')\n\t\t\t.toLocaleLowerCase();\n\n\t\tif (!_isInvalidSlugRe.test(_legacy)) {\n\t\t\treturn _legacy;\n\t\t}\n\t\t/* /legacy */\n\n\t\treturn base\n\t\t\t.replace(_illegalSlugCharsRe, '')\n\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-');\n\n\t\t// For v3.\n\t\t// return base.replace(_illegalSlugCharsRe, '-');\n\t}\n\n\t/*\n\t\tReturns an entity encoded version of the passed string.\n\n\t\tNOTE: Only escapes the five primary special characters and the backquote.\n\t*/\n\tconst _htmlCharsRe    = /[&<>\"'`]/g;\n\tconst _hasHtmlCharsRe = new RegExp(_htmlCharsRe.source); // to drop the global flag\n\tconst _htmlCharsMap   = Object.freeze({\n\t\t'&' : '&amp;',\n\t\t'<' : '&lt;',\n\t\t'>' : '&gt;',\n\t\t'\"' : '&quot;',\n\t\t\"'\" : '&#39;',\n\t\t'`' : '&#96;'\n\t});\n\n\tfunction utilEscape(str) {\n\t\tif (str == null) { // lazy equality for null\n\t\t\treturn '';\n\t\t}\n\n\t\tconst val = String(str);\n\t\treturn val && _hasHtmlCharsRe.test(val)\n\t\t\t? val.replace(_htmlCharsRe, ch => _htmlCharsMap[ch])\n\t\t\t: val;\n\t}\n\n\t/*\n\t\tReturns a decoded version of the passed entity encoded string.\n\n\t\tNOTE: The extended replacement set here, in contrast to `utilEscape()`,\n\t\tis required due to observed stupidity from various sources.\n\t*/\n\tconst _escapedHtmlRe    = /&(?:amp|#38|#x26|lt|#60|#x3c|gt|#62|#x3e|quot|#34|#x22|apos|#39|#x27|#96|#x60);/gi;\n\tconst _hasEscapedHtmlRe = new RegExp(_escapedHtmlRe.source, 'i'); // to drop the global flag\n\tconst _escapedHtmlMap   = Object.freeze({\n\t\t'&amp;'  : '&', // ampersand (HTML character entity, XML predefined entity)\n\t\t'&#38;'  : '&', // ampersand (decimal numeric character reference)\n\t\t'&#x26;' : '&', // ampersand (hexadecimal numeric character reference)\n\t\t'&lt;'   : '<', // less-than (HTML character entity, XML predefined entity)\n\t\t'&#60;'  : '<', // less-than (decimal numeric character reference)\n\t\t'&#x3c;' : '<', // less-than (hexadecimal numeric character reference)\n\t\t'&gt;'   : '>', // greater-than (HTML character entity, XML predefined entity)\n\t\t'&#62;'  : '>', // greater-than (decimal numeric character reference)\n\t\t'&#x3e;' : '>', // greater-than (hexadecimal numeric character reference)\n\t\t'&quot;' : '\"', // double quote (HTML character entity, XML predefined entity)\n\t\t'&#34;'  : '\"', // double quote (decimal numeric character reference)\n\t\t'&#x22;' : '\"', // double quote (hexadecimal numeric character reference)\n\t\t'&apos;' : \"'\", // apostrophe (XML predefined entity)\n\t\t'&#39;'  : \"'\", // apostrophe (decimal numeric character reference)\n\t\t'&#x27;' : \"'\", // apostrophe (hexadecimal numeric character reference)\n\t\t'&#96;'  : '`', // backquote (decimal numeric character reference)\n\t\t'&#x60;' : '`'  // backquote (hexadecimal numeric character reference)\n\t});\n\n\tfunction utilUnescape(str) {\n\t\tif (str == null) { // lazy equality for null\n\t\t\treturn '';\n\t\t}\n\n\t\tconst val = String(str);\n\t\treturn val && _hasEscapedHtmlRe.test(val)\n\t\t\t? val.replace(_escapedHtmlRe, entity => _escapedHtmlMap[entity.toLowerCase()])\n\t\t\t: val;\n\t}\n\n\t/*\n\t\tReturns an object (`{ char, start, end }`) containing the Unicode character at\n\t\tposition `pos`, its starting position, and its ending position—surrogate pairs\n\t\tare properly handled.  If `pos` is out-of-bounds, returns an object containing\n\t\tthe empty string and start/end positions of `-1`.\n\n\t\tThis function is necessary because JavaScript strings are sequences of UTF-16\n\t\tcode units, so surrogate pairs are exposed and thus must be handled.  While the\n\t\tES6/2015 standard does improve the situation somewhat, it does not alleviate\n\t\tthe need for this function.\n\n\t\tNOTE: Returns the individual code units of invalid surrogate pairs as-is.\n\n\t\tIDEA: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt\n\t*/\n\tfunction utilCharAndPosAt(text, position) {\n\t\tconst str  = String(text);\n\t\tconst pos  = Math.trunc(position);\n\t\tconst code = str.charCodeAt(pos);\n\n\t\t// Given position was out-of-bounds.\n\t\tif (Number.isNaN(code)) {\n\t\t\treturn { char : '', start : -1, end : -1 };\n\t\t}\n\n\t\tconst retval = {\n\t\t\tchar  : str.charAt(pos),\n\t\t\tstart : pos,\n\t\t\tend   : pos\n\t\t};\n\n\t\t// Code unit is not a UTF-16 surrogate.\n\t\tif (code < 0xD800 || code > 0xDFFF) {\n\t\t\treturn retval;\n\t\t}\n\n\t\t// Code unit is a high surrogate (D800–DBFF).\n\t\tif (code >= 0xD800 && code <= 0xDBFF) {\n\t\t\tconst nextPos = pos + 1;\n\n\t\t\t// End of string.\n\t\t\tif (nextPos >= str.length) {\n\t\t\t\treturn retval;\n\t\t\t}\n\n\t\t\tconst nextCode = str.charCodeAt(nextPos);\n\n\t\t\t// Next code unit is not a low surrogate (DC00–DFFF).\n\t\t\tif (nextCode < 0xDC00 || nextCode > 0xDFFF) {\n\t\t\t\treturn retval;\n\t\t\t}\n\n\t\t\tretval.char = retval.char + str.charAt(nextPos);\n\t\t\tretval.end = nextPos;\n\t\t\treturn retval;\n\t\t}\n\n\t\t// Code unit is a low surrogate (DC00–DFFF) in the first position.\n\t\tif (pos === 0) {\n\t\t\treturn retval;\n\t\t}\n\n\t\tconst prevPos  = pos - 1;\n\t\tconst prevCode = str.charCodeAt(prevPos);\n\n\t\t// Previous code unit is not a high surrogate (D800–DBFF).\n\t\tif (prevCode < 0xD800 || prevCode > 0xDBFF) {\n\t\t\treturn retval;\n\t\t}\n\n\t\tretval.char = str.charAt(prevPos) + retval.char;\n\t\tretval.start = prevPos;\n\t\treturn retval;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTime Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the number of milliseconds elapsed since a reference epoch.\n\n\t\tNOTE: Use the Performance API, if available, elsewise use Date as a\n\t\tfailover.  The Performance API is preferred for its monotonic clock—\n\t\tmeaning, it's not subject to the vagaries of timezone changes and leap\n\t\tperiods, as is Date.\n\t*/\n\tconst _nowSource = Has.performance ? performance : Date;\n\n\tfunction utilNow() {\n\t\treturn _nowSource.now();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tConversion Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the number of miliseconds represented by the passed CSS time string.\n\t*/\n\tconst _cssTimeRe = /^([+-]?(?:\\d*\\.)?\\d+)([Mm]?[Ss])$/;\n\n\tfunction utilFromCssTime(cssTime) {\n\t\tconst match = _cssTimeRe.exec(String(cssTime));\n\n\t\tif (match === null) {\n\t\t\tthrow new SyntaxError(`invalid time value syntax: \"${cssTime}\"`);\n\t\t}\n\n\t\tlet msec = Number(match[1]);\n\n\t\tif (match[2].length === 1) {\n\t\t\tmsec *= 1000;\n\t\t}\n\n\t\tif (Number.isNaN(msec) || !Number.isFinite(msec)) {\n\t\t\tthrow new RangeError(`invalid time value: \"${cssTime}\"`);\n\t\t}\n\n\t\treturn msec;\n\t}\n\n\t/*\n\t\tReturns the CSS time string represented by the passed number of milliseconds.\n\t*/\n\tfunction utilToCssTime(msec) {\n\t\tif (typeof msec !== 'number' || Number.isNaN(msec) || !Number.isFinite(msec)) {\n\t\t\tlet what;\n\n\t\t\tswitch (typeof msec) {\n\t\t\tcase 'string':\n\t\t\t\twhat = `\"${msec}\"`;\n\t\t\t\tbreak;\n\n\t\t\tcase 'number':\n\t\t\t\twhat = String(msec);\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\twhat = utilToStringTag(msec);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tthrow new Error(`invalid milliseconds: ${what}`);\n\t\t}\n\n\t\treturn `${msec}ms`;\n\t}\n\n\t/*\n\t\tReturns the DOM property name represented by the passed CSS property name.\n\t*/\n\tfunction utilFromCssProperty(cssName) {\n\t\tif (!cssName.includes('-')) {\n\t\t\tswitch (cssName) {\n\t\t\tcase 'bgcolor': return 'backgroundColor';\n\t\t\tcase 'float':   return 'cssFloat';\n\t\t\tdefault:        return cssName;\n\t\t\t}\n\t\t}\n\n\t\t// Strip the leading hyphen from the `-ms-` vendor prefix, so it stays lowercased.\n\t\tconst normalized = cssName.slice(0, 4) === '-ms-' ? cssName.slice(1) : cssName;\n\n\t\treturn normalized\n\t\t\t.split('-')\n\t\t\t.map((part, i) => i === 0 ? part : part.toUpperFirst())\n\t\t\t.join('');\n\t}\n\n\t/*\n\t\tReturns an object containing the component properties parsed from the passed URL.\n\t*/\n\tfunction utilParseUrl(url) {\n\t\tconst el       = document.createElement('a');\n\t\tconst queryObj = Object.create(null);\n\n\t\t// Let the `<a>` element parse the URL.\n\t\tel.href = url;\n\n\t\t// Populate the `queryObj` object with the query string attributes.\n\t\tif (el.search) {\n\t\t\tel.search\n\t\t\t\t.replace(/^\\?/, '')\n\t\t\t\t.splitOrEmpty(/(?:&(?:amp;)?|;)/)\n\t\t\t\t.forEach(query => {\n\t\t\t\t\tconst [key, value] = query.split('=');\n\t\t\t\t\tqueryObj[key] = value;\n\t\t\t\t});\n\t\t}\n\n\t\t/*\n\t\t\tCaveats by browser:\n\t\t\t\tEdge and Internet Explorer (≥8) do not support authentication\n\t\t\t\tinformation within a URL at all and will throw a security exception\n\t\t\t\ton *any* property access if it's included.\n\n\t\t\t\tInternet Explorer does not include the leading forward slash on\n\t\t\t\t`pathname` when required.\n\n\t\t\t\tOpera (Presto) strips the authentication information from `href`\n\t\t\t\tand does not supply `username` or `password`.\n\n\t\t\t\tSafari (ca. v5.1.x) does not supply `username` or `password` and\n\t\t\t\tpeforms URI decoding on `pathname`.\n\t\t*/\n\n\t\t// Patch for IE not including the leading slash on `pathname` when required.\n\t\tconst pathname = el.host && el.pathname[0] !== '/' ? `/${el.pathname}` : el.pathname;\n\n\t\treturn {\n\t\t\t// The full URL that was originally parsed.\n\t\t\thref : el.href,\n\n\t\t\t// The request protocol, lowercased.\n\t\t\tprotocol : el.protocol,\n\n\t\t\t// // The full authentication information.\n\t\t\t// auth : el.username || el.password // eslint-disable-line no-nested-ternary\n\t\t\t// \t? `${el.username}:${el.password}`\n\t\t\t// \t: typeof el.username === 'string' ? '' : undefined,\n\t\t\t//\n\t\t\t// // The username portion of the auth info.\n\t\t\t// username : el.username,\n\t\t\t//\n\t\t\t// // The password portion of the auth info.\n\t\t\t// password : el.password,\n\n\t\t\t// The full host information, including port number, lowercased.\n\t\t\thost : el.host,\n\n\t\t\t// The hostname portion of the host info, lowercased.\n\t\t\thostname : el.hostname,\n\n\t\t\t// The port number portion of the host info.\n\t\t\tport : el.port,\n\n\t\t\t// The full path information, including query info.\n\t\t\tpath : `${pathname}${el.search}`,\n\n\t\t\t// The pathname portion of the path info.\n\t\t\tpathname,\n\n\t\t\t// The query string portion of the path info, including the leading question mark.\n\t\t\tquery  : el.search,\n\t\t\tsearch : el.search,\n\n\t\t\t// The attributes portion of the query string, parsed into an object.\n\t\t\tqueries  : queryObj,\n\t\t\tsearches : queryObj,\n\n\t\t\t// The fragment string, including the leading hash/pound sign.\n\t\t\thash : el.hash\n\t\t};\n\t}\n\n\t/*\n\t\tReturns a new exception based on the given exception.\n\n\t\tNOTE: Mostly useful for making a standard JavaScript exception type copy\n\t\tof a host exception type—e.g. `DOMException` → `Error`.\n\t*/\n\tfunction utilNewExceptionFrom(original, exceptionType, override) {\n\t\tif (typeof original !== 'object' || original === null) {\n\t\t\tthrow new Error('Util.newExceptionFrom original parameter must be an object');\n\t\t}\n\t\tif (typeof exceptionType !== 'function') {\n\t\t\tthrow new Error('Util.newExceptionFrom exceptionType parameter must be an error type constructor');\n\t\t}\n\n\t\tconst ex = new exceptionType(original.message); // eslint-disable-line new-cap\n\n\t\tif (typeof original.name !== 'undefined') {\n\t\t\tex.name = original.name;\n\t\t}\n\t\tif (typeof original.code !== 'undefined') {\n\t\t\tex.code = original.code;\n\t\t}\n\t\tif (typeof original.columnNumber !== 'undefined') {\n\t\t\tex.columnNumber = original.columnNumber;\n\t\t}\n\t\tif (typeof original.description !== 'undefined') {\n\t\t\tex.description = original.description;\n\t\t}\n\t\tif (typeof original.fileName !== 'undefined') {\n\t\t\tex.fileName = original.fileName;\n\t\t}\n\t\tif (typeof original.lineNumber !== 'undefined') {\n\t\t\tex.lineNumber = original.lineNumber;\n\t\t}\n\t\tif (typeof original.number !== 'undefined') {\n\t\t\tex.number = original.number;\n\t\t}\n\t\tif (typeof original.stack !== 'undefined') {\n\t\t\tex.stack = original.stack;\n\t\t}\n\n\t\tconst overrideType = typeof override;\n\n\t\tif (overrideType !== 'undefined') {\n\t\t\tif (overrideType === 'object' && override !== null) {\n\t\t\t\tObject.assign(ex, override);\n\t\t\t}\n\t\t\telse if (overrideType === 'string') {\n\t\t\t\tex.message = override;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('Util.newExceptionFrom override parameter must be an object or string');\n\t\t\t}\n\t\t}\n\n\t\treturn ex;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tType Functions.\n\t\t*/\n\t\tgetType       : { value : utilGetType },\n\t\tisBoolean     : { value : utilIsBoolean },\n\t\tisIterable    : { value : utilIsIterable },\n\t\tisNumeric     : { value : utilIsNumeric },\n\t\tsameValueZero : { value : utilSameValueZero },\n\t\ttoEnum        : { value : utilToEnum },\n\t\ttoStringTag   : { value : utilToStringTag },\n\n\t\t/*\n\t\t\tString Encoding Functions.\n\t\t*/\n\t\tslugify      : { value : utilSlugify },\n\t\tescape       : { value : utilEscape },\n\t\tunescape     : { value : utilUnescape },\n\t\tcharAndPosAt : { value : utilCharAndPosAt },\n\n\t\t/*\n\t\t\tConversion Functions.\n\t\t*/\n\t\tfromCssTime      : { value : utilFromCssTime },\n\t\ttoCssTime        : { value : utilToCssTime },\n\t\tfromCssProperty  : { value : utilFromCssProperty },\n\t\tparseUrl         : { value : utilParseUrl },\n\t\tnewExceptionFrom : { value : utilNewExceptionFrom },\n\n\t\t/*\n\t\t\tTime Functions.\n\t\t*/\n\t\tnow : { value : utilNow },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\trandom         : { value : Math.random },\n\t\tentityEncode   : { value : utilEscape },\n\t\tentityDecode   : { value : utilUnescape },\n\t\tevalExpression : { value : (...args) => Scripting.evalJavaScript(...args) }, // SEE: `markup/scripting.js`.\n\t\tevalStatements : { value : (...args) => Scripting.evalJavaScript(...args) }  // SEE: `markup/scripting.js`.\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/simplestore.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar SimpleStore = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// In-order list of database adapters.\n\tconst _adapters = [];\n\n\t// The initialized adapter.\n\tlet _initialized = null;\n\n\n\t/*******************************************************************************************************************\n\t\tSimpleStore Functions.\n\t*******************************************************************************************************************/\n\tfunction storeCreate(storageId, persistent) {\n\t\tif (_initialized) {\n\t\t\treturn _initialized.create(storageId, persistent);\n\t\t}\n\n\t\t// Return the first adapter which successfully initializes, elsewise throw an exception.\n\t\tfor (let i = 0; i < _adapters.length; ++i) {\n\t\t\tif (_adapters[i].init(storageId, persistent)) {\n\t\t\t\t_initialized = _adapters[i];\n\t\t\t\treturn _initialized.create(storageId, persistent);\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error('no valid storage adapters found');\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tAdapters List.\n\n\t\t\tTODO: This should probably have a getter, rather than being exported directly.\n\t\t*/\n\t\tadapters : { value : _adapters },\n\n\t\t/*\n\t\t\tCore Functions.\n\t\t*/\n\t\tcreate : { value : storeCreate }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/FCHost.Storage.js\n\n\tCopyright © 2013–2019 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_FCHostStorageAdapter Class.\n        Note that FCHost is only intended for a single document, so we ignore both prefixing and storageID\n\t*******************************************************************************************************************/\n\tclass _FCHostStorageAdapter {\n\t\tconstructor(persistent) {\n\t\t\tlet engine = null;\n\t\t\tlet name   = null;\n\n\t\t\tif (persistent) {\n\t\t\t\tengine = window.FCHostPersistent;\n\t\t\t\tname   = 'FCHostPersistent';\n\t\t\t}\n\t\t\telse {\n\t\t\t    engine = window.FCHostSession;\n\t\t\t\tname   = 'FCHostSession';\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_engine : {\n\t\t\t\t\tvalue : engine\n\t\t\t\t},\n                \n\t\t\t\tname : {\n\t\t\t\t\tvalue : name\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\treturn this._engine.size();\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\treturn this._engine.size();\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\treturn this._engine.keys();\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn this._engine.has(key);\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = this._engine.get(key);\n\n\t\t\treturn value == null ? null : _FCHostStorageAdapter._deserialize(value); // lazy equality for null\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.set(key, _FCHostStorageAdapter._serialize(value));\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.remove(key);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tthis._engine.clear();\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn JSON.stringify(obj);\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse(str);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit() {\n\t\t// FCHost feature test.\n\t\tfunction hasFCHostStorage() {\n\t\t\ttry {\n\t\t\t    if (typeof window.FCHostPersistent !== 'undefined')\n\t\t\t        return true;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn false;\n\t\t}\n\n\t\t_ok = hasFCHostStorage();\n\t\t\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _FCHostStorageAdapter(persistent);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/webstorage.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_WebStorageAdapter Class.\n\t*******************************************************************************************************************/\n\tclass _WebStorageAdapter {\n\t\tconstructor(storageId, persistent) {\n\t\t\tconst prefix = `${storageId}.`;\n\t\t\tlet engine = null;\n\t\t\tlet name   = null;\n\n\t\t\tif (persistent) {\n\t\t\t\tengine = window.localStorage;\n\t\t\t\tname   = 'localStorage';\n\t\t\t}\n\t\t\telse {\n\t\t\t\tengine = window.sessionStorage;\n\t\t\t\tname   = 'sessionStorage';\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_engine : {\n\t\t\t\t\tvalue : engine\n\t\t\t\t},\n\n\t\t\t\t_prefix : {\n\t\t\t\t\tvalue : prefix\n\t\t\t\t},\n\n\t\t\t\t_prefixRe : {\n\t\t\t\t\tvalue : new RegExp(`^${RegExp.escape(prefix)}`)\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : name\n\t\t\t\t},\n\n\t\t\t\tid : {\n\t\t\t\t\tvalue : storageId\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\t/*\n\t\t\t\tNOTE: DO NOT do something like `return this._engine.length;` here,\n\t\t\t\tas that will return the length of the entire store, rather than\n\t\t\t\tjust our prefixed keys.\n\t\t\t*/\n\t\t\treturn this.keys().length;\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\t/*\n\t\t\t\tNOTE: DO NOT do something like `return this._engine.length;` here,\n\t\t\t\tas that will return the length of the entire store, rather than\n\t\t\t\tjust our prefixed keys.\n\t\t\t*/\n\t\t\treturn this.keys().length;\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\tconst keys = [];\n\n\t\t\tfor (let i = 0; i < this._engine.length; ++i) {\n\t\t\t\tconst key = this._engine.key(i);\n\n\t\t\t\tif (this._prefixRe.test(key)) {\n\t\t\t\t\tkeys.push(key.replace(this._prefixRe, ''));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn keys;\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// // FIXME: This method should probably check for the key, rather than comparing its value.\n\t\t\t// return this._engine.getItem(this._prefix + key) != null; // lazy equality for null\n\n\t\t\treturn this._engine.hasOwnProperty(this._prefix + key);\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = this._engine.getItem(this._prefix + key);\n\n\t\t\treturn value == null ? null : _WebStorageAdapter._deserialize(value); // lazy equality for null\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tthis._engine.setItem(this._prefix + key, _WebStorageAdapter._serialize(value));\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t/*\n\t\t\t\t\tIf the exception is a quota exceeded error, massage it into something\n\t\t\t\t\ta bit nicer for the player.\n\n\t\t\t\t\tNOTE: Ideally, we could simply do something like checking `ex.code`, but\n\t\t\t\t\tit's a non-standard property and not supported in all browsers.  Thus,\n\t\t\t\t\twe have to resort to pattern matching the name and message—the latter being\n\t\t\t\t\trequired by Opera (Presto).  I hate the parties responsible for this snafu\n\t\t\t\t\tso much.\n\t\t\t\t*/\n\t\t\t\tif (/quota.?(?:exceeded|reached)/i.test(ex.name + ex.message)) {\n\t\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `${this.name} quota exceeded`);\n\t\t\t\t}\n\n\t\t\t\tthrow ex;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.removeItem(this._prefix + key);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tconst keys = this.keys();\n\n\t\t\tfor (let i = 0, iend = keys.length; i < iend; ++i) {\n\t\t\t\tif (DEBUG) { console.log('\\tdeleting key:', keys[i]); }\n\n\t\t\t\tthis.delete(keys[i]);\n\t\t\t}\n\n\t\t\t// return this.keys().forEach(key => {\n\t\t\t// \tif (DEBUG) { console.log('\\tdeleting key:', key); }\n\t\t\t//\n\t\t\t// \tthis.delete(key);\n\t\t\t// });\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn JSON.stringify(obj);\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse((!str || str[0] == \"{\") ? str : LZString.decompressFromUTF16(str));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit() {\n\t\t// Web Storage feature test.\n\t\tfunction hasWebStorage(storeId) {\n\t\t\ttry {\n\t\t\t\tconst store = window[storeId];\n\t\t\t\tconst tid   = `_sc_${String(Date.now())}`;\n\t\t\t\tstore.setItem(tid, tid);\n\t\t\t\tconst result = store.getItem(tid) === tid;\n\t\t\t\tstore.removeItem(tid);\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn false;\n\t\t}\n\n\t\t/*\n\t\t\tJust to be safe, we feature test for both `localStorage` and `sessionStorage`,\n\t\t\tas you never know what browser implementation bugs you're going to run into.\n\t\t*/\n\t\t_ok = hasWebStorage('localStorage') && hasWebStorage('sessionStorage');\n\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _WebStorageAdapter(storageId, persistent);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/cookie.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Expiry constants.\n\tconst _MAX_EXPIRY = 'Tue, 19 Jan 2038 03:14:07 GMT'; // (new Date((Math.pow(2, 31) - 1) * 1000)).toUTCString()\n\tconst _MIN_EXPIRY = 'Thu, 01 Jan 1970 00:00:00 GMT'; // (new Date(0)).toUTCString()\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_CookieAdapter Class.\n\t*******************************************************************************************************************/\n\tclass _CookieAdapter {\n\t\tconstructor(storageId, persistent) {\n\t\t\tconst prefix = `${storageId}${persistent ? '!' : '*'}.`;\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_prefix : {\n\t\t\t\t\tvalue : prefix\n\t\t\t\t},\n\n\t\t\t\t_prefixRe : {\n\t\t\t\t\tvalue : new RegExp(`^${RegExp.escape(prefix)}`)\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : 'cookie'\n\t\t\t\t},\n\n\t\t\t\tid : {\n\t\t\t\t\tvalue : storageId\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\treturn this.keys().length;\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\treturn this.keys().length;\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\tif (document.cookie === '') {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst cookies = document.cookie.split(/;\\s*/);\n\t\t\tconst keys    = [];\n\n\t\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\t\tif (this._prefixRe.test(key)) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\t\tnot a serialized empty string, so we should omit such pairs.\n\t\t\t\t\t*/\n\t\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\t\tif (value !== '') {\n\t\t\t\t\t\tkeys.push(key.replace(this._prefixRe, ''));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn keys;\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn _CookieAdapter._getCookie(this._prefix + key) !== null;\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = _CookieAdapter._getCookie(this._prefix + key);\n\n\t\t\treturn value === null ? null : _CookieAdapter._deserialize(value);\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\tthis._prefix + key,\n\t\t\t\t\t_CookieAdapter._serialize(value),\n\n\t\t\t\t\t// An undefined expiry denotes a session cookie.\n\t\t\t\t\tthis.persistent ? _MAX_EXPIRY : undefined\n\t\t\t\t);\n\n\t\t\t\tif (!this.has(key)) {\n\t\t\t\t\tthrow new Error('unknown validation error during set');\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t// Massage the cookie exception into something a bit nicer for the player.\n\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `cookie error: ${ex.message}`);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\t/*\n\t\t\t\tAttempting to delete a cookie implies setting it, so we test for its existence\n\t\t\t\tbeforehand, to avoid creating it in the event that it does not already exist.\n\t\t\t*/\n\t\t\tif (typeof key !== 'string' || !key || !this.has(key)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\tthis._prefix + key,\n\n\t\t\t\t\t// Use `undefined` as the value.\n\t\t\t\t\tundefined,\n\n\t\t\t\t\t// Use the epoch as the expiry.\n\t\t\t\t\t_MIN_EXPIRY\n\t\t\t\t);\n\n\t\t\t\tif (this.has(key)) {\n\t\t\t\t\tthrow new Error('unknown validation error during delete');\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t// Massage the cookie exception into something a bit nicer for the player.\n\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `cookie error: ${ex.message}`);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tconst keys = this.keys();\n\n\t\t\tfor (let i = 0, iend = keys.length; i < iend; ++i) {\n\t\t\t\tif (DEBUG) { console.log('\\tdeleting key:', keys[i]); }\n\n\t\t\t\tthis.delete(keys[i]);\n\t\t\t}\n\n\t\t\t// this.keys().forEach(key => {\n\t\t\t// \tif (DEBUG) { console.log('\\tdeleting key:', key); }\n\t\t\t//\n\t\t\t// \tthis.delete(key);\n\t\t\t// });\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _getCookie(prefixedKey) {\n\t\t\tif (!prefixedKey || document.cookie === '') {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst cookies = document.cookie.split(/;\\s*/);\n\n\t\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\t\tif (prefixedKey === key) {\n\t\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\t\tnot a serialized empty string, so we should yield `null` for such pairs.\n\t\t\t\t\t*/\n\t\t\t\t\treturn value || null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tstatic _setCookie(prefixedKey, value, expiry) {\n\t\t\tif (!prefixedKey) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet payload = `${encodeURIComponent(prefixedKey)}=`;\n\n\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\tpayload += encodeURIComponent(value);\n\t\t\t}\n\n\t\t\tif (expiry != null) { // lazy equality for null\n\t\t\t\tpayload += `; expires=${expiry}`;\n\t\t\t}\n\n\t\t\tpayload += '; path=/';\n\t\t\tdocument.cookie = payload;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn LZString.compressToBase64(JSON.stringify(obj));\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse(LZString.decompressFromBase64(str));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit(\n\t\t// Only used for stores updates.\n\t\tstorageId\n\t) {\n\t\t// Cookie feature test.\n\t\ttry {\n\t\t\tconst tid = `_sc_${String(Date.now())}`;\n\n\t\t\t// We only test a session cookie as that should suffice.\n\t\t\t_CookieAdapter._setCookie(tid, _CookieAdapter._serialize(tid), undefined);\n\t\t\t_ok = _CookieAdapter._deserialize(_CookieAdapter._getCookie(tid)) === tid;\n\t\t\t_CookieAdapter._setCookie(tid, undefined, _MIN_EXPIRY);\n\t\t}\n\t\tcatch (ex) {\n\t\t\t_ok = false;\n\t\t}\n\n\t\t/* legacy */\n\t\t// Attempt to update the cookie stores, if necessary.  This should happen only during initialization.\n\t\tif (_ok) {\n\t\t\t_updateCookieStores(storageId);\n\t\t}\n\t\t/* /legacy */\n\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _CookieAdapter(storageId, persistent);\n\t}\n\n\t/* legacy */\n\t// Updates old non-segmented cookie stores into segmented stores.\n\tfunction _updateCookieStores(storageId) {\n\t\tif (document.cookie === '') {\n\t\t\treturn;\n\t\t}\n\n\t\tconst oldPrefix     = `${storageId}.`;\n\t\tconst oldPrefixRe   = new RegExp(`^${RegExp.escape(oldPrefix)}`);\n\t\tconst persistPrefix = `${storageId}!.`;\n\t\tconst sessionPrefix = `${storageId}*.`;\n\t\tconst sessionTestRe = /\\.(?:state|rcWarn)$/;\n\t\tconst cookies       = document.cookie.split(/;\\s*/);\n\n\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\tif (oldPrefixRe.test(key)) {\n\t\t\t\t/*\n\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\tnot a serialized empty string, so we should skip processing such pairs.\n\t\t\t\t*/\n\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\tif (value !== '') {\n\t\t\t\t\tconst persist = !sessionTestRe.test(key);\n\n\t\t\t\t\t// Delete the old k/v pair.\n\t\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t_MIN_EXPIRY\n\t\t\t\t\t);\n\n\t\t\t\t\t// Set the new k/v pair.\n\t\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\t\tkey.replace(oldPrefixRe, () => persist ? persistPrefix : sessionPrefix),\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tpersist ? _MAX_EXPIRY : undefined\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t/* /legacy */\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/debugview.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tTODO: Make this use jQuery throughout.\n*/\nvar DebugView = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tDebugView Class.\n\t*******************************************************************************************************************/\n\tclass DebugView {\n\t\tconstructor(parent, type, name, title) {\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tparent : {\n\t\t\t\t\tvalue : parent\n\t\t\t\t},\n\n\t\t\t\tview : {\n\t\t\t\t\tvalue : document.createElement('span')\n\t\t\t\t},\n\n\t\t\t\tbreak : {\n\t\t\t\t\tvalue : document.createElement('wbr')\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Set up the wrapper (`<span>`) element.\n\t\t\tjQuery(this.view)\n\t\t\t\t.attr({\n\t\t\t\t\ttitle,\n\t\t\t\t\t'aria-label' : title,\n\t\t\t\t\t'data-type'  : type != null ? type : '', // lazy equality for null\n\t\t\t\t\t'data-name'  : name != null ? name : ''  // lazy equality for null\n\t\t\t\t})\n\t\t\t\t.addClass('debug');\n\n\t\t\t// Set up the word break (`<wbr>`) element.\n\t\t\tjQuery(this.break).addClass('debug hidden');\n\n\t\t\t// Add the wrapper (`<span>`) and word break (`<wbr>`) elements to the `parent` element.\n\t\t\tthis.parent.appendChild(this.view);\n\t\t\tthis.parent.appendChild(this.break);\n\t\t}\n\n\t\tget output() {\n\t\t\treturn this.view;\n\t\t}\n\n\t\tget type() {\n\t\t\treturn this.view.getAttribute('data-type');\n\t\t}\n\t\tset type(type) {\n\t\t\tthis.view.setAttribute('data-type', type != null ? type : ''); // lazy equality for null\n\t\t}\n\n\t\tget name() {\n\t\t\treturn this.view.getAttribute('data-name');\n\t\t}\n\t\tset name(name) {\n\t\t\tthis.view.setAttribute('data-name', name != null ? name : ''); // lazy equality for null\n\t\t}\n\n\t\tget title() {\n\t\t\treturn this.view.title;\n\t\t}\n\t\tset title(title) {\n\t\t\tthis.view.title = title;\n\t\t}\n\n\t\tappend(el) {\n\t\t\tjQuery(this.view).append(el);\n\t\t\treturn this;\n\t\t}\n\n\t\tmodes(options) {\n\t\t\tif (options == null) { // lazy equality for null\n\t\t\t\tconst current = {};\n\n\t\t\t\tthis.view.className.splitOrEmpty(/\\s+/).forEach(name => {\n\t\t\t\t\tif (name !== 'debug') {\n\t\t\t\t\t\tcurrent[name] = true;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\treturn current;\n\t\t\t}\n\t\t\telse if (typeof options === 'object') {\n\t\t\t\tObject.keys(options).forEach(function (name) {\n\t\t\t\t\tthis[options[name] ? 'addClass' : 'removeClass'](name);\n\t\t\t\t}, jQuery(this.view));\n\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tthrow new Error('DebugView.prototype.modes options parameter must be an object or null/undefined');\n\t\t}\n\n\t\tremove() {\n\t\t\tconst $view = jQuery(this.view);\n\n\t\t\tif (this.view.hasChildNodes()) {\n\t\t\t\t$view.contents().appendTo(this.parent);\n\t\t\t}\n\n\t\t\t$view.remove();\n\t\t\tjQuery(this.break).remove();\n\t\t}\n\n\t\tstatic isEnabled() {\n\t\t\treturn jQuery(document.documentElement).attr('data-debug-view') === 'enabled';\n\t\t}\n\n\t\tstatic enable() {\n\t\t\tjQuery(document.documentElement).attr('data-debug-view', 'enabled');\n\t\t\tjQuery.event.trigger(':debugviewupdate');\n\t\t}\n\n\t\tstatic disable() {\n\t\t\tjQuery(document.documentElement).removeAttr('data-debug-view');\n\t\t\tjQuery.event.trigger(':debugviewupdate');\n\t\t}\n\n\t\tstatic toggle() {\n\t\t\tif (jQuery(document.documentElement).attr('data-debug-view') === 'enabled') {\n\t\t\t\tDebugView.disable();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tDebugView.enable();\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn DebugView;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/prngwrapper.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar PRNGWrapper = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tPRNGWrapper Class.\n\t*******************************************************************************************************************/\n\tclass PRNGWrapper {\n\t\tconstructor(seed, useEntropy) {\n\t\t\t/* eslint-disable new-cap */\n\t\t\tObject.defineProperties(this, new Math.seedrandom(seed, useEntropy, (prng, seed) => ({\n\t\t\t\t_prng : {\n\t\t\t\t\tvalue : prng\n\t\t\t\t},\n\n\t\t\t\tseed : {\n\t\t\t\t\t/*\n\t\t\t\t\t\tTODO: Make this non-writable.\n\t\t\t\t\t*/\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : seed\n\t\t\t\t},\n\n\t\t\t\tpull : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\trandom : {\n\t\t\t\t\tvalue() {\n\t\t\t\t\t\t++this.pull;\n\t\t\t\t\t\treturn this._prng();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})));\n\t\t\t/* eslint-enable new-cap */\n\t\t}\n\n\t\tstatic marshal(prng) {\n\t\t\tif (!prng || !prng.hasOwnProperty('seed') || !prng.hasOwnProperty('pull')) {\n\t\t\t\tthrow new Error('PRNG is missing required data');\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tseed : prng.seed,\n\t\t\t\tpull : prng.pull\n\t\t\t};\n\t\t}\n\n\t\tstatic unmarshal(prngObj) {\n\t\t\tif (!prngObj || !prngObj.hasOwnProperty('seed') || !prngObj.hasOwnProperty('pull')) {\n\t\t\t\tthrow new Error('PRNG object is missing required data');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tCreate a new PRNG using the original seed and pull values from it until it\n\t\t\t\thas reached the original pull count.\n\t\t\t*/\n\t\t\tconst prng = new PRNGWrapper(prngObj.seed, false);\n\n\t\t\tfor (let i = prngObj.pull; i > 0; --i) {\n\t\t\t\tprng.random();\n\t\t\t}\n\n\t\t\treturn prng;\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn PRNGWrapper;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/stylewrapper.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns, Story, Wikifier */\n\nvar StyleWrapper = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tconst _imageMarkupRe    = new RegExp(Patterns.cssImage, 'g');\n\tconst _hasImageMarkupRe = new RegExp(Patterns.cssImage);\n\n\n\t/*******************************************************************************************************************\n\t\tStyleWrapper Class.\n\t*******************************************************************************************************************/\n\tclass StyleWrapper {\n\t\tconstructor(style) {\n\t\t\tif (style == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('StyleWrapper style parameter must be an HTMLStyleElement object');\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tstyle : {\n\t\t\t\t\tvalue : style\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tisEmpty() {\n\t\t\t// This should work in all supported browsers.\n\t\t\treturn this.style.cssRules.length === 0;\n\t\t}\n\n\t\tset(rawCss) {\n\t\t\tthis.clear();\n\t\t\tthis.add(rawCss);\n\t\t}\n\n\t\tadd(rawCss) {\n\t\t\tlet css = rawCss;\n\n\t\t\t// Check for wiki image transclusion.\n\t\t\tif (_hasImageMarkupRe.test(css)) {\n\t\t\t\t/*\n\t\t\t\t\tThe JavaScript specifications, since at least ES3, say that `<String>.replace()`\n\t\t\t\t\tshould reset a global-flagged regular expression's `lastIndex` property to `0`\n\t\t\t\t\tupon invocation.  Buggy browser versions exist, however, which do not reset\n\t\t\t\t\t`lastIndex`, so we should do so manually to support those browsers.\n\n\t\t\t\t\tNOTE: I do not think this is actually necessary, since `_imageMarkupRe` is\n\t\t\t\t\tscoped to this module—meaning users should not be able to access it.  That\n\t\t\t\t\tbeing the case, and since we search to exhaustion which should also cause\n\t\t\t\t\t`lastIndex` to be reset, there should never be an instance where we invoke\n\t\t\t\t\t`css.replace()` and `_imageMarkupRe.lastIndex` is not already `0`.  Still,\n\t\t\t\t\tconsidering the other bug, better safe than sorry.\n\t\t\t\t*/\n\t\t\t\t_imageMarkupRe.lastIndex = 0;\n\n\t\t\t\tcss = css.replace(_imageMarkupRe, wikiImage => {\n\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\tsource     : wikiImage,\n\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t});\n\n\t\t\t\t\tif (markup.hasOwnProperty('error') || markup.pos < wikiImage.length) {\n\t\t\t\t\t\treturn wikiImage;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet source = markup.source;\n\n\t\t\t\t\t// Handle image passage transclusion.\n\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\tsource = passage.text.trim();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tThe source may be URI- or Base64-encoded, so we cannot use `encodeURIComponent()`\n\t\t\t\t\t\there.  Instead, we simply encode any double quotes, since the URI will be\n\t\t\t\t\t\tdelimited by them.\n\t\t\t\t\t*/\n\t\t\t\t\treturn `url(\"${source.replace(/\"/g, '%22')}\")`;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// For IE ≤ 10.\n\t\t\tif (this.style.styleSheet) {\n\t\t\t\tthis.style.styleSheet.cssText += css;\n\t\t\t}\n\n\t\t\t// For all other browsers (incl. IE ≥ 11).\n\t\t\telse {\n\t\t\t\tthis.style.appendChild(document.createTextNode(css));\n\t\t\t}\n\t\t}\n\n\t\tclear() {\n\t\t\t// For IE ≤10.\n\t\t\tif (this.style.styleSheet) {\n\t\t\t\tthis.style.styleSheet.cssText = '';\n\t\t\t}\n\n\t\t\t// For all other browsers (incl. IE ≥11).\n\t\t\telse {\n\t\t\t\tjQuery(this.style).empty();\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn StyleWrapper;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/diff.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util, clone */\n\nvar Diff = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tDiff Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tDiff operations object (pseudo-enumeration).\n\t*/\n\tconst Op = Util.toEnum({\n\t\tDelete      : 0,\n\t\tSpliceArray : 1,\n\t\tCopy        : 2,\n\t\tCopyDate    : 3\n\t});\n\n\t/*\n\t\tReturns a difference object generated from comparing the the orig and dest objects.\n\t*/\n\tfunction diff(orig, dest) /* diff object */ {\n\t\tconst objToString = Object.prototype.toString;\n\t\tconst origIsArray = orig instanceof Array;\n\t\tconst keys        = []\n\t\t\t.concat(Object.keys(orig), Object.keys(dest))\n\t\t\t.sort()\n\t\t\t.filter((val, i, arr) => i === 0 || arr[i - 1] !== val);\n\t\tconst diffed      = {};\n\t\tlet aOpRef;\n\n\t\tconst keyIsAOpRef = key => key === aOpRef;\n\n\t\t/* eslint-disable max-depth */\n\t\tfor (let i = 0, klen = keys.length; i < klen; ++i) {\n\t\t\tconst key   = keys[i];\n\t\t\tconst origP = orig[key];\n\t\t\tconst destP = dest[key];\n\n\t\t\tif (orig.hasOwnProperty(key)) {\n\t\t\t\t// Key exists in both.\n\t\t\t\tif (dest.hasOwnProperty(key)) {\n\t\t\t\t\t// Values are exactly the same, so do nothing.\n\t\t\t\t\tif (origP === destP) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Values are of the same basic type.\n\t\t\t\t\tif (typeof origP === typeof destP) { // eslint-disable-line valid-typeof\n\t\t\t\t\t\t// Values are functions.\n\t\t\t\t\t\tif (typeof origP === 'function') {\n\t\t\t\t\t\t\t/* diffed[key] = [Op.Copy, destP]; */\n\t\t\t\t\t\t\tif (origP.toString() !== destP.toString()) {\n\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, destP];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Values are primitives.\n\t\t\t\t\t\telse if (typeof origP !== 'object' || origP === null) {\n\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, destP];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Values are objects.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst origPType = objToString.call(origP);\n\t\t\t\t\t\t\tconst destPType = objToString.call(destP);\n\n\t\t\t\t\t\t\t// Values are objects of the same reported type.\n\t\t\t\t\t\t\tif (origPType === destPType) {\n\t\t\t\t\t\t\t\t// Various special cases to handle supported non-generic objects.\n\t\t\t\t\t\t\t\tif (origP instanceof Date) {\n\t\t\t\t\t\t\t\t\tif (Number(origP) !== Number(destP)) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof Map) {\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof RegExp) {\n\t\t\t\t\t\t\t\t\tif (origP.toString() !== destP.toString()) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof Set) {\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Unknown non-generic objects (custom or unsupported natives).\n\t\t\t\t\t\t\t\telse if (origPType !== '[object Object]') {\n\t\t\t\t\t\t\t\t\t// We cannot know how to process these objects,\n\t\t\t\t\t\t\t\t\t// so we simply accept them as-is.\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Generic objects.\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tconst recurse = diff(origP, destP);\n\n\t\t\t\t\t\t\t\t\tif (recurse !== null) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = recurse;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Values are objects of different reported types.\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Values are of different types.\n\t\t\t\t\telse {\n\t\t\t\t\t\tdiffed[key] = [\n\t\t\t\t\t\t\tOp.Copy,\n\t\t\t\t\t\t\ttypeof destP !== 'object' || destP === null ? destP : clone(destP)\n\t\t\t\t\t\t];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Key only exists in orig.\n\t\t\t\telse {\n\t\t\t\t\tif (origIsArray && Util.isNumeric(key)) {\n\t\t\t\t\t\tconst nKey = Number(key);\n\n\t\t\t\t\t\tif (!aOpRef) {\n\t\t\t\t\t\t\taOpRef = '';\n\n\t\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\t\taOpRef += '~';\n\t\t\t\t\t\t\t} while (keys.some(keyIsAOpRef));\n\n\t\t\t\t\t\t\tdiffed[aOpRef] = [Op.SpliceArray, nKey, nKey];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (nKey < diffed[aOpRef][1]) {\n\t\t\t\t\t\t\tdiffed[aOpRef][1] = nKey;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (nKey > diffed[aOpRef][2]) {\n\t\t\t\t\t\t\tdiffed[aOpRef][2] = nKey;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdiffed[key] = Op.Delete;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Key only exists in dest.\n\t\t\telse {\n\t\t\t\tdiffed[key] = [\n\t\t\t\t\tOp.Copy,\n\t\t\t\t\ttypeof destP !== 'object' || destP === null ? destP : clone(destP)\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\t\t/* eslint-enable max-depth */\n\n\t\treturn Object.keys(diffed).length > 0 ? diffed : null;\n\t}\n\n\t/*\n\t\tReturns the object resulting from updating the orig object with the diffed object.\n\t*/\n\tfunction patch(orig, diffed) /* patched object */ {\n\t\tconst keys    = Object.keys(diffed || {});\n\t\tconst patched = clone(orig);\n\n\t\tfor (let i = 0, klen = keys.length; i < klen; ++i) {\n\t\t\tconst key     = keys[i];\n\t\t\tconst diffedP = diffed[key];\n\n\t\t\tif (diffedP === Op.Delete) {\n\t\t\t\tdelete patched[key];\n\t\t\t}\n\t\t\telse if (diffedP instanceof Array) {\n\t\t\t\tswitch (diffedP[0]) {\n\t\t\t\tcase Op.SpliceArray:\n\t\t\t\t\tpatched.splice(diffedP[1], 1 + (diffedP[2] - diffedP[1]));\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase Op.Copy:\n\t\t\t\t\tpatched[key] = clone(diffedP[1]);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase Op.CopyDate:\n\t\t\t\t\tpatched[key] = new Date(diffedP[1]);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tpatched[key] = patch(patched[key], diffedP);\n\t\t\t}\n\t\t}\n\n\t\treturn patched;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tOp    : { value : Op },\n\t\tdiff  : { value : diff },\n\t\tpatch : { value : patch }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tl10n/l10n.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global l10nStrings, strings */\n\nvar L10n = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Replacement pattern regular expressions.\n\tconst _patternRe    = /\\{\\w+\\}/g;\n\tconst _hasPatternRe = new RegExp(_patternRe.source); // to drop the global flag\n\n\n\t/*******************************************************************************************************************\n\t\tLocalization Functions.\n\t*******************************************************************************************************************/\n\tfunction l10nInit() {\n\t\t/* legacy */\n\t\t_mapStringsToL10nStrings();\n\t\t/* /legacy */\n\t}\n\n\t/*******************************************************************************************************************\n\t\tLocalized String Functions.\n\t*******************************************************************************************************************/\n\tfunction l10nGet(ids, overrides) {\n\t\tif (!ids) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst id = (idList => {\n\t\t\tlet selectedId;\n\t\t\tidList.some(id => {\n\t\t\t\tif (l10nStrings.hasOwnProperty(id)) {\n\t\t\t\t\tselectedId = id;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\treturn selectedId;\n\t\t})(Array.isArray(ids) ? ids : [ids]);\n\n\t\tif (!id) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst maxIterations = 50;\n\t\tlet processed = l10nStrings[id];\n\t\tlet iteration = 0;\n\n\t\twhile (_hasPatternRe.test(processed)) {\n\t\t\tif (++iteration > maxIterations) {\n\t\t\t\tthrow new Error('L10n.get exceeded maximum replacement iterations, probable infinite loop');\n\t\t\t}\n\n\t\t\t// Possibly required by some old buggy browsers.\n\t\t\t_patternRe.lastIndex = 0;\n\n\t\t\tprocessed = processed.replace(_patternRe, pat => {\n\t\t\t\tconst subId = pat.slice(1, -1);\n\n\t\t\t\tif (overrides && overrides.hasOwnProperty(subId)) {\n\t\t\t\t\treturn overrides[subId];\n\t\t\t\t}\n\t\t\t\telse if (l10nStrings.hasOwnProperty(subId)) {\n\t\t\t\t\treturn l10nStrings[subId];\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treturn processed;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tLegacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tAttempt to map legacy `strings` object properties to the `l10nStrings` object.\n\t*/\n\tfunction _mapStringsToL10nStrings() {\n\t\tif (strings && Object.keys(strings).length > 0) {\n\t\t\tObject.keys(l10nStrings).forEach(id => {\n\t\t\t\ttry {\n\t\t\t\t\tlet value;\n\n\t\t\t\t\tswitch (id) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tGeneral.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'identity': value = strings.identity; break;\n\t\t\t\t\tcase 'aborting': value = strings.aborting; break;\n\t\t\t\t\tcase 'cancel':   value = strings.cancel; break;\n\t\t\t\t\tcase 'close':    value = strings.close; break;\n\t\t\t\t\tcase 'ok':       value = strings.ok; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tErrors.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'errorTitle':              value = strings.errors.title; break;\n\t\t\t\t\tcase 'errorNonexistentPassage': value = strings.errors.nonexistentPassage; break;\n\t\t\t\t\tcase 'errorSaveMissingData':    value = strings.errors.saveMissingData; break;\n\t\t\t\t\tcase 'errorSaveIdMismatch':     value = strings.errors.saveIdMismatch; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tWarnings.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'warningDegraded': value = strings.warnings.degraded; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tDebug View.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'debugViewTitle':  value = strings.debugView.title; break;\n\t\t\t\t\tcase 'debugViewToggle': value = strings.debugView.toggle; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tUI bar.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'uiBarToggle':   value = strings.uiBar.toggle; break;\n\t\t\t\t\tcase 'uiBarBackward': value = strings.uiBar.backward; break;\n\t\t\t\t\tcase 'uiBarForward':  value = strings.uiBar.forward; break;\n\t\t\t\t\tcase 'uiBarJumpto':   value = strings.uiBar.jumpto; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tJump To.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'jumptoTitle':       value = strings.jumpto.title; break;\n\t\t\t\t\tcase 'jumptoTurn':        value = strings.jumpto.turn; break;\n\t\t\t\t\tcase 'jumptoUnavailable': value = strings.jumpto.unavailable; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tSaves.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'savesTitle':       value = strings.saves.title; break;\n\t\t\t\t\tcase 'savesDisallowed':  value = strings.saves.disallowed; break;\n\t\t\t\t\tcase 'savesIncapable':   value = strings.saves.incapable; break;\n\t\t\t\t\tcase 'savesLabelAuto':   value = strings.saves.labelAuto; break;\n\t\t\t\t\tcase 'savesLabelDelete': value = strings.saves.labelDelete; break;\n\t\t\t\t\tcase 'savesLabelExport': value = strings.saves.labelExport; break;\n\t\t\t\t\tcase 'savesLabelImport': value = strings.saves.labelImport; break;\n\t\t\t\t\tcase 'savesLabelLoad':   value = strings.saves.labelLoad; break;\n\t\t\t\t\tcase 'savesLabelClear':  value = strings.saves.labelClear; break;\n\t\t\t\t\tcase 'savesLabelSave':   value = strings.saves.labelSave; break;\n\t\t\t\t\tcase 'savesLabelSlot':   value = strings.saves.labelSlot; break;\n\t\t\t\t\tcase 'savesUnavailable': value = strings.saves.unavailable; break;\n\t\t\t\t\tcase 'savesUnknownDate': value = strings.saves.unknownDate; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tSettings.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'settingsTitle': value = strings.settings.title; break;\n\t\t\t\t\tcase 'settingsOff':   value = strings.settings.off; break;\n\t\t\t\t\tcase 'settingsOn':    value = strings.settings.on; break;\n\t\t\t\t\tcase 'settingsReset': value = strings.settings.reset; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tRestart.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'restartTitle':  value = strings.restart.title; break;\n\t\t\t\t\tcase 'restartPrompt': value = strings.restart.prompt; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tShare.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'shareTitle': value = strings.share.title; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAlert.\n\t\t\t\t\t*/\n\t\t\t\t\t/* none */\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAutoload.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'autoloadTitle':  value = strings.autoload.title; break;\n\t\t\t\t\tcase 'autoloadCancel': value = strings.autoload.cancel; break;\n\t\t\t\t\tcase 'autoloadOk':     value = strings.autoload.ok; break;\n\t\t\t\t\tcase 'autoloadPrompt': value = strings.autoload.prompt; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tMacros.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'macroBackText':   value = strings.macros.back.text; break;\n\t\t\t\t\tcase 'macroReturnText': value = strings.macros.return.text; break;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (value) {\n\t\t\t\t\t\tl10nStrings[id] = value.replace(/%\\w+%/g, pat => `{${pat.slice(1, -1)}}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t});\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tLocalization Functions.\n\t\t*/\n\t\tinit : { value : l10nInit },\n\n\t\t/*\n\t\t\tLocalized String Functions.\n\t\t*/\n\t\tget : { value : l10nGet }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tl10n/legacy.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\t[DEPRECATED] The `strings` object is deprecated and should no longer be used.\n\tAll new or updated translations should be based upon the `l10nStrings` object\n\t(see: `l10n/strings.js`).\n\n\tLegacy/existing uses of the `strings` object will be mapped to the `l10nStrings`\n\tobject after user script evaluation.\n*/\nvar strings = { // eslint-disable-line no-unused-vars, no-var\n\terrors    : {},\n\twarnings  : {},\n\tdebugView : {},\n\tuiBar     : {},\n\tjumpto    : {},\n\tsaves     : {},\n\tsettings  : {},\n\trestart   : {},\n\tshare     : {},\n\tautoload  : {},\n\tmacros    : {\n\t\tback   : {},\n\t\treturn : {}\n\t}\n};\n\n/***********************************************************************************************************************\n\n\tl10n/strings.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* eslint-disable max-len, prefer-template */\n\n/*\n\tATTENTION TRANSLATORS\n\n\tPlease use the `locale/l10n-template.js` file, from the root of the repository,\n\tas the template for your translation rather than this file.\n\n\tSEE: https://github.com/tmedwards/sugarcube-2/tree/develop/locale\n*/\nvar l10nStrings = { // eslint-disable-line no-unused-vars, no-var\n\t/*\n\t\tGeneral.\n\t*/\n\tidentity : 'game',\n\taborting : 'Aborting',\n\tcancel   : 'Cancel',\n\tclose    : 'Close',\n\tok       : 'OK',\n\n\t/*\n\t\tErrors.\n\t*/\n\terrorTitle              : 'Error',\n\terrorToggle             : 'Toggle the error view',\n\terrorNonexistentPassage : 'the passage \"{passage}\" does not exist', // NOTE: `passage` is supplied locally\n\terrorSaveMissingData    : 'save is missing required data. Either the loaded file is not a save or the save has become corrupted',\n\terrorSaveIdMismatch     : 'save is from the wrong {identity}',\n\n\t/*\n\t\tWarnings.\n\t*/\n\t_warningIntroLacking  : 'Your browser either lacks or has disabled',\n\t_warningOutroDegraded : ', so this {identity} is running in a degraded mode. You may be able to continue, however, some parts may not work properly.',\n\twarningNoWebStorage   : '{_warningIntroLacking} the Web Storage API{_warningOutroDegraded}',\n\twarningDegraded       : '{_warningIntroLacking} some of the capabilities required by this {identity}{_warningOutroDegraded}',\n\n\t/*\n\t\tDebug bar.\n\t*/\n\tdebugBarToggle      : 'Toggle the debug bar',\n\tdebugBarNoWatches   : '\\u2014 no watches set \\u2014',\n\tdebugBarAddWatch    : 'Add watch',\n\tdebugBarDeleteWatch : 'Delete watch',\n\tdebugBarWatchAll    : 'Watch all',\n\tdebugBarWatchNone   : 'Delete all',\n\tdebugBarLabelAdd    : 'Add',\n\tdebugBarLabelWatch  : 'Watch',\n\tdebugBarLabelTurn   : 'Turn', // (noun) chance to act (in a game), moment, period\n\tdebugBarLabelViews  : 'Views',\n\tdebugBarViewsToggle : 'Toggle the debug views',\n\tdebugBarWatchToggle : 'Toggle the watch panel',\n\n\t/*\n\t\tUI bar.\n\t*/\n\tuiBarToggle   : 'Toggle the UI bar',\n\tuiBarBackward : 'Go backward within the {identity} history',\n\tuiBarForward  : 'Go forward within the {identity} history',\n\tuiBarJumpto   : 'Jump to a specific point within the {identity} history',\n\n\t/*\n\t\tJump To.\n\t*/\n\tjumptoTitle       : 'Jump To',\n\tjumptoTurn        : 'Turn', // (noun) chance to act (in a game), moment, period\n\tjumptoUnavailable : 'No jump points currently available\\u2026',\n\n\t/*\n\t\tSaves.\n\t*/\n\tsavesTitle       : 'Saves',\n\tsavesDisallowed  : 'Saving has been disallowed on this passage.',\n\tsavesIncapable   : '{_warningIntroLacking} the capabilities required to support saves, so saves have been disabled for this session.',\n\tsavesLabelAuto   : 'Autosave',\n\tsavesLabelDelete : 'Delete',\n\tsavesLabelExport : 'Save to Disk\\u2026',\n\tsavesLabelImport : 'Load from Disk\\u2026',\n\tsavesLabelLoad   : 'Load',\n\tsavesLabelClear  : 'Delete All',\n\tsavesLabelSave   : 'Save',\n\tsavesLabelSlot   : 'Slot',\n\tsavesUnavailable : 'No save slots found\\u2026',\n\tsavesUnknownDate : 'unknown',\n\n\t/*\n\t\tSettings.\n\t*/\n\tsettingsTitle : 'Settings',\n\tsettingsOff   : 'Off',\n\tsettingsOn    : 'On',\n\tsettingsReset : 'Reset to Defaults',\n\n\t/*\n\t\tRestart.\n\t*/\n\trestartTitle  : 'Restart',\n\trestartPrompt : 'Are you sure that you want to restart? Unsaved progress will be lost.',\n\n\t/*\n\t\tShare.\n\t*/\n\tshareTitle : 'Share',\n\n\t/*\n\t\tAlert.\n\t*/\n\t/* none */\n\n\t/*\n\t\tAutoload.\n\t*/\n\tautoloadTitle  : 'Autoload',\n\tautoloadCancel : 'Go to start',\n\tautoloadOk     : 'Load autosave',\n\tautoloadPrompt : 'An autosave exists. Load it now or go to the start?',\n\n\t/*\n\t\tMacros.\n\t*/\n\tmacroBackText   : 'Back',  // (verb) rewind, revert\n\tmacroReturnText : 'Return' // (verb) go/send back\n};\n\n/***********************************************************************************************************************\n\n\tconfig.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util */\n\nvar Config = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// General settings.\n\tlet _debug                 = false;\n\tlet _addVisitedLinkClass   = false;\n\tlet _cleanupWikifierOutput = false;\n\tlet _loadDelay             = 0;\n\n\t// Audio settings.\n\tlet _audioPauseOnFadeToZero = true;\n\tlet _audioPreloadMetadata   = true;\n\n\t// State history settings.\n\tlet _historyControls  = true;\n\tlet _historyMaxStates = 100;\n\n\t// Macros settings.\n\tlet _macrosIfAssignmentError = true;\n\tlet _macrosMaxLoopIterations = 1000;\n\n\t// Navigation settings.\n\tlet _navigationOverride;\n\n\t// Passages settings.\n\tlet _passagesDescriptions;\n\tlet _passagesDisplayTitles = false;\n\tlet _passagesNobr          = false;\n\tlet _passagesStart; // set by `Story.load()`\n\tlet _passagesOnProcess;\n\tlet _passagesTransitionOut;\n\n\t// Saves settings.\n\tlet _savesAutoload;\n\tlet _savesAutosave;\n\tlet _savesId        = 'untitled-story';\n\tlet _savesIsAllowed;\n\tlet _savesOnLoad;\n\tlet _savesOnSave;\n\tlet _savesSlots     = 8;\n\tlet _savesVersion;\n\n\t// UI settings.\n\tlet _uiStowBarInitially    = 800;\n\tlet _uiUpdateStoryElements = true;\n\n\n\t/*******************************************************************************\n\t\tError Constants.\n\t*******************************************************************************/\n\n\tconst _errHistoryModeDeprecated     = 'Config.history.mode has been deprecated and is no longer used by SugarCube, please remove it from your code';\n\tconst _errHistoryTrackingDeprecated = 'Config.history.tracking has been deprecated, use Config.history.maxStates instead';\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze({\n\t\t/*\n\t\t\tGeneral settings.\n\t\t*/\n\t\tget debug() { return _debug; },\n\t\tset debug(value) { _debug = Boolean(value); },\n\n\t\tget addVisitedLinkClass() { return _addVisitedLinkClass; },\n\t\tset addVisitedLinkClass(value) { _addVisitedLinkClass = Boolean(value); },\n\n\t\tget cleanupWikifierOutput() { return _cleanupWikifierOutput; },\n\t\tset cleanupWikifierOutput(value) { _cleanupWikifierOutput = Boolean(value); },\n\n\t\tget loadDelay() { return _loadDelay; },\n\t\tset loadDelay(value) {\n\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\tthrow new RangeError('Config.loadDelay must be a non-negative integer');\n\t\t\t}\n\n\t\t\t_loadDelay = value;\n\t\t},\n\n\t\t/*\n\t\t\tAudio settings.\n\t\t*/\n\t\taudio : Object.freeze({\n\t\t\tget pauseOnFadeToZero() { return _audioPauseOnFadeToZero; },\n\t\t\tset pauseOnFadeToZero(value) { _audioPauseOnFadeToZero = Boolean(value); },\n\n\t\t\tget preloadMetadata() { return _audioPreloadMetadata; },\n\t\t\tset preloadMetadata(value) { _audioPreloadMetadata = Boolean(value); }\n\t\t}),\n\n\t\t/*\n\t\t\tState history settings.\n\t\t*/\n\t\thistory : Object.freeze({\n\t\t\t// TODO: (v3) This should be under UI settings → `Config.ui.historyControls`.\n\t\t\tget controls() { return _historyControls; },\n\t\t\tset controls(value) {\n\t\t\t\tconst controls = Boolean(value);\n\n\t\t\t\tif (_historyMaxStates === 1 && controls) {\n\t\t\t\t\tthrow new Error('Config.history.controls must be false when Config.history.maxStates is 1');\n\t\t\t\t}\n\n\t\t\t\t_historyControls = controls;\n\t\t\t},\n\n\t\t\tget maxStates() { return _historyMaxStates; },\n\t\t\tset maxStates(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new RangeError('Config.history.maxStates must be a non-negative integer');\n\t\t\t\t}\n\n\t\t\t\t_historyMaxStates = value;\n\n\t\t\t\t// Force `Config.history.controls` to `false`, when limited to `1` moment.\n\t\t\t\tif (_historyControls && value === 1) {\n\t\t\t\t\t_historyControls = false;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// legacy\n\t\t\t// Die if deprecated state history settings are accessed.\n\t\t\tget mode()  { throw new Error(_errHistoryModeDeprecated); },\n\t\t\tset mode(_) { throw new Error(_errHistoryModeDeprecated); },\n\t\t\tget tracking()  { throw new Error(_errHistoryTrackingDeprecated); },\n\t\t\tset tracking(_) { throw new Error(_errHistoryTrackingDeprecated); }\n\t\t\t// /legacy\n\t\t}),\n\n\t\t/*\n\t\t\tMacros settings.\n\t\t*/\n\t\tmacros : Object.freeze({\n\t\t\tget ifAssignmentError() { return _macrosIfAssignmentError; },\n\t\t\tset ifAssignmentError(value) { _macrosIfAssignmentError = Boolean(value); },\n\n\t\t\tget maxLoopIterations() { return _macrosMaxLoopIterations; },\n\t\t\tset maxLoopIterations(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new RangeError('Config.macros.maxLoopIterations must be a non-negative integer');\n\t\t\t\t}\n\n\t\t\t\t_macrosMaxLoopIterations = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tNavigation settings.\n\t\t*/\n\t\tnavigation : Object.freeze({\n\t\t\tget override() { return _navigationOverride; },\n\t\t\tset override(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.navigation.override must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_navigationOverride = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tPassages settings.\n\t\t*/\n\t\tpassages : Object.freeze({\n\t\t\tget descriptions() { return _passagesDescriptions; },\n\t\t\tset descriptions(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'boolean' && valueType !== 'Object' && valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.descriptions must be a boolean, object, function, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesDescriptions = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.updateTitle`.\n\t\t\tget displayTitles() { return _passagesDisplayTitles; },\n\t\t\tset displayTitles(value) { _passagesDisplayTitles = Boolean(value); },\n\n\t\t\tget nobr() { return _passagesNobr; },\n\t\t\tset nobr(value) { _passagesNobr = Boolean(value); },\n\n\t\t\tget onProcess() { return _passagesOnProcess; },\n\t\t\tset onProcess(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.onProcess must be a function or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesOnProcess = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.(start|startingPassage)`.\n\t\t\tget start() { return _passagesStart; },\n\t\t\tset start(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'string') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.start must be a string or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesStart = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.transitionOut`.\n\t\t\tget transitionOut() { return _passagesTransitionOut; },\n\t\t\tset transitionOut(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t   valueType !== 'string'\n\t\t\t\t\t\t&& (valueType !== 'number' || !Number.isSafeInteger(value) || value < 0)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.transitionOut must be a string, non-negative integer, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesTransitionOut = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tSaves settings.\n\t\t*/\n\t\tsaves : Object.freeze({\n\t\t\tget autoload() { return _savesAutoload; },\n\t\t\tset autoload(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'boolean' && valueType !== 'string' && valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.saves.autoload must be a boolean, string, function, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_savesAutoload = value;\n\t\t\t},\n\n\t\t\tget autosave() { return _savesAutosave; },\n\t\t\tset autosave(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\t// legacy\n\t\t\t\t\t// Convert a string value to an Array of string.\n\t\t\t\t\tif (valueType === 'string') {\n\t\t\t\t\t\t_savesAutosave = [value];\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// /legacy\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t   valueType !== 'boolean'\n\t\t\t\t\t\t&& (valueType !== 'Array' || !value.every(item => typeof item === 'string'))\n\t\t\t\t\t\t&& valueType !== 'function'\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new TypeError(`Config.saves.autosave must be a boolean, Array of strings, function, or null/undefined (received: ${valueType}${valueType === 'Array' ? ' of mixed' : ''})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_savesAutosave = value;\n\t\t\t},\n\n\t\t\tget id() { return _savesId; },\n\t\t\tset id(value) {\n\t\t\t\tif (typeof value !== 'string' || value === '') {\n\t\t\t\t\tthrow new TypeError(`Config.saves.id must be a non-empty string (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesId = value;\n\t\t\t},\n\n\t\t\tget isAllowed() { return _savesIsAllowed; },\n\t\t\tset isAllowed(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.isAllowed must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesIsAllowed = value;\n\t\t\t},\n\n\t\t\tget onLoad() { return _savesOnLoad; },\n\t\t\tset onLoad(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.onLoad must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesOnLoad = value;\n\t\t\t},\n\n\t\t\tget onSave() { return _savesOnSave; },\n\t\t\tset onSave(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.onSave must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesOnSave = value;\n\t\t\t},\n\n\t\t\tget slots() { return _savesSlots; },\n\t\t\tset slots(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new TypeError(`Config.saves.slots must be a non-negative integer (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesSlots = value;\n\t\t\t},\n\n\t\t\tget version() { return _savesVersion; },\n\t\t\tset version(value) { _savesVersion = value; }\n\t\t}),\n\n\t\t/*\n\t\t\tUI settings.\n\t\t*/\n\t\tui : Object.freeze({\n\t\t\tget stowBarInitially() { return _uiStowBarInitially; },\n\t\t\tset stowBarInitially(value) {\n\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\tif (\n\t\t\t\t\t   valueType !== 'boolean'\n\t\t\t\t\t&& (valueType !== 'number' || !Number.isSafeInteger(value) || value < 0)\n\t\t\t\t) {\n\t\t\t\t\tthrow new TypeError(`Config.ui.stowBarInitially must be a boolean or non-negative integer (received: ${valueType})`);\n\t\t\t\t}\n\n\t\t\t\t_uiStowBarInitially = value;\n\t\t\t},\n\n\t\t\tget updateStoryElements() { return _uiUpdateStoryElements; },\n\t\t\tset updateStoryElements(value) { _uiUpdateStoryElements = Boolean(value); }\n\t\t})\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tsimpleaudio.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser, Config, Has, LoadScreen, Story, Util, Visibility, clone */\n\nvar SimpleAudio = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tEvents that count as user activation—i.e. \"user gestures\", \"activation behavior\".\n\n\t\tNOTE (ca. Dec, 2018): This not an exhaustive list and varies significantly by browser.\n\t\tProposals for a specification/standard are still very much in flux at this point.\n\n\t\tTODO (ca. Dec, 2018): Revisit this topic.\n\n\t\tSEE: (too many to list)\n\t\t\thttps://github.com/whatwg/html/issues/3849\n\t\t\thttps://github.com/whatwg/html/issues/1903\n\t\t\thttps://html.spec.whatwg.org/#activation\n\t\t\thttps://docs.google.com/spreadsheets/d/1DGXjhQ6D3yZXIePOMo0dsd2agz0t5W7rYH1NwJ-QGJo/edit#gid=0\n\t*/\n\tconst _gestureEventNames = Object.freeze(['click', 'contextmenu', 'dblclick', 'keyup', 'mouseup', 'pointerup', 'touchend']);\n\n\t// Special group IDs.\n\tconst _specialIds = Object.freeze([':not', ':all', ':looped', ':muted', ':paused', ':playing']);\n\n\t// Format specifier regular expression.\n\tconst _formatSpecRe = /^([\\w-]+)\\s*\\|\\s*(\\S.*)$/; // e.g. 'mp3|https://audiohost.tld/id'\n\n\t// ID verification regular expressions.\n\tconst _badIdRe = /[:\\s]/;\n\n\t// Tracks collection.\n\tconst _tracks = new Map();\n\n\t// Groups collection.\n\tconst _groups = new Map();\n\n\t// Playlists collection.\n\tconst _lists = new Map();\n\n\t// Subscriber collection.\n\tconst _subscribers = new Map();\n\n\t// Master playback rate.\n\tlet _masterRate = 1;\n\n\t// Master playback volume.\n\tlet _masterVolume = 1;\n\n\t// Master mute state.\n\tlet _masterMute = false;\n\n\t// Master mute on tab/window visibility state.\n\tlet _masterMuteOnHidden = false;\n\n\n\t/*******************************************************************************************************************\n\t\tFeature Detection Functions.\n\t*******************************************************************************************************************/\n\t// Return whether the `<HTMLAudioElement>.play()` method returns a `Promise`.\n\t//\n\t// NOTE: The initial result is cached for future calls.\n\tconst _playReturnsPromise = (function () {\n\t\t// Cache of whether `<HTMLAudioElement>.play()` returns a `Promise`.\n\t\tlet _hasPromise = null;\n\n\t\tfunction _playReturnsPromise() {\n\t\t\tif (_hasPromise !== null) {\n\t\t\t\treturn _hasPromise;\n\t\t\t}\n\n\t\t\t_hasPromise = false;\n\n\t\t\tif (Has.audio) {\n\t\t\t\ttry {\n\t\t\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t\t\t// NOTE (ca. Jan 01, 2020): Firefox will still log an \"Autoplay is only allowed\n\t\t\t\t\t// when […] media is muted.\" message to the console when attempting the test\n\t\t\t\t\t// below, even though the audio has been muted.  Stay classy, Firefox.\n\t\t\t\t\t//\n\t\t\t\t\t// QUESTION (ca. Jan 01, 2020): Keep this?  It's only here to appease Firefox,\n\t\t\t\t\t// but doesn't seem to work as Firefox seems to ignore mute in violation of the\n\t\t\t\t\t// `HTMLAudioElement` specification—willfully or simply a bug, I can't say.\n\t\t\t\t\taudio.muted = true;\n\n\t\t\t\t\tconst value = audio.play();\n\n\t\t\t\t\t// Silence \"Uncaught (in promise)\" console errors from Blink.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: Swallowing errors is generally bad, but in this case we know there's\n\t\t\t\t\t// going to be an error regardless, since there's no source, and we don't actually\n\t\t\t\t\t// care about the error, since we just want the return value, so we consign it\n\t\t\t\t\t// to the bit bucket.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: We don't ensure that the return value is not `undefined` here because\n\t\t\t\t\t// having the attempted call to `<Promise>.catch()` on an `undefined` value throw\n\t\t\t\t\t// is acceptable, since it will be caught and `false` eventually returned.\n\t\t\t\t\tvalue.catch(() => { /* no-op */ });\n\n\t\t\t\t\t_hasPromise = value instanceof Promise;\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t}\n\n\t\t\treturn _hasPromise;\n\t\t}\n\n\t\treturn _playReturnsPromise;\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tAudioTrack Class.\n\t*******************************************************************************************************************/\n\tclass AudioTrack {\n\t\tconstructor(obj) {\n\t\t\t// Process the given array of sources or AudioTrack object.\n\t\t\tif (obj instanceof Array) {\n\t\t\t\tthis._create(obj);\n\t\t\t}\n\t\t\telse if (obj instanceof AudioTrack) {\n\t\t\t\tthis._copy(obj);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('sources parameter must be either an array, of URIs or source objects, or an AudioTrack instance');\n\t\t\t}\n\t\t}\n\n\t\t_create(sourceList) {\n\t\t\tconst dataUriRe   = /^data:\\s*audio\\/([^;,]+)\\s*[;,]/i;\n\t\t\tconst extRe       = /\\.([^./\\\\]+)$/;\n\t\t\tconst getType     = AudioTrack.getType;\n\t\t\tconst usedSources = [];\n\t\t\t/*\n\t\t\t\tHTMLAudioElement: DOM factory method vs. constructor\n\n\t\t\t\tUse of the DOM factory method, `document.createElement('audio')`, should be\n\t\t\t\tpreferred over use of the constructor, `new Audio()`.  The reason being that\n\t\t\t\tobjects created by the latter are, erroneously, treated differently, often\n\t\t\t\tunfavorably, by certain browser engines—e.g. within some versions of the iOS\n\t\t\t\tbrowser core.\n\n\t\t\t\tNotably, the only difference between the two, per the specification, is that\n\t\t\t\tobjects created via the constructor should have their `preload` property\n\t\t\t\tautomatically set to 'auto'.  Thus, there's no technical reason to prefer\n\t\t\t\tusage of the constructor, even discounting buggy browser implementations.\n\t\t\t*/\n\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t// Initially set the `preload` attribute to `'none'`.\n\t\t\taudio.preload = 'none';\n\n\t\t\t// Process the array of sources, adding any valid sources to the `usedSources`\n\t\t\t// array and to the audio element as source elements.\n\t\t\tsourceList.forEach(src => {\n\t\t\t\tlet srcObj = null;\n\n\t\t\t\tswitch (typeof src) {\n\t\t\t\tcase 'string':\n\t\t\t\t\t{\n\t\t\t\t\t\tlet match;\n\n\t\t\t\t\t\tif (src.slice(0, 5) === 'data:') {\n\t\t\t\t\t\t\tmatch = dataUriRe.exec(src);\n\n\t\t\t\t\t\t\tif (match === null) {\n\t\t\t\t\t\t\t\tthrow new Error('source data URI missing media type');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tmatch = extRe.exec(Util.parseUrl(src).pathname);\n\n\t\t\t\t\t\t\tif (match === null) {\n\t\t\t\t\t\t\t\tthrow new Error('source URL missing file extension');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst type = getType(match[1]);\n\n\t\t\t\t\t\tif (type !== null) {\n\t\t\t\t\t\t\tsrcObj = { src, type };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\t{\n\t\t\t\t\t\tif (src === null) {\n\t\t\t\t\t\t\tthrow new Error('source object cannot be null');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (!src.hasOwnProperty('src')) {\n\t\t\t\t\t\t\tthrow new Error('source object missing required \"src\" property');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (!src.hasOwnProperty('format')) {\n\t\t\t\t\t\t\tthrow new Error('source object missing required \"format\" property');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst type = getType(src.format);\n\n\t\t\t\t\t\tif (type !== null) {\n\t\t\t\t\t\t\tsrcObj = { src : src.src, type };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`invalid source value (type: ${typeof src})`);\n\t\t\t\t}\n\n\t\t\t\tif (srcObj !== null) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tOpera (Blink; ca. Jul 2017) fails to play audio from some sources\n\t\t\t\t\t\twith MIME-types containing a `codecs` parameter, despite the fact\n\t\t\t\t\t\tthat `canPlayType()` blessed the full MIME-type including `codecs`.\n\n\t\t\t\t\t\tBizarrely, this only affects some MIME-types—e.g. MP3s are affected,\n\t\t\t\t\t\twhile WAVEs are not.\n\t\t\t\t\t\t\tFails: 'audio/mpeg; codecs=\"mp3\"'\n\t\t\t\t\t\t\tPlays: 'audio/mpeg'\n\t\t\t\t\t\t\tPlays: 'audio/wav; codecs=\"1\"'\n\n\t\t\t\t\t\tTo workaround this we remove all parameters from the MIME-type in\n\t\t\t\t\t\tOpera.\n\t\t\t\t\t*/\n\t\t\t\t\tif (Browser.isOpera) {\n\t\t\t\t\t\tsrcObj.type =  srcObj.type.replace(/;.*$/, '');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst source = document.createElement('source');\n\t\t\t\t\tsource.src  = srcObj.src;\n\t\t\t\t\tsource.type = srcObj.type;\n\t\t\t\t\taudio.appendChild(source);\n\t\t\t\t\tusedSources.push(srcObj);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (audio.hasChildNodes()) {\n\t\t\t\t// Set the `preload` attribute to `'metadata'`, unless preloading has been disabled.\n\t\t\t\tif (Config.audio.preloadMetadata) {\n\t\t\t\t\taudio.preload = 'metadata';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._finalize(audio, usedSources, clone(sourceList));\n\t\t}\n\n\t\t_copy(obj) {\n\t\t\tthis._finalize(\n\t\t\t\tobj.audio.cloneNode(true), // deep clone of the audio element & its children\n\t\t\t\tclone(obj.sources),\n\t\t\t\tclone(obj.originals)\n\t\t\t);\n\t\t}\n\n\t\t_finalize(audio, sources, originals) {\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\taudio : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : audio\n\t\t\t\t},\n\n\t\t\t\tsources : {\n\t\t\t\t\tvalue : Object.freeze(sources)\n\t\t\t\t},\n\n\t\t\t\toriginals : {\n\t\t\t\t\tvalue : Object.freeze(originals)\n\t\t\t\t},\n\n\t\t\t\t_error : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_faderId : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_mute : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_rate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_volume : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Set up event handlers on the audio and source elements.\n\t\t\tjQuery(this.audio)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving a `loadstart` event on the audio element, set `_error` to\n\t\t\t\t\t`false`.\n\t\t\t\t*/\n\t\t\t\t.on('loadstart.AudioTrack', () => this._error = false)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving an `error` event on the audio element, set `_error` to\n\t\t\t\t\t`true`.\n\n\t\t\t\t\tCaveats by browser:\n\t\t\t\t\t\tEdge violates the specification by triggering `error` events from source\n\t\t\t\t\t\telements on their parent media element, rather than the source element.\n\t\t\t\t\t\tTo enable error handling in all browsers, we set the error handler on the\n\t\t\t\t\t\taudio element and have the final source element forward its `error` event.\n\n\t\t\t\t\t\tIE does not trigger, at least some, `error` events from source elements at\n\t\t\t\t\t\tall, not on the source element or its parent media element.  AFAIK, nothing\n\t\t\t\t\t\tcan be done about this lossage.\n\t\t\t\t*/\n\t\t\t\t.on('error.AudioTrack', () => this._error = true)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving an `error` event on the final source element (if any), trigger\n\t\t\t\t\tan `error` event on the audio element—that being necessary because the source\n\t\t\t\t\t`error` event does not bubble.\n\t\t\t\t*/\n\t\t\t\t.find('source:last-of-type')\n\t\t\t\t.on('error.AudioTrack', () => this._trigger('error'));\n\n\t\t\t// Subscribe to command messages.\n\t\t\tsubscribe(this, mesg => {\n\t\t\t\tif (!this.audio) {\n\t\t\t\t\tunsubscribe(this);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch (mesg) {\n\t\t\t\tcase 'loadwithscreen':\n\t\t\t\t\tif (this.hasSource()) {\n\t\t\t\t\t\tconst lockId = LoadScreen.lock();\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t// NOTE: Do not use an arrow function here.\n\t\t\t\t\t\t\t.one(\n\t\t\t\t\t\t\t\t'canplaythrough.AudioTrack_loadwithscreen error.AudioTrack_loadwithscreen',\n\t\t\t\t\t\t\t\tfunction () {\n\t\t\t\t\t\t\t\t\tjQuery(this).off('.AudioTrack_loadwithscreen');\n\t\t\t\t\t\t\t\t\tLoadScreen.unlock(lockId);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.load();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'load':   this.load();               break;\n\t\t\t\tcase 'mute':   this._updateAudioMute();   break;\n\t\t\t\tcase 'rate':   this._updateAudioRate();   break;\n\t\t\t\tcase 'stop':   this.stop();               break;\n\t\t\t\tcase 'volume': this._updateAudioVolume(); break;\n\t\t\t\tcase 'unload': this.unload();             break;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Synchronize with the current master audio settings.\n\t\t\tthis._updateAudioMute();\n\t\t\tthis._updateAudioRate();\n\t\t\tthis._updateAudioVolume();\n\t\t}\n\n\t\t_trigger(eventName) {\n\t\t\t// Do not use `trigger()` here as we do not want these events to bubble.\n\t\t\tjQuery(this.audio).triggerHandler(eventName);\n\t\t}\n\n\t\t_destroy() {\n\t\t\t/*\n\t\t\t\tStrictly speaking, self-destruction is not necessary as this object will,\n\t\t\t\teventually, be garbage collected.  That said, since the audio element contains\n\t\t\t\tdata buffers for the selected audio source, which may be quite large, manually\n\t\t\t\tpurging them as soon as we know that they're no longer needed is not a bad idea.\n\t\t\t*/\n\t\t\tunsubscribe(this);\n\n\t\t\tif (!this.audio) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tjQuery(this.audio).off();\n\t\t\tthis.unload();\n\t\t\tthis._error = true;\n\n\t\t\t// Delete the audio element property.\n\t\t\tdelete this.audio;\n\t\t}\n\n\t\tclone() {\n\t\t\treturn new AudioTrack(this);\n\t\t}\n\n\t\tload() {\n\t\t\tthis.fadeStop();\n\t\t\tthis.audio.pause();\n\n\t\t\tif (!this.audio.hasChildNodes()) {\n\t\t\t\tif (this.sources.length === 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.sources.forEach(srcObj => {\n\t\t\t\t\tconst source = document.createElement('source');\n\t\t\t\t\tsource.src  = srcObj.src;\n\t\t\t\t\tsource.type = srcObj.type;\n\t\t\t\t\tthis.audio.appendChild(source);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (this.audio.preload !== 'auto') {\n\t\t\t\tthis.audio.preload = 'auto';\n\t\t\t}\n\n\t\t\tif (!this.isLoading()) {\n\t\t\t\tthis.audio.load();\n\t\t\t}\n\t\t}\n\n\t\tunload() {\n\t\t\tthis.fadeStop();\n\t\t\tthis.stop();\n\n\t\t\tconst audio = this.audio;\n\t\t\taudio.preload = 'none';\n\n\t\t\t// Remove all source elements.\n\t\t\twhile (audio.hasChildNodes()) {\n\t\t\t\taudio.removeChild(audio.firstChild);\n\t\t\t}\n\n\t\t\t// Force the audio element to drop any existing data buffers.\n\t\t\taudio.load();\n\t\t}\n\n\t\tplay() {\n\t\t\tif (!this.hasSource()) {\n\t\t\t\treturn Promise.reject(new Error('none of the candidate sources were acceptable'));\n\t\t\t}\n\n\t\t\tif (this.isUnloaded()) {\n\t\t\t\treturn Promise.reject(new Error('no sources are loaded'));\n\t\t\t}\n\n\t\t\tif (this.isFailed()) {\n\t\t\t\treturn Promise.reject(new Error('failed to load any of the sources'));\n\t\t\t}\n\n\t\t\tif (this.audio.preload !== 'auto') {\n\t\t\t\tthis.audio.preload = 'auto';\n\t\t\t}\n\n\t\t\tconst namespace = '.AudioTrack_play';\n\n\t\t\treturn _playReturnsPromise()\n\t\t\t\t? this.audio.play()\n\t\t\t\t: new Promise((resolve, reject) => {\n\t\t\t\t\tif (this.isPlaying()) {\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tjQuery(this.audio)\n\t\t\t\t\t\t\t.off(namespace)\n\t\t\t\t\t\t\t.one(`error${namespace} playing${namespace} timeupdate${namespace}`, ev => {\n\t\t\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\t\t\tif (ev.type === 'error') {\n\t\t\t\t\t\t\t\t\treject(new Error('unknown audio play error'));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.audio.play();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tthis.play().catch(() => {\n\t\t\t\tconst gestures = _gestureEventNames.map(name => `${name}.AudioTrack_playWhenAllowed`).join(' ');\n\t\t\t\tjQuery(document).one(gestures, () => {\n\t\t\t\t\tjQuery(document).off('.AudioTrack_playWhenAllowed');\n\t\t\t\t\tthis.audio.play();\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tpause() {\n\t\t\tthis.audio.pause();\n\t\t}\n\n\t\tstop() {\n\t\t\tthis.audio.pause();\n\t\t\tthis.time(0);\n\t\t\tthis._trigger(':stopped');\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (typeof duration !== 'number') {\n\t\t\t\tthrow new TypeError('duration parameter must be a number');\n\t\t\t}\n\t\t\tif (typeof toVol !== 'number') {\n\t\t\t\tthrow new TypeError('toVolume parameter must be a number');\n\t\t\t}\n\t\t\tif (fromVol != null && typeof fromVol !== 'number') { // lazy equality for null\n\t\t\t\tthrow new TypeError('fromVolume parameter must be a number');\n\t\t\t}\n\n\t\t\tif (!this.hasSource()) {\n\t\t\t\treturn Promise.reject(new Error('none of the candidate sources were acceptable'));\n\t\t\t}\n\n\t\t\tif (this.isUnloaded()) {\n\t\t\t\treturn Promise.reject(new Error('no sources are loaded'));\n\t\t\t}\n\n\t\t\tif (this.isFailed()) {\n\t\t\t\treturn Promise.reject(new Error('failed to load any of the sources'));\n\t\t\t}\n\n\t\t\tthis.fadeStop();\n\n\t\t\tconst from = Math.clamp(fromVol == null ? this.volume() : fromVol, 0, 1); // lazy equality for null\n\t\t\tconst to   = Math.clamp(toVol, 0, 1);\n\n\t\t\tif (from === to) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.volume(from);\n\n\t\t\t/*\n\t\t\t\tWe listen for the `timeupdate` event here, rather than `playing`, because\n\t\t\t\tvarious browsers (notably, mobile browsers) are poor at firing media events\n\t\t\t\tin a timely fashion, so we use `timeupdate` to ensure that we don't start\n\t\t\t\tthe fade until the track is actually progressing.\n\t\t\t*/\n\t\t\tjQuery(this.audio)\n\t\t\t\t.off('timeupdate.AudioTrack_fade')\n\t\t\t\t.one('timeupdate.AudioTrack_fade', () => {\n\t\t\t\t\tlet min;\n\t\t\t\t\tlet max;\n\n\t\t\t\t\t// Fade in.\n\t\t\t\t\tif (from < to) {\n\t\t\t\t\t\tmin = from;\n\t\t\t\t\t\tmax = to;\n\t\t\t\t\t}\n\t\t\t\t\t// Fade out.\n\t\t\t\t\telse {\n\t\t\t\t\t\tmin = to;\n\t\t\t\t\t\tmax = from;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst time     = Math.max(duration, 1);\n\t\t\t\t\tconst interval = 25; // in milliseconds\n\t\t\t\t\tconst delta    = (to - from) / (time / (interval / 1000));\n\n\t\t\t\t\tthis._trigger(':fading');\n\t\t\t\t\tthis._faderId = setInterval(() => {\n\t\t\t\t\t\tif (!this.isPlaying()) {\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tWhile it may seem like a good idea to also set the track volume\n\t\t\t\t\t\t\t\tto the `to` value here, we should not do so.  We cannot know why\n\t\t\t\t\t\t\t\tthe track is no longer playing, nor if the volume has been modified\n\t\t\t\t\t\t\t\tin the interim, so doing so now may clobber an end-user set volume.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tthis.fadeStop();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthis.volume(Math.clamp(this.volume() + delta, min, max));\n\n\t\t\t\t\t\tif (Config.audio.pauseOnFadeToZero && this.volume() === 0) {\n\t\t\t\t\t\t\tthis.pause();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.volume() === to) {\n\t\t\t\t\t\t\tthis.fadeStop();\n\t\t\t\t\t\t\tthis._trigger(':faded');\n\t\t\t\t\t\t}\n\t\t\t\t\t}, interval);\n\t\t\t\t});\n\n\t\t\treturn this.play();\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\treturn this.fade(duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\treturn this.fade(duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tif (this._faderId !== null) {\n\t\t\t\tclearInterval(this._faderId);\n\t\t\t\tthis._faderId = null;\n\t\t\t}\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\treturn this.audio.loop;\n\t\t\t}\n\n\t\t\tthis.audio.loop = !!loop;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\treturn this._mute;\n\t\t\t}\n\n\t\t\tthis._mute = !!mute;\n\t\t\tthis._updateAudioMute();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioMute() {\n\t\t\tthis.audio.muted = this._mute || _masterMute;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\treturn this._rate;\n\t\t\t}\n\n\t\t\tif (typeof rate !== 'number') {\n\t\t\t\tthrow new TypeError('rate parameter must be a number');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tClamp the playback rate to sane values—some browsers also do this to varying degrees.\n\n\t\t\t\tNOTE (ca. Aug 2016): The specification allows negative values for reverse playback,\n\t\t\t\thowever, most browsers either completely ignore negative values or clamp them to\n\t\t\t\tsome positive value.  In some (notably, IE & Edge), setting a negative playback\n\t\t\t\trate breaks the associated controls, if displayed.\n\t\t\t*/\n\t\t\t/*\n\t\t\tthis._rate = rate < 0\n\t\t\t\t? Math.clamp(rate, -0.2, -5) // clamp to 5× slower & faster, backward\n\t\t\t\t: Math.clamp(rate, 0.2, 5);  // clamp to 5× slower & faster, forward\n\t\t\t*/\n\t\t\tthis._rate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\t\t\tthis._updateAudioRate();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioRate() {\n\t\t\t/*\n\t\t\tconst rate = this._rate * _masterRate;\n\t\t\tthis.audio.playbackRate = rate < 0\n\t\t\t\t? Math.clamp(rate, -0.2, -5) // clamp to 5× slower & faster, backward\n\t\t\t\t: Math.clamp(rate, 0.2, 5);  // clamp to 5× slower & faster, forward\n\t\t\t*/\n\t\t\tthis.audio.playbackRate = Math.clamp(this._rate * _masterRate, 0.2, 5); // clamp to 5× slower & faster\n\t\t}\n\n\t\ttime(time) {\n\t\t\tif (time == null) { // lazy equality for null\n\t\t\t\treturn this.audio.currentTime;\n\t\t\t}\n\n\t\t\tif (typeof time !== 'number') {\n\t\t\t\tthrow new TypeError('time parameter must be a number');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tNOTE (historic): If we try to modify the audio clip's `.currentTime` property\n\t\t\t\tbefore its metadata has been loaded, it will throw an `InvalidStateError`\n\t\t\t\t(since it doesn't know its duration, allowing `.currentTime` to be set would\n\t\t\t\tbe undefined behavior), so in case an exception is thrown we provide a fallback\n\t\t\t\tusing the `loadedmetadata` event.\n\n\t\t\t\tNOTE (ca. 2016): This workaround should no longer be necessary in most browsers.\n\t\t\t\tThat said, it will still be required for some time to service legacy browsers.\n\n\t\t\t\tNOTE (ca. Dec 09, 2018): Firefox will still log an `InvalidStateError` to the\n\t\t\t\tconsole when attempting to modify the clip's `.currentTime` property before its\n\t\t\t\tmetadata has been loaded, even though it handles the situation properly—by waiting\n\t\t\t\tfor the metadata, as all browsers do now.  To prevent this spurious logging, we\n\t\t\t\tmust now manually check for the existence of the metadata and always failover to\n\t\t\t\tan event regardless of if the browser needs it or not—because I don't want to\n\t\t\t\tintroduce a browser check here.  Stay classy, Firefox.\n\t\t\t*/\n\t\t\tif (this.hasMetadata()) {\n\t\t\t\tthis.audio.currentTime = time;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery(this.audio)\n\t\t\t\t\t.off('loadedmetadata.AudioTrack_time')\n\t\t\t\t\t.one('loadedmetadata.AudioTrack_time', () => this.audio.currentTime = time);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\treturn this._volume;\n\t\t\t}\n\n\t\t\tif (typeof volume !== 'number') {\n\t\t\t\tthrow new TypeError('volume parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._volume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\t\t\tthis._updateAudioVolume();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioVolume() {\n\t\t\tthis.audio.volume = Math.clamp(this._volume * _masterVolume, 0, 1);\n\t\t}\n\n\t\tduration() {\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.audio.duration;\n\t\t}\n\n\t\tremaining() {\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.audio.duration - this.audio.currentTime;\n\t\t}\n\n\t\tisFailed() {\n\t\t\treturn this._error;\n\t\t}\n\n\t\tisLoading() {\n\t\t\treturn this.audio.networkState === HTMLMediaElement.NETWORK_LOADING;\n\t\t}\n\n\t\tisUnloaded() {\n\t\t\treturn !this.audio.hasChildNodes();\n\t\t}\n\n\t\tisUnavailable() {\n\t\t\treturn !this.hasSource() || this.isUnloaded() || this.isFailed();\n\t\t}\n\n\t\tisPlaying() {\n\t\t\t// NOTE: The `this.hasSomeData()` check is probably no longer necessary.\n\t\t\treturn !this.audio.paused && this.hasSomeData();\n\t\t}\n\n\t\tisPaused() {\n\t\t\t/*\n\t\t\t\tIf the selected audio resource is a stream, `currentTime` may return a non-zero\n\t\t\t\tvalue even at the earliest available position within the stream as the browser\n\t\t\t\tmay have dropped the earliest chunks of buffered data or the stream may have a\n\t\t\t\ttimeline which does not start at zero.\n\n\t\t\t\tIn an attempt to guard against these possiblities, as best as we can, we test\n\t\t\t\t`duration` against `Infinity` first, which should yield true for actual streams.\n\t\t\t*/\n\t\t\treturn this.audio.paused\n\t\t\t\t&& (this.audio.duration === Infinity || this.audio.currentTime > 0)\n\t\t\t\t&& !this.audio.ended;\n\t\t}\n\n\t\tisStopped() {\n\t\t\treturn this.audio.paused && this.audio.currentTime === 0;\n\t\t}\n\n\t\tisEnded() {\n\t\t\treturn this.audio.ended;\n\t\t}\n\n\t\tisFading() {\n\t\t\treturn this._faderId !== null;\n\t\t}\n\n\t\tisSeeking() {\n\t\t\treturn this.audio.seeking;\n\t\t}\n\n\t\thasSource() {\n\t\t\treturn this.sources.length > 0;\n\t\t}\n\n\t\thasNoData() {\n\t\t\treturn this.audio.readyState === HTMLMediaElement.HAVE_NOTHING;\n\t\t}\n\n\t\thasMetadata() {\n\t\t\treturn this.audio.readyState >= HTMLMediaElement.HAVE_METADATA;\n\t\t}\n\n\t\thasSomeData() {\n\t\t\treturn this.audio.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA;\n\t\t}\n\n\t\thasData() {\n\t\t\treturn this.audio.readyState === HTMLMediaElement.HAVE_ENOUGH_DATA;\n\t\t}\n\n\t\ton(...args) {\n\t\t\tjQuery.fn.on.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\tone(...args) {\n\t\t\tjQuery.fn.one.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\toff(...args) {\n\t\t\tjQuery.fn.off.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\t/*\n\t\t\tVerifies that the browser supports the given MIME-type and then retuns either\n\t\t\tthe MIME-type, if it is supported, or `null`, if it is not.\n\t\t*/\n\t\tstatic _verifyType(type) {\n\t\t\tif (!type || !Has.audio) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst cache = AudioTrack._types;\n\n\t\t\tif (!cache.hasOwnProperty(type)) {\n\t\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t\t// Some early implementations return 'no' instead of the empty string.\n\t\t\t\tcache[type] = audio.canPlayType(type).replace(/^no$/i, '') !== '';\n\t\t\t}\n\n\t\t\treturn cache[type] ? type : null;\n\t\t}\n\n\t\t/*\n\t\t\tRetuns the MIME-type associated with the given format-ID, if it is supported,\n\t\t\telsewise `null`.\n\t\t*/\n\t\tstatic getType(format) {\n\t\t\tif (!format || !Has.audio) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst known = AudioTrack.formats;\n\t\t\tconst id    = format.toLowerCase();\n\t\t\tconst type  = known.hasOwnProperty(id) ? known[id] : `audio/${id}`;\n\n\t\t\treturn AudioTrack._verifyType(type);\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the browser potentially supports a format.\n\t\t*/\n\t\tstatic canPlayFormat(format) {\n\t\t\treturn AudioTrack.getType(format) !== null;\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the browser potentially supports a MIME-type.\n\t\t*/\n\t\tstatic canPlayType(type) {\n\t\t\treturn AudioTrack._verifyType(type) !== null;\n\t\t}\n\t}\n\n\t// Attach the static data members.\n\tObject.defineProperties(AudioTrack, {\n\t\t/*\n\t\t\tFormat-ID to MIME-type mappings for common audio types.\n\n\t\t\tIn most cases, the codecs property should not be included with the MIME-type,\n\t\t\tas we have no way of knowing which codec was used—and the browser will figure\n\t\t\tit out.  Conversely, in cases where the relationship relationship between a\n\t\t\tformat-ID and a specific codec is strong, we should include the codecs property.\n\n\t\t\tNOTE: Caveats by browser/engine:\n\t\t\t\tOpera ≤12 (Presto) will return a false-negative if the codecs value is quoted\n\t\t\t\twith single quotes, requiring the use of either double quotes or no quotes.\n\n\t\t\t\tBlink-based browsers (e.g. Chrome, Opera ≥15) will return a false-negative\n\t\t\t\tfor WAVE audio if the preferred MIME-type of 'audio/wave' is specified,\n\t\t\t\trequiring the use of 'audio/wav' instead.\n\t\t*/\n\t\tformats : {\n\t\t\tvalue : { // Leave this object extensible for users.\n\t\t\t\t// AAC — MPEG-2 AAC audio; specific profiles vary, but commonly \"AAC-LC\".\n\t\t\t\taac : 'audio/aac',\n\n\t\t\t\t// CAF — Codecs vary.\n\t\t\t\tcaf     : 'audio/x-caf',\n\t\t\t\t'x-caf' : 'audio/x-caf',\n\n\t\t\t\t// MP3 — MPEG-1/-2 Layer-III audio.\n\t\t\t\tmp3  : 'audio/mpeg; codecs=\"mp3\"',\n\t\t\t\tmpeg : 'audio/mpeg; codecs=\"mp3\"',\n\n\t\t\t\t// MP4 — Codecs vary, but commonly \"mp4a.40.2\" (a.k.a. \"AAC-LC\").\n\t\t\t\tm4a     : 'audio/mp4',\n\t\t\t\tmp4     : 'audio/mp4',\n\t\t\t\t'x-m4a' : 'audio/mp4',\n\t\t\t\t'x-mp4' : 'audio/mp4',\n\n\t\t\t\t// OGG — Codecs vary, but commonly \"vorbis\" and, recently, \"opus\".\n\t\t\t\toga : 'audio/ogg',\n\t\t\t\togg : 'audio/ogg',\n\n\t\t\t\t// OPUS — Opus audio in an Ogg container.\n\t\t\t\topus : 'audio/ogg; codecs=\"opus\"',\n\n\t\t\t\t// WAVE — Codecs vary, but commonly \"1\" (1 is the FourCC for PCM/LPCM).\n\t\t\t\twav  : 'audio/wav',\n\t\t\t\twave : 'audio/wav',\n\n\t\t\t\t// WEBM — Codecs vary, but commonly \"vorbis\" and, recently, \"opus\".\n\t\t\t\tweba : 'audio/webm',\n\t\t\t\twebm : 'audio/webm'\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t\tCache of supported MIME-types.\n\t\t*/\n\t\t_types : {\n\t\t\tvalue : {}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAudioList Class.\n\t*******************************************************************************************************************/\n\tclass AudioList {\n\t\tconstructor(obj) {\n\t\t\t// Process the given array of track objects or AudioList object.\n\t\t\tif (obj instanceof Array) {\n\t\t\t\tthis._create(obj);\n\t\t\t}\n\t\t\telse if (obj instanceof AudioList) {\n\t\t\t\tthis._copy(obj);\n\t\t\t\t// this._create(obj.tracks);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('tracks parameter must be either an array, of track objects, or an AudioTrack instance');\n\t\t\t}\n\t\t}\n\n\t\t_create(trackList) {\n\t\t\t// Map the array of tracks to playlist track objects.\n\t\t\tthis._finalize(trackList.map(trackObj => {\n\t\t\t\tif (typeof trackObj !== 'object') { // lazy equality for null\n\t\t\t\t\tthrow new Error('tracks parameter array members must be objects');\n\t\t\t\t}\n\n\t\t\t\tlet own;\n\t\t\t\tlet rate;\n\t\t\t\tlet track;\n\t\t\t\tlet volume;\n\n\t\t\t\tif (trackObj instanceof AudioTrack) {\n\t\t\t\t\town    = true;\n\t\t\t\t\trate   = trackObj.rate();\n\t\t\t\t\ttrack  = trackObj.clone();\n\t\t\t\t\tvolume = trackObj.volume();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (!trackObj.hasOwnProperty('track')) {\n\t\t\t\t\t\tthrow new Error('track object missing required \"track\" property');\n\t\t\t\t\t}\n\t\t\t\t\telse if (!(trackObj.track instanceof AudioTrack)) {\n\t\t\t\t\t\tthrow new Error('track object\\'s \"track\" property must be an AudioTrack object');\n\t\t\t\t\t}\n\t\t\t\t\t// else if (!trackObj.hasOwnProperty('volume')) {\n\t\t\t\t\t// \tthrow new Error('track object missing required \"volume\" property');\n\t\t\t\t\t// }\n\n\t\t\t\t\town    = trackObj.hasOwnProperty('own') && trackObj.own;\n\t\t\t\t\trate   = trackObj.hasOwnProperty('rate') ? trackObj.rate : trackObj.track.rate();\n\t\t\t\t\ttrack  = trackObj.track;\n\t\t\t\t\tvolume = trackObj.hasOwnProperty('volume') ? trackObj.volume : trackObj.track.volume();\n\t\t\t\t}\n\n\t\t\t\ttrack.stop();\n\t\t\t\ttrack.loop(false);\n\t\t\t\ttrack.mute(false);\n\t\t\t\ttrack.rate(rate);\n\t\t\t\ttrack.volume(volume);\n\t\t\t\ttrack.on('ended.AudioList', () => this._onEnd());\n\n\t\t\t\treturn { own, track, volume, rate };\n\t\t\t}));\n\t\t}\n\n\t\t_copy(obj) {\n\t\t\tthis._finalize(clone(obj.tracks));\n\t\t}\n\n\t\t_finalize(tracks) {\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\ttracks : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : Object.freeze(tracks)\n\t\t\t\t},\n\n\t\t\t\tqueue : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : []\n\t\t\t\t},\n\n\t\t\t\tcurrent : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_rate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_volume : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_mute : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_loop : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_shuffle : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t_destroy() {\n\t\t\t/*\n\t\t\t\tStrictly speaking, self-destruction is not necessary as this object will,\n\t\t\t\teventually, be garbage collected.\n\t\t\t*/\n\t\t\t// Stop playback.\n\t\t\tthis.stop();\n\n\t\t\t// Destroy all owned tracks.\n\t\t\tthis.tracks\n\t\t\t\t.filter(trackObj => trackObj.own)\n\t\t\t\t.forEach(trackObj => trackObj.track._destroy());\n\n\t\t\t// Delete the reference-type properties.\n\t\t\tdelete this.tracks;\n\t\t\tdelete this.queue;\n\t\t}\n\n\t\tload() {\n\t\t\tthis.tracks.forEach(trackObj => trackObj.track.load());\n\t\t}\n\n\t\tunload() {\n\t\t\tthis.stop();\n\t\t\tthis.tracks.forEach(trackObj => trackObj.track.unload());\n\t\t}\n\n\t\tplay() {\n\t\t\tif (this.current === null || this.current.track.isUnavailable() || this.current.track.isEnded()) {\n\t\t\t\tif (this.queue.length === 0) {\n\t\t\t\t\tthis._fillQueue();\n\t\t\t\t}\n\n\t\t\t\tif (!this._next()) {\n\t\t\t\t\treturn Promise.reject(new Error('no tracks were available'));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.current.track.play();\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tthis.play().catch(() => {\n\t\t\t\tconst gestures = _gestureEventNames.map(name => `${name}.AudioList_playWhenAllowed`).join(' ');\n\t\t\t\tjQuery(document).one(gestures, () => {\n\t\t\t\t\tjQuery(document).off('.AudioList_playWhenAllowed');\n\t\t\t\t\tthis.play();\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tpause() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.pause();\n\t\t\t}\n\t\t}\n\n\t\tstop() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.stop();\n\t\t\t\tthis.current = null;\n\t\t\t}\n\n\t\t\tthis._drainQueue();\n\t\t}\n\n\t\tskip() {\n\t\t\tif (this._next()) {\n\t\t\t\tthis.current.track.play();\n\t\t\t}\n\t\t\telse if (this._loop) {\n\t\t\t\tthis.play();\n\t\t\t}\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (typeof duration !== 'number') {\n\t\t\t\tthrow new TypeError('duration parameter must be a number');\n\t\t\t}\n\t\t\tif (typeof toVol !== 'number') {\n\t\t\t\tthrow new TypeError('toVolume parameter must be a number');\n\t\t\t}\n\t\t\tif (fromVol != null && typeof fromVol !== 'number') { // lazy equality for null\n\t\t\t\tthrow new TypeError('fromVolume parameter must be a number');\n\t\t\t}\n\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\tthis._fillQueue();\n\t\t\t}\n\n\t\t\tif (this.current === null || this.current.track.isUnavailable() || this.current.track.isEnded()) {\n\t\t\t\tif (!this._next()) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst adjToVol = Math.clamp(toVol, 0, 1) * this.current.volume;\n\t\t\tlet adjFromVol;\n\n\t\t\tif (fromVol != null) { // lazy equality for null\n\t\t\t\tadjFromVol = Math.clamp(fromVol, 0, 1) * this.current.volume;\n\t\t\t}\n\n\t\t\tthis._volume = toVol; // NOTE: Kludgey, but necessary.\n\n\t\t\treturn this.current.track.fade(duration, adjToVol, adjFromVol);\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\treturn this.fade(duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\treturn this.fade(duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.fadeStop();\n\t\t\t}\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\treturn this._loop;\n\t\t\t}\n\n\t\t\tthis._loop = !!loop;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\treturn this._mute;\n\t\t\t}\n\n\t\t\tthis._mute = !!mute;\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.mute(this._mute);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\treturn this._rate;\n\t\t\t}\n\n\t\t\tif (typeof rate !== 'number') {\n\t\t\t\tthrow new TypeError('rate parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._rate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.rate(this._rate * this.current.rate);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tshuffle(shuffle) {\n\t\t\tif (shuffle == null) { // lazy equality for null\n\t\t\t\treturn this._shuffle;\n\t\t\t}\n\n\t\t\tthis._shuffle = !!shuffle;\n\n\t\t\tif (this.queue.length > 0) {\n\t\t\t\tthis._fillQueue();\n\n\t\t\t\t// Try not to immediately replay the last track when not shuffling.\n\t\t\t\tif (!this._shuffle && this.current !== null && this.queue.length > 1) {\n\t\t\t\t\tconst firstIdx = this.queue.findIndex(trackObj => trackObj === this.current);\n\n\t\t\t\t\tif (firstIdx !== -1) {\n\t\t\t\t\t\tthis.queue.push(...this.queue.splice(0, firstIdx + 1));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\treturn this._volume;\n\t\t\t}\n\n\t\t\tif (typeof volume !== 'number') {\n\t\t\t\tthrow new TypeError('volume parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._volume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.volume(this._volume * this.current.volume);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tduration() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('duration takes no parameters');\n\t\t\t}\n\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.tracks\n\t\t\t\t.map(trackObj => trackObj.track.duration())\n\t\t\t\t.reduce((prev, cur) => prev + cur, 0);\n\t\t}\n\n\t\tremaining() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('remaining takes no parameters');\n\t\t\t}\n\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\tlet remainingTime = this.queue\n\t\t\t\t.map(trackObj => trackObj.track.duration())\n\t\t\t\t.reduce((prev, cur) => prev + cur, 0);\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tremainingTime += this.current.track.remaining();\n\t\t\t}\n\n\t\t\treturn remainingTime;\n\t\t}\n\n\t\ttime() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('time takes no parameters');\n\t\t\t}\n\n\t\t\treturn this.duration() - this.remaining();\n\t\t}\n\n\t\tisPlaying() {\n\t\t\treturn this.current !== null && this.current.track.isPlaying();\n\t\t}\n\n\t\tisPaused() {\n\t\t\treturn this.current === null || this.current.track.isPaused();\n\t\t}\n\n\t\tisStopped() {\n\t\t\treturn this.queue.length === 0 && this.current === null;\n\t\t}\n\n\t\tisEnded() {\n\t\t\treturn this.queue.length === 0 && (this.current === null || this.current.track.isEnded());\n\t\t}\n\n\t\tisFading() {\n\t\t\treturn this.current !== null && this.current.track.isFading();\n\t\t}\n\n\t\t_next() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.stop();\n\t\t\t\tthis.current = null;\n\t\t\t}\n\n\t\t\tlet nextTrack;\n\n\t\t\twhile ((nextTrack = this.queue.shift())) {\n\t\t\t\tif (!nextTrack.track.isUnavailable()) {\n\t\t\t\t\tthis.current = nextTrack;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.current === null) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis.current.track.mute(this._mute);\n\t\t\tthis.current.track.rate(this._rate * this.current.rate);\n\t\t\tthis.current.track.volume(this._volume * this.current.volume);\n\n\t\t\t// Attempt to protect against the `loop` state being reenabled\n\t\t\t// outside of the playlist.  Mostly for unowned tracks.\n\t\t\t//\n\t\t\t// TODO: Should we reapply the `ended` event handler too?\n\t\t\tthis.current.track.loop(false);\n\n\t\t\treturn true;\n\t\t}\n\n\t\t_onEnd() {\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\tif (!this._loop) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._fillQueue();\n\t\t\t}\n\n\t\t\tif (!this._next()) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.current.track.play();\n\t\t}\n\n\t\t_drainQueue() {\n\t\t\tthis.queue.splice(0);\n\t\t}\n\n\t\t_fillQueue() {\n\t\t\tthis._drainQueue();\n\t\t\tthis.queue.push(...this.tracks.filter(trackObj => !trackObj.track.isUnavailable()));\n\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (this._shuffle) {\n\t\t\t\tthis.queue.shuffle();\n\n\t\t\t\t// Try not to immediately replay the last track when shuffling.\n\t\t\t\tif (this.queue.length > 1 && this.queue[0] === this.current) {\n\t\t\t\t\tthis.queue.push(this.queue.shift());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAudioRunner Class.\n\t*******************************************************************************************************************/\n\tclass AudioRunner {\n\t\tconstructor(list) {\n\t\t\tif (!(list instanceof Set || list instanceof AudioRunner)) {\n\t\t\t\tthrow new TypeError('list parameter must be a Set or a AudioRunner instance');\n\t\t\t}\n\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\ttrackIds : {\n\t\t\t\t\tvalue : new Set(list instanceof AudioRunner ? list.trackIds : list)\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tload() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.load);\n\t\t}\n\n\t\tunload() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.unload);\n\t\t}\n\n\t\tplay() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.play);\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.playWhenAllowed);\n\t\t}\n\n\t\tpause() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.pause);\n\t\t}\n\n\t\tstop() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.stop);\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (duration == null || toVol == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fade requires parameters');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fade, duration, toVol, fromVol);\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\tif (duration == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fadeIn requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeIn, duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\tif (duration == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fadeOut requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeOut, duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeStop);\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\tthrow new Error('loop requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.loop, loop);\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\tthrow new Error('mute requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.mute, mute);\n\t\t\treturn this;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\tthrow new Error('rate requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.rate, rate);\n\t\t\treturn this;\n\t\t}\n\n\t\ttime(time) {\n\t\t\tif (time == null) { // lazy equality for null\n\t\t\t\tthrow new Error('time requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.time, time);\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\tthrow new Error('volume requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.volume, volume);\n\t\t\treturn this;\n\t\t}\n\n\t\ton(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.on, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\tone(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.one, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\toff(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.off, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\tstatic _run(ids, fn, ...args) {\n\t\t\tids.forEach(id => {\n\t\t\t\tconst track = _tracks.get(id);\n\n\t\t\t\tif (track) {\n\t\t\t\t\tfn.apply(track, args);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTrack Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.tracks.add(trackId, sources…);\n\n\t\tE.g.\n\t\t\tSimpleAudio.tracks.add(\n\t\t\t\t'over_the_top',\n\t\t\t\t'https://audiohost.tld/id/over_the_top.mp3',\n\t\t\t\t'https://audiohost.tld/id/over_the_top.ogg'\n\t\t\t);\n\t*/\n\tfunction trackAdd(/* trackId , sources… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('track ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('sources'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `track ID \"${id}\"`;\n\n\t\tif (_badIdRe.test(id)) {\n\t\t\tthrow new Error(`invalid ${what}: track IDs must not contain colons or whitespace`);\n\t\t}\n\n\t\tconst sources = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet track;\n\n\t\ttry {\n\t\t\ttrack = _newTrack(sources);\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during track initialization: ${ex.message}`);\n\t\t}\n\n\t\t// If in Test Mode and no supported sources were specified, throw an error.\n\t\tif (Config.debug && !track.hasSource()) {\n\t\t\tthrow new Error(`${what}: no supported audio sources found`);\n\t\t}\n\n\t\t// If a track by the given ID already exists, destroy it.\n\t\tif (_tracks.has(id)) {\n\t\t\t_tracks.get(id)._destroy();\n\t\t}\n\n\t\t// Add the track to the cache.\n\t\t_tracks.set(id, track);\n\t}\n\n\tfunction trackDelete(id) {\n\t\tif (_tracks.has(id)) {\n\t\t\t_tracks.get(id)._destroy();\n\t\t}\n\n\t\t// TODO: Should this also remove references to the track from groups and playlists?\n\n\t\treturn _tracks.delete(id);\n\t}\n\n\tfunction trackClear() {\n\t\t_tracks.forEach(track => track._destroy());\n\t\t_tracks.clear();\n\t}\n\n\tfunction trackHas(id) {\n\t\treturn _tracks.has(id);\n\t}\n\n\tfunction trackGet(id) {\n\t\treturn _tracks.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tGroup Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.groups.add(groupId, trackIds…);\n\n\t\tE.g.\n\t\t\tSimpleAudio.groups.add(':ui', 'beep', 'boop', 'boing');\n\t*/\n\tfunction groupAdd(/* groupId , trackIds… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('group ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('track IDs'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `group ID \"${id}\"`;\n\n\t\tif (id[0] !== ':' || _badIdRe.test(id.slice(1))) {\n\t\t\tthrow new Error(`invalid ${what}: group IDs must start with a colon and must not contain colons or whitespace`);\n\t\t}\n\n\t\tif (_specialIds.includes(id)) {\n\t\t\tthrow new Error(`cannot clobber special ${what}`);\n\t\t}\n\n\t\tconst trackIds = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet group;\n\n\t\ttry {\n\t\t\tgroup = new Set(trackIds.map(trackId => {\n\t\t\t\tif (!_tracks.has(trackId)) {\n\t\t\t\t\tthrow new Error(`track \"${trackId}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\treturn trackId;\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during group initialization: ${ex.message}`);\n\t\t}\n\n\t\t// Add the group to the cache.\n\t\t_groups.set(id, Object.freeze(Array.from(group)));\n\t}\n\n\tfunction groupDelete(id) {\n\t\treturn _groups.delete(id);\n\t}\n\n\tfunction groupClear() {\n\t\t_groups.clear();\n\t}\n\n\tfunction groupHas(id) {\n\t\treturn _groups.has(id);\n\t}\n\n\tfunction groupGet(id) {\n\t\treturn _groups.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPlaylist Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.lists.add(listId, sources…);\n\t\t\tWhere `sources` may be either a track ID or descriptor (object).\n\t\t\tTrack descriptors are either { id, [own], [rate], [volume] } or { sources, [rate], [volume] }.\n\n\t\tNOTE: Rate properties are currently unsupported due to poor browser support.\n\n\t\tE.g.\n\t\t\tSimpleAudio.lists.add(\n\t\t\t\t'bgm',\n\t\t\t\t'over_the_top',\n\t\t\t\t{\n\t\t\t\t\tid     : 'heavens_a_lie',\n\t\t\t\t\tvolume : 0.5,\n\t\t\t\t\town    : true\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tsources : [\n\t\t\t\t\t\t'https://audiohost.tld/id/swamped.mp3',\n\t\t\t\t\t\t'https://audiohost.tld/id/swamped.ogg'\n\t\t\t\t\t],\n\t\t\t\t\tvolume  : 0.75\n\t\t\t\t}\n\t\t\t);\n\t*/\n\tfunction listAdd(/* listId , sources… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('list ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('track IDs'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `list ID \"${id}\"`;\n\n\t\tif (_badIdRe.test(id)) {\n\t\t\treturn this.error(`invalid ${what}: list IDs must not contain colons or whitespace`);\n\t\t}\n\n\t\tconst descriptors = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet list;\n\n\t\ttry {\n\t\t\tlist = new AudioList(descriptors.map(desc => {\n\t\t\t\tif (desc === null) {\n\t\t\t\t\tthrow new Error('track descriptor must be a string or object (type: null)');\n\t\t\t\t}\n\n\t\t\t\tswitch (typeof desc) {\n\t\t\t\tcase 'string':\n\t\t\t\t\t// Simply a track ID, so convert it into an object.\n\t\t\t\t\tdesc = { id : desc }; // eslint-disable-line no-param-reassign\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\tif (!desc.hasOwnProperty('id') && !desc.hasOwnProperty('sources')) {\n\t\t\t\t\t\tthrow new Error('track descriptor must contain one of either an \"id\" or a \"sources\" property');\n\t\t\t\t\t}\n\t\t\t\t\telse if (desc.hasOwnProperty('id') && desc.hasOwnProperty('sources')) {\n\t\t\t\t\t\tthrow new Error('track descriptor must contain either an \"id\" or a \"sources\" property, not both');\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`track descriptor must be a string or object (type: ${typeof desc})`);\n\t\t\t\t}\n\n\t\t\t\tlet own;\n\t\t\t\t// let rate;\n\t\t\t\tlet track;\n\t\t\t\tlet volume;\n\n\t\t\t\tif (desc.hasOwnProperty('id')) {\n\t\t\t\t\tif (typeof desc.id !== 'string') {\n\t\t\t\t\t\tthrow new Error('\"id\" property must be a string');\n\t\t\t\t\t}\n\t\t\t\t\tif (!_tracks.has(desc.id)) {\n\t\t\t\t\t\tthrow new Error(`track \"${desc.id}\" does not exist`);\n\t\t\t\t\t}\n\n\t\t\t\t\ttrack = _tracks.get(desc.id);\n\t\t\t\t}\n\t\t\t\telse if (desc.hasOwnProperty('sources')) {\n\t\t\t\t\tif (!Array.isArray(desc.sources) || desc.sources.length === 0) {\n\t\t\t\t\t\tthrow new Error('\"sources\" property must be a non-empty array');\n\t\t\t\t\t}\n\t\t\t\t\tif (desc.hasOwnProperty('own')) {\n\t\t\t\t\t\tthrow new Error('\"own\" property is not allowed with the \"sources\" property');\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\ttrack = _newTrack(desc.sources);\n\t\t\t\t\t\town = true;\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`error during track initialization: ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// If in Test Mode and no supported sources were specified, return an error.\n\t\t\t\t\tif (Config.debug && !track.hasSource()) {\n\t\t\t\t\t\tthrow new Error('no supported audio sources found');\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (desc.hasOwnProperty('own')) {\n\t\t\t\t\tif (typeof desc.own !== 'boolean') {\n\t\t\t\t\t\tthrow new Error('\"own\" property must be a boolean');\n\t\t\t\t\t}\n\n\t\t\t\t\town = desc.own;\n\n\t\t\t\t\tif (own) {\n\t\t\t\t\t\ttrack = track.clone();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if (desc.hasOwnProperty('rate')) {\n\t\t\t\t// \tif (\n\t\t\t\t// \t\t   typeof desc.rate !== 'number'\n\t\t\t\t// \t\t|| Number.isNaN(desc.rate)\n\t\t\t\t// \t\t|| !Number.isFinite(desc.rate)\n\t\t\t\t// \t) {\n\t\t\t\t// \t\tthrow new Error('\"rate\" property must be a finite number');\n\t\t\t\t// \t}\n\t\t\t\t//\n\t\t\t\t// \trate = desc.rate;\n\t\t\t\t// }\n\n\t\t\t\tif (desc.hasOwnProperty('volume')) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t   typeof desc.volume !== 'number'\n\t\t\t\t\t\t|| Number.isNaN(desc.volume)\n\t\t\t\t\t\t|| !Number.isFinite(desc.volume)\n\t\t\t\t\t\t|| desc.volume < 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new Error('\"volume\" property must be a non-negative finite number');\n\t\t\t\t\t}\n\n\t\t\t\t\tvolume = desc.volume;\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\town    : own != null ? own : false, // lazy equality for null,\n\t\t\t\t\t// rate   : rate != null ? rate : track.rate(), // lazy equality for null,\n\t\t\t\t\ttrack,\n\t\t\t\t\tvolume : volume != null ? volume : track.volume() // lazy equality for null\n\t\t\t\t};\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during playlist initialization: ${ex.message}`);\n\t\t}\n\n\t\t// If a playlist by the given ID already exists, destroy it.\n\t\tif (_lists.has(id)) {\n\t\t\t_lists.get(id)._destroy();\n\t\t}\n\n\t\t// Add the playlist to the cache.\n\t\t_lists.set(id, list);\n\t}\n\n\tfunction listDelete(id) {\n\t\tif (_lists.has(id)) {\n\t\t\t_lists.get(id)._destroy();\n\t\t}\n\n\t\treturn _lists.delete(id);\n\t}\n\n\tfunction listClear() {\n\t\t_lists.forEach(list => list._destroy());\n\t\t_lists.clear();\n\t}\n\n\tfunction listHas(id) {\n\t\treturn _lists.has(id);\n\t}\n\n\tfunction listGet(id) {\n\t\treturn _lists.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tRunner Functions.\n\t*******************************************************************************************************************/\n\tconst _runnerParseSelector = (() => {\n\t\tconst notWsRe = /\\S/g;\n\t\tconst parenRe = /[()]/g;\n\n\t\tfunction processNegation(str, startPos) {\n\t\t\tlet match;\n\n\t\t\tnotWsRe.lastIndex = startPos;\n\t\t\tmatch = notWsRe.exec(str);\n\n\t\t\tif (match === null || match[0] !== '(') {\n\t\t\t\tthrow new Error('invalid \":not()\" syntax: missing parentheticals');\n\t\t\t}\n\n\t\t\tparenRe.lastIndex = notWsRe.lastIndex;\n\t\t\tconst start  = notWsRe.lastIndex;\n\t\t\tconst result = { str : '', nextMatch : -1 };\n\t\t\tlet depth = 1;\n\n\t\t\twhile ((match = parenRe.exec(str)) !== null) {\n\t\t\t\tif (match[0] === '(') {\n\t\t\t\t\t++depth;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t--depth;\n\t\t\t\t}\n\n\t\t\t\tif (depth < 1) {\n\t\t\t\t\tresult.nextMatch = parenRe.lastIndex;\n\t\t\t\t\tresult.str = str.slice(start, result.nextMatch - 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tfunction parseSelector(idArg) {\n\t\t\tconst ids  = [];\n\t\t\tconst idRe = /:?[^\\s:()]+/g;\n\t\t\tlet match;\n\n\t\t\twhile ((match = idRe.exec(idArg)) !== null) {\n\t\t\t\tconst id = match[0];\n\n\t\t\t\t// Group negation.\n\t\t\t\tif (id === ':not') {\n\t\t\t\t\tif (ids.length === 0) {\n\t\t\t\t\t\tthrow new Error('invalid negation: no group ID preceded \":not()\"');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst parent = ids[ids.length - 1];\n\n\t\t\t\t\tif (parent.id[0] !== ':') {\n\t\t\t\t\t\tthrow new Error(`invalid negation of track \"${parent.id}\": only groups may be negated with \":not()\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst negation = processNegation(idArg, idRe.lastIndex);\n\n\t\t\t\t\tif (negation.nextMatch === -1) {\n\t\t\t\t\t\tthrow new Error('unknown error parsing \":not()\"');\n\t\t\t\t\t}\n\n\t\t\t\t\tidRe.lastIndex = negation.nextMatch;\n\t\t\t\t\tparent.not = parseSelector(negation.str);\n\t\t\t\t}\n\n\t\t\t\t// Group or track ID.\n\t\t\t\telse {\n\t\t\t\t\tids.push({ id });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn ids;\n\t\t}\n\n\t\treturn parseSelector;\n\t})();\n\n\t/*\n\t\tSimpleAudio.select(selector).…;\n\n\t\tE.g.\n\t\t\tSimpleAudio.select(':ui').…\n\t\t\tSimpleAudio.select(':ui:not(boop)').…\n\t\t\tSimpleAudio.select('boop beep').…\n\t\t\tSimpleAudio.select(':ui :sfx').…\n\t\t\tSimpleAudio.select(':ui:not(boop) :sfx overthetop').…\n\t*/\n\tfunction runnerGet(/* selector */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('no track selector specified');\n\t\t}\n\n\t\tconst selector = String(arguments[0]).trim();\n\t\tconst trackIds = new Set();\n\n\t\ttry {\n\t\t\tconst allIds = Array.from(_tracks.keys());\n\n\t\t\tfunction renderIds(idObj) {\n\t\t\t\tconst id = idObj.id;\n\t\t\t\tlet ids;\n\n\t\t\t\tswitch (id) {\n\t\t\t\tcase ':all':     ids = allIds; break;\n\t\t\t\tcase ':looped':  ids = allIds.filter(id => _tracks.get(id).loop()); break;\n\t\t\t\tcase ':muted':   ids = allIds.filter(id => _tracks.get(id).mute()); break;\n\t\t\t\tcase ':paused':  ids = allIds.filter(id => _tracks.get(id).isPaused()); break;\n\t\t\t\tcase ':playing': ids = allIds.filter(id => _tracks.get(id).isPlaying()); break;\n\t\t\t\tdefault:         ids = id[0] === ':' ? _groups.get(id) : [id]; break;\n\t\t\t\t}\n\n\t\t\t\tif (idObj.hasOwnProperty('not')) {\n\t\t\t\t\tconst negated = idObj.not.map(idObj => renderIds(idObj)).flat(Infinity);\n\t\t\t\t\tids = ids.filter(id => !negated.includes(id));\n\t\t\t\t}\n\n\t\t\t\treturn ids;\n\t\t\t}\n\n\t\t\t_runnerParseSelector(selector).forEach(idObj => renderIds(idObj).forEach(id => {\n\t\t\t\tif (!_tracks.has(id)) {\n\t\t\t\t\tthrow new Error(`track \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\ttrackIds.add(id);\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`error during runner initialization: ${ex.message}`);\n\t\t}\n\n\t\treturn new AudioRunner(trackIds);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMaster Audio Functions.\n\t*******************************************************************************************************************/\n\tfunction masterLoad() {\n\t\tpublish('load');\n\t}\n\n\tfunction masterLoadWithScreen() {\n\t\tpublish('loadwithscreen');\n\t}\n\n\tfunction masterMute(mute) {\n\t\tif (mute == null) { // lazy equality for null\n\t\t\treturn _masterMute;\n\t\t}\n\n\t\t_masterMute = !!mute;\n\t\tpublish('mute', _masterMute);\n\t}\n\n\tfunction masterMuteOnHidden(mute) {\n\t\t// NOTE: Some older browsers—notably: IE 9—do not support the Page Visibility API.\n\t\tif (!Visibility.isEnabled()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (mute == null) { // lazy equality for null\n\t\t\treturn _masterMuteOnHidden;\n\t\t}\n\n\t\t_masterMuteOnHidden = !!mute;\n\n\t\tconst namespace = '.SimpleAudio_masterMuteOnHidden';\n\n\t\tif (_masterMuteOnHidden) {\n\t\t\tconst visibilityChange = `${Visibility.changeEvent}${namespace}`;\n\t\t\tjQuery(document)\n\t\t\t\t.off(namespace)\n\t\t\t\t.on(visibilityChange, () => masterMute(Visibility.isHidden()));\n\n\t\t\t// Only change the mute state initially if hidden.\n\t\t\tif (Visibility.isHidden()) {\n\t\t\t\tmasterMute(true);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tjQuery(document).off(namespace);\n\t\t}\n\t}\n\n\tfunction masterRate(rate) {\n\t\tif (rate == null) { // lazy equality for null\n\t\t\treturn _masterRate;\n\t\t}\n\n\t\tif (typeof rate !== 'number' || Number.isNaN(rate) || !Number.isFinite(rate)) {\n\t\t\tthrow new Error('rate must be a finite number');\n\t\t}\n\n\t\t_masterRate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\t\tpublish('rate', _masterRate);\n\t}\n\n\tfunction masterStop() {\n\t\tpublish('stop');\n\t}\n\n\tfunction masterUnload() {\n\t\tpublish('unload');\n\t}\n\n\tfunction masterVolume(volume) {\n\t\tif (volume == null) { // lazy equality for null\n\t\t\treturn _masterVolume;\n\t\t}\n\n\t\tif (typeof volume !== 'number' || Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\tthrow new Error('volume must be a finite number');\n\t\t}\n\n\t\t_masterVolume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\t\tpublish('volume', _masterVolume);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSubscription Functions.\n\t*******************************************************************************************************************/\n\tfunction subscribe(id, callback) {\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new Error('callback parameter must be a function');\n\t\t}\n\n\t\t_subscribers.set(id, callback);\n\t}\n\n\tfunction unsubscribe(id) {\n\t\t_subscribers.delete(id);\n\t}\n\n\tfunction publish(mesg, data) {\n\t\t_subscribers.forEach(fn => fn(mesg, data));\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _newTrack(sources) {\n\t\treturn new AudioTrack(sources.map(source => {\n\t\t\t// Handle audio passages.\n\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\tif (passage.tags.includes('Twine.audio')) {\n\t\t\t\t\treturn passage.text.trim();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle URIs—possibly prefixed with a format specifier.\n\t\t\tconst match = _formatSpecRe.exec(source);\n\t\t\treturn match === null ? source : {\n\t\t\t\tformat : match[1],\n\t\t\t\tsrc    : match[2]\n\t\t\t};\n\t\t}));\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Track Functions.\n\t\ttracks : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : trackAdd },\n\t\t\t\tdelete : { value : trackDelete },\n\t\t\t\tclear  : { value : trackClear },\n\t\t\t\thas    : { value : trackHas },\n\t\t\t\tget    : { value : trackGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Group Functions.\n\t\tgroups : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : groupAdd },\n\t\t\t\tdelete : { value : groupDelete },\n\t\t\t\tclear  : { value : groupClear },\n\t\t\t\thas    : { value : groupHas },\n\t\t\t\tget    : { value : groupGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Playlist Functions.\n\t\tlists : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : listAdd },\n\t\t\t\tdelete : { value : listDelete },\n\t\t\t\tclear  : { value : listClear },\n\t\t\t\thas    : { value : listHas },\n\t\t\t\tget    : { value : listGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Runner Functions.\n\t\tselect : { value : runnerGet },\n\n\t\t// Master Audio Functions.\n\t\tload           : { value : masterLoad },\n\t\tloadWithScreen : { value : masterLoadWithScreen },\n\t\tmute           : { value : masterMute },\n\t\tmuteOnHidden   : { value : masterMuteOnHidden },\n\t\trate           : { value : masterRate },\n\t\tstop           : { value : masterStop },\n\t\tunload         : { value : masterUnload },\n\t\tvolume         : { value : masterVolume }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tstate.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Diff, Engine, PRNGWrapper, Patterns, clone, session, storage */\n\nvar State = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// History moment stack.\n\tlet _history = [];\n\n\t// Currently active/played moment.\n\tlet _active = momentCreate();\n\n\t// Currently active/played moment index.\n\tlet _activeIndex = -1;\n\n\t// Titles of all moments which have expired (i.e. fallen off the bottom of the stack).\n\tlet _expired = [];\n\n\t// (optional) Seedable PRNG object.\n\tlet _prng = null;\n\n\t// Temporary variables object.\n\tlet _tempVariables = {};\n\n\n\t/*******************************************************************************************************************\n\t\tState Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tResets the story state.\n\t*/\n\tfunction stateReset() {\n\t\tif (DEBUG) { console.log('[State/stateReset()]'); }\n\n\t\t/*\n\t\t\tDelete the active session.\n\t\t*/\n\t\tsession.delete('state');\n\n\t\t/*\n\t\t\tReset the properties.\n\t\t*/\n\t\t_history     = [];\n\t\t_active      = momentCreate();\n\t\t_activeIndex = -1;\n\t\t_expired     = [];\n\t\t_prng        = _prng === null ? null : new PRNGWrapper(_prng.seed, false);\n\t}\n\n\t/*\n\t\tRestores the story state from the active session.\n\t*/\n\tfunction stateRestore() {\n\t\tif (DEBUG) { console.log('[State/stateRestore()]'); }\n\n\t\t/*\n\t\t\tAttempt to restore an active session.\n\t\t*/\n\t\tif (session.has('state')) {\n\t\t\t/*\n\t\t\t\tRetrieve the session.\n\t\t\t*/\n\t\t\tconst stateObj = session.get('state');\n\n\t\t\tif (DEBUG) { console.log('\\tsession state:', stateObj); }\n\n\t\t\tif (stateObj == null) { // lazy equality for null\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tRestore the session.\n\t\t\t*/\n\t\t\tstateUnmarshal(stateObj);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tReturns the current story state marshaled into a serializable object.\n\t*/\n\tfunction stateMarshal(noDelta) {\n\t\t/*\n\t\t\tGather the properties.\n\t\t*/\n\t\tconst stateObj = {\n\t\t\tindex : _activeIndex\n\t\t};\n\n\t\tif (noDelta) {\n\t\t\tstateObj.history = clone(_history);\n\t\t}\n\t\telse {\n\t\t\tstateObj.delta = historyDeltaEncode(_history);\n\t\t}\n\n\t\tif (_expired.length > 0) {\n\t\t\tstateObj.expired = [];\n\t\t}\n\n\t\tif (_prng !== null) {\n\t\t\tstateObj.seed = _prng.seed;\n\t\t}\n\n\t\treturn stateObj;\n\t}\n\n\t/*\n\t\tRestores the story state from a marshaled story state serialization object.\n\t*/\n\tfunction stateUnmarshal(stateObj, noDelta) {\n\t\tif (stateObj == null) { // lazy equality for null\n\t\t\tthrow new Error('state object is null or undefined');\n\t\t}\n\n\t\tif (\n\t\t\t   !stateObj.hasOwnProperty(noDelta ? 'history' : 'delta')\n\t\t\t|| stateObj[noDelta ? 'history' : 'delta'].length === 0\n\t\t) {\n\t\t\tthrow new Error('state object has no history or history is empty');\n\t\t}\n\n\t\tif (!stateObj.hasOwnProperty('index')) {\n\t\t\tthrow new Error('state object has no index');\n\t\t}\n\n\t\tif (_prng !== null && !stateObj.hasOwnProperty('seed')) {\n\t\t\tthrow new Error('state object has no seed, but PRNG is enabled');\n\t\t}\n\n\t\tif (_prng === null && stateObj.hasOwnProperty('seed')) {\n\t\t\tthrow new Error('state object has seed, but PRNG is disabled');\n\t\t}\n\n\t\t/*\n\t\t\tRestore the properties.\n\t\t*/\n\t\t_history     = noDelta ? clone(stateObj.history) : historyDeltaDecode(stateObj.delta);\n\t\t_activeIndex = stateObj.index;\n\t\t_expired     = stateObj.hasOwnProperty('expired') ? [...stateObj.expired] : [];\n\n\t\tif (stateObj.hasOwnProperty('seed')) {\n\t\t\t/*\n\t\t\t\tWe only need to restore the PRNG's seed here as `momentActivate()` will handle\n\t\t\t\tfully restoring the PRNG to its proper state.\n\t\t\t*/\n\t\t\t_prng.seed = stateObj.seed;\n\t\t}\n\n\t\t/*\n\t\t\tActivate the current moment (do this only after all properties have been restored).\n\t\t*/\n\t\tmomentActivate(_activeIndex);\n\t}\n\n\t/*\n\t\tReturns the current story state marshaled into a save-compatible serializable object.\n\t*/\n\tfunction stateMarshalForSave() {\n\t\treturn stateMarshal(true);\n\t}\n\n\t/*\n\t\tRestores the story state from a marshaled save-compatible story state serialization object.\n\t*/\n\tfunction stateUnmarshalForSave(stateObj) {\n\t\treturn stateUnmarshal(stateObj, true);\n\t}\n\n\t/*\n\t\tReturns the titles of expired moments.\n\t*/\n\tfunction stateExpired() {\n\t\treturn _expired;\n\t}\n\n\t/*\n\t\tReturns the total number of played moments (expired + in-play history moments).\n\t*/\n\tfunction stateTurns() {\n\t\treturn _expired.length + historyLength();\n\t}\n\n\t/*\n\t\tReturns the passage titles of all played moments (expired + in-play history moments).\n\t*/\n\tfunction stateTitles() {\n\t\treturn _expired.concat(_history.slice(0, historyLength()).map(moment => moment.title));\n\t}\n\n\t/*\n\t\tReturns whether a passage with the given title has been played (expired + in-play history moments).\n\t*/\n\tfunction stateHasPlayed(title) {\n\t\tif (title == null || title === '') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tif (_expired.includes(title)) {\n\t\t\treturn true;\n\t\t}\n\t\telse if (_history.slice(0, historyLength()).some(moment => moment.title === title)) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMoment Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a new moment object created from the given passage title and variables object.\n\t*/\n\tfunction momentCreate(title, variables) {\n\t\treturn {\n\t\t\ttitle     : title == null ? '' : String(title),       // lazy equality for null\n\t\t\tvariables : variables == null ? {} : clone(variables) // lazy equality for null\n\t\t};\n\t}\n\n\t/*\n\t\tReturns the active (present) moment.\n\t*/\n\tfunction momentActive() {\n\t\treturn _active;\n\t}\n\n\t/*\n\t\tReturns the index within the history of the active (present) moment.\n\t*/\n\tfunction momentActiveIndex() {\n\t\treturn _activeIndex;\n\t}\n\n\t/*\n\t\tReturns the title from the active (present) moment.\n\t*/\n\tfunction momentActiveTitle() {\n\t\treturn _active.title;\n\t}\n\n\t/*\n\t\tReturns the variables from the active (present) moment.\n\t*/\n\tfunction momentActiveVariables() {\n\t\treturn _active.variables;\n\t}\n\n\t/*\n\t\tReturns the active (present) moment after setting it to either the given moment object\n\t\tor the moment object at the given history index.  Additionally, updates the active session\n\t\tand triggers a history update event.\n\t*/\n\tfunction momentActivate(moment) {\n\t\tif (moment == null) { // lazy equality for null\n\t\t\tthrow new Error('moment activation attempted with null or undefined');\n\t\t}\n\n\t\t/*\n\t\t\tSet the active moment.\n\t\t*/\n\t\tswitch (typeof moment) {\n\t\tcase 'object':\n\t\t\t_active = clone(moment);\n\t\t\tbreak;\n\n\t\tcase 'number':\n\t\t\tif (historyIsEmpty()) {\n\t\t\t\tthrow new Error('moment activation attempted with index on empty history');\n\t\t\t}\n\n\t\t\tif (moment < 0 || moment >= historySize()) {\n\t\t\t\tthrow new RangeError(`moment activation attempted with out-of-bounds index; need [0, ${historySize() - 1}], got ${moment}`);\n\t\t\t}\n\n\t\t\t_active = clone(_history[moment]);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new TypeError(`moment activation attempted with a \"${typeof moment}\"; must be an object or valid history stack index`);\n\t\t}\n\n\t\t/*\n\t\t\tRestore the seedable PRNG.\n\n\t\t\tNOTE: We cannot simply set `_prng.pull` to `_active.pull` as that would\n\t\t\tnot properly mutate the PRNG's internal state.\n\t\t*/\n\t\tif (_prng !== null) {\n\t\t\t_prng = PRNGWrapper.unmarshal({\n\t\t\t\tseed : _prng.seed,\n\t\t\t\tpull : _active.pull\n\t\t\t});\n\t\t}\n\n\t\t/*\n\t\t\tUpdate the active session.\n\t\t*/\n\t\tsession.set('state', stateMarshal());\n\n\t\t/*\n\t\t\tTrigger a global `:historyupdate` event.\n\n\t\t\tNOTE: We do this here because setting a new active moment is a core component\n\t\t\tof, virtually, all history updates.\n\t\t*/\n\t\tjQuery.event.trigger(':historyupdate');\n\n\t\treturn _active;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tHistory Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the moment history.\n\t*/\n\tfunction historyGet() {\n\t\treturn _history;\n\t}\n\n\t/*\n\t\tReturns the number of active history moments (past only).\n\t*/\n\tfunction historyLength() {\n\t\treturn _activeIndex + 1;\n\t}\n\n\t/*\n\t\tReturns the total number of history moments (past + future).\n\t*/\n\tfunction historySize() {\n\t\treturn _history.length;\n\t}\n\n\t/*\n\t\tReturns whether the history is empty.\n\t*/\n\tfunction historyIsEmpty() {\n\t\treturn _history.length === 0;\n\t}\n\n\t/*\n\t\tReturns the current (pre-play version of the active) moment within the history.\n\t*/\n\tfunction historyCurrent() {\n\t\treturn _history.length > 0 ? _history[_activeIndex] : null;\n\t}\n\n\t/*\n\t\tReturns the topmost (most recent) moment within the history.\n\t*/\n\tfunction historyTop() {\n\t\treturn _history.length > 0 ? _history[_history.length - 1] : null;\n\t}\n\n\t/*\n\t\tReturns the bottommost (least recent) moment within the history.\n\t*/\n\tfunction historyBottom() {\n\t\treturn _history.length > 0 ? _history[0] : null;\n\t}\n\n\t/*\n\t\tReturns the moment at the given index within the history.\n\t*/\n\tfunction historyIndex(index) {\n\t\tif (historyIsEmpty() || index < 0 || index > _activeIndex) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn _history[index];\n\t}\n\n\t/*\n\t\tReturns the moment at the given offset from the active moment within the history.\n\t*/\n\tfunction historyPeek(offset) {\n\t\tif (historyIsEmpty()) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst lengthOffset = 1 + (offset ? Math.abs(offset) : 0);\n\n\t\tif (lengthOffset > historyLength()) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn _history[historyLength() - lengthOffset];\n\t}\n\n\t/*\n\t\tReturns whether a moment with the given title exists within the history.\n\t*/\n\tfunction historyHas(title) {\n\t\tif (historyIsEmpty() || title == null || title === '') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (let i = _activeIndex; i >= 0; --i) {\n\t\t\tif (_history[i].title === title) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tCreates a new moment and pushes it onto the history, discarding future moments if necessary.\n\t*/\n\tfunction historyCreate(title) {\n\t\tif (DEBUG) { console.log(`[State/historyCreate(title: \"${title}\")]`); }\n\n\t\t/*\n\t\t\tTODO: It might be good to have some assertions about the passage title here.\n\t\t*/\n\n\t\t/*\n\t\t\tIf we're not at the top of the stack, discard the future moments.\n\t\t*/\n\t\tif (historyLength() < historySize()) {\n\t\t\tif (DEBUG) { console.log(`\\tnon-top push; discarding ${historySize() - historyLength()} future moments`); }\n\n\t\t\t_history.splice(historyLength(), historySize() - historyLength());\n\t\t}\n\n\t\t/*\n\t\t\tPush the new moment onto the history stack.\n\t\t*/\n\t\t_history.push(momentCreate(title, _active.variables));\n\n\t\tif (_prng) {\n\t\t\thistoryTop().pull = _prng.pull;\n\t\t}\n\n\t\t/*\n\t\t\tTruncate the history, if necessary, by discarding moments from the bottom.\n\t\t*/\n\t\tif (Config.history.maxStates > 0) {\n\t\t\twhile (historySize() > Config.history.maxStates) {\n\t\t\t\t_expired.push(_history.shift().title);\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t\tActivate the new top moment.\n\t\t*/\n\t\t_activeIndex = historySize() - 1;\n\t\tmomentActivate(_activeIndex);\n\n\t\treturn historyLength();\n\t}\n\n\t/*\n\t\tActivate the moment at the given index within the history.\n\t*/\n\tfunction historyGoTo(index) {\n\t\tif (DEBUG) { console.log(`[State/historyGoTo(index: ${index})]`); }\n\n\t\tif (\n\t\t\t   index == null /* lazy equality for null */\n\t\t\t|| index < 0\n\t\t\t|| index >= historySize()\n\t\t\t|| index === _activeIndex\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\t_activeIndex = index;\n\t\tmomentActivate(_activeIndex);\n\n\t\treturn true;\n\t}\n\n\t/*\n\t\tActivate the moment at the given offset from the active moment within the history.\n\t*/\n\tfunction historyGo(offset) {\n\t\tif (DEBUG) { console.log(`[State/historyGo(offset: ${offset})]`); }\n\n\t\tif (offset == null || offset === 0) { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\treturn historyGoTo(_activeIndex + offset);\n\t}\n\n\t/*\n\t\tReturns the delta encoded form of the given history array.\n\t*/\n\tfunction historyDeltaEncode(historyArr) {\n\t\tif (!Array.isArray(historyArr)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (historyArr.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst delta = [clone(historyArr[0])];\n\n\t\tfor (let i = 1, iend = historyArr.length; i < iend; ++i) {\n\t\t\tdelta.push(Diff.diff(historyArr[i - 1], historyArr[i]));\n\t\t}\n\n\t\treturn delta;\n\t}\n\n\t/*\n\t\tReturns a history array from the given delta encoded history array.\n\t*/\n\tfunction historyDeltaDecode(delta) {\n\t\tif (!Array.isArray(delta)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (delta.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst historyArr = [clone(delta[0])];\n\n\t\tfor (let i = 1, iend = delta.length; i < iend; ++i) {\n\t\t\thistoryArr.push(Diff.patch(historyArr[i - 1], delta[i]));\n\t\t}\n\n\t\treturn historyArr;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPRNG Functions.\n\t*******************************************************************************************************************/\n\tfunction prngInit(seed, useEntropy) {\n\t\tif (DEBUG) { console.log(`[State/prngInit(seed: ${seed}, useEntropy: ${useEntropy})]`); }\n\n\t\tif (!historyIsEmpty()) {\n\t\t\tlet scriptSection;\n\n\t\t\tif (TWINE1) { // for Twine 1\n\t\t\t\tscriptSection = 'a script-tagged passage';\n\t\t\t}\n\t\t\telse { // for Twine 2\n\t\t\t\tscriptSection = 'the Story JavaScript';\n\t\t\t}\n\n\t\t\tthrow new Error(`State.initPRNG must be called during initialization, within either ${scriptSection} or the StoryInit special passage`);\n\t\t}\n\n\t\t_prng = new PRNGWrapper(seed, useEntropy);\n\t\t_active.pull = _prng.pull;\n\t}\n\n\tfunction prngIsEnabled() {\n\t\treturn _prng !== null;\n\t}\n\n\tfunction prngPull() {\n\t\treturn _prng ? _prng.pull : NaN;\n\t}\n\n\tfunction prngSeed() {\n\t\treturn _prng ? _prng.seed : null;\n\t}\n\n\tfunction prngRandom() {\n\t\tif (DEBUG) { console.log('[State/prngRandom()]'); }\n\n\t\treturn _prng ? _prng.random() : Math.random();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTemporary Variables Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tClear the temporary variables.\n\t*/\n\tfunction tempVariablesClear() {\n\t\tif (DEBUG) { console.log('[State/tempVariablesReset()]'); }\n\n\t\t_tempVariables = {};\n\n\t\t/* legacy */\n\t\tTempVariables = _tempVariables; // eslint-disable-line no-undef\n\t\t/* /legacy */\n\t}\n\n\t/*\n\t\tReturns the current temporary variables.\n\t*/\n\tfunction tempVariables() {\n\t\treturn _tempVariables;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tVariable Chain Parsing Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the value of the given story/temporary variable.\n\t*/\n\tfunction variableGet(name) {\n\t\tconst varData = _parseVariableChain(name);\n\n\t\tif (varData === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst pNames = varData.names;\n\t\tlet retVal = varData.store;\n\n\t\tfor (let i = 0, iend = pNames.length; i < iend; ++i) {\n\t\t\tif (typeof retVal[pNames[i]] === 'undefined') {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tretVal = retVal[pNames[i]];\n\t\t}\n\n\t\treturn retVal;\n\t}\n\n\t/*\n\t\tSets the value of the given story/temporary variable.\n\t*/\n\tfunction variableSet(name, value) {\n\t\tconst varData = _parseVariableChain(name);\n\n\t\tif (varData === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst pNames  = varData.names;\n\t\tconst varName = pNames.pop();\n\t\tlet baseObj = varData.store;\n\n\t\tfor (let i = 0, iend = pNames.length; i < iend; ++i) {\n\t\t\tif (typeof baseObj[pNames[i]] === 'undefined') {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tbaseObj = baseObj[pNames[i]];\n\t\t}\n\n\t\tbaseObj[varName] = value;\n\t\treturn true;\n\t}\n\n\t/*\n\t\tReturns the property name chain of the given story/temporary variable,\n\t\twhich may be of arbitrary complexity.\n\t*/\n\tconst _parseVarRegExp = new RegExp(`^(?:${Patterns.variableSigil}(${Patterns.identifier})|\\\\.(${Patterns.identifier})|\\\\[(?:(?:\"((?:\\\\\\\\.|[^\"\\\\\\\\])+)\")|(?:'((?:\\\\\\\\.|[^'\\\\\\\\])+)')|(${Patterns.variableSigil}${Patterns.identifierFirstChar}.*)|(\\\\d+))\\\\])`);\n\tfunction _parseVariableChain(varText) {\n\t\tconst retVal = {\n\t\t\tstore : varText[0] === '$' ? State.variables : State.temporary,\n\t\t\tnames : []\n\t\t};\n\t\tlet text  = varText;\n\t\tlet match;\n\n\t\twhile ((match = _parseVarRegExp.exec(text)) !== null) {\n\t\t\t// Remove full match from text.\n\t\t\ttext = text.slice(match[0].length);\n\n\t\t\t// Base variable.\n\t\t\tif (match[1]) {\n\t\t\t\tretVal.names.push(match[1]);\n\t\t\t}\n\n\t\t\t// Dot property.\n\t\t\telse if (match[2]) {\n\t\t\t\tretVal.names.push(match[2]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (double quoted).\n\t\t\telse if (match[3]) {\n\t\t\t\tretVal.names.push(match[3]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (single quoted).\n\t\t\telse if (match[4]) {\n\t\t\t\tretVal.names.push(match[4]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (embedded variable).\n\t\t\telse if (match[5]) {\n\t\t\t\tretVal.names.push(variableGet(match[5]));\n\t\t\t}\n\n\t\t\t// Square-bracketed property (numeric index).\n\t\t\telse if (match[6]) {\n\t\t\t\tretVal.names.push(Number(match[6]));\n\t\t\t}\n\t\t}\n\n\t\treturn text === '' ? retVal : null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tStory Metadata Functions.\n\t*******************************************************************************************************************/\n\tconst _METADATA_STORE = 'metadata';\n\n\tfunction metadataClear() {\n\t\tstorage.delete(_METADATA_STORE);\n\t}\n\n\tfunction metadataDelete(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.delete key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\n\t\tif (store && store.hasOwnProperty(key)) {\n\t\t\tif (Object.keys(store).length === 1) {\n\t\t\t\tstorage.delete(_METADATA_STORE);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdelete store[key];\n\t\t\t\tstorage.set(_METADATA_STORE, store);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction metadataGet(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.get key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store && store.hasOwnProperty(key) ? store[key] : undefined;\n\t}\n\n\tfunction metadataHas(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.has key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store && store.hasOwnProperty(key);\n\t}\n\n\tfunction metadataSet(key, value) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.set key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tif (typeof value === 'undefined') {\n\t\t\tmetadataDelete(key);\n\t\t}\n\t\telse {\n\t\t\tconst store = storage.get(_METADATA_STORE) || {};\n\t\t\tstore[key] = value;\n\t\t\tstorage.set(_METADATA_STORE, store);\n\t\t}\n\t}\n\n\tfunction metadataSize() {\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store ? Object.keys(store).length : 0;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tState Functions.\n\t\t*/\n\t\treset            : { value : stateReset },\n\t\trestore          : { value : stateRestore },\n\t\tmarshalForSave   : { value : stateMarshalForSave },\n\t\tunmarshalForSave : { value : stateUnmarshalForSave },\n\t\texpired          : { get : stateExpired },\n\t\tturns            : { get : stateTurns },\n\t\tpassages         : { get : stateTitles },\n\t\thasPlayed        : { value : stateHasPlayed },\n\n\t\t/*\n\t\t\tMoment Functions.\n\t\t*/\n\t\tactive      : { get : momentActive },\n\t\tactiveIndex : { get : momentActiveIndex },\n\t\tpassage     : { get : momentActiveTitle },     // shortcut for `State.active.title`\n\t\tvariables   : { get : momentActiveVariables }, // shortcut for `State.active.variables`\n\n\t\t/*\n\t\t\tHistory Functions.\n\t\t*/\n\t\thistory     : { get : historyGet },\n\t\tlength      : { get : historyLength },\n\t\tsize        : { get : historySize },\n\t\tisEmpty     : { value : historyIsEmpty },\n\t\tcurrent     : { get : historyCurrent },\n\t\ttop         : { get : historyTop },\n\t\tbottom      : { get : historyBottom },\n\t\tindex       : { value : historyIndex },\n\t\tpeek        : { value : historyPeek },\n\t\thas         : { value : historyHas },\n\t\tcreate      : { value : historyCreate },\n\t\tgoTo        : { value : historyGoTo },\n\t\tgo          : { value : historyGo },\n\t\tdeltaEncode : { value : historyDeltaEncode },\n\t\tdeltaDecode : { value : historyDeltaDecode },\n\n\t\t/*\n\t\t\tPRNG Functions.\n\t\t*/\n\t\tprng : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tinit      : { value : prngInit },\n\t\t\t\tisEnabled : { value : prngIsEnabled },\n\t\t\t\tpull      : { get : prngPull },\n\t\t\t\tseed      : { get : prngSeed }\n\t\t\t}))\n\t\t},\n\t\trandom : { value : prngRandom },\n\n\t\t/*\n\t\t\tTemporary Variables Functions.\n\t\t*/\n\t\tclearTemporary : { value : tempVariablesClear },\n\t\ttemporary      : { get : tempVariables },\n\n\t\t/*\n\t\t\tVariable Chain Parsing Functions.\n\t\t*/\n\t\tgetVar : { value : variableGet },\n\t\tsetVar : { value : variableSet },\n\n\t\t/*\n\t\t\tStory Metadata Functions.\n\t\t*/\n\t\tmetadata : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tclear  : { value : metadataClear },\n\t\t\t\tdelete : { value : metadataDelete },\n\t\t\t\tget    : { value : metadataGet },\n\t\t\t\thas    : { value : metadataHas },\n\t\t\t\tset    : { value : metadataSet },\n\t\t\t\tsize   : { get : metadataSize }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tinitPRNG : { value : prngInit },\n\t\trestart  : { value : () => Engine.restart() },\n\t\tbackward : { value : () => Engine.backward() },\n\t\tforward  : { value : () => Engine.forward() },\n\t\tdisplay  : { value : (...args) => Engine.display(...args) },\n\t\tshow     : { value : (...args) => Engine.show(...args) },\n\t\tplay     : { value : (...args) => Engine.play(...args) }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/scripting.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Engine, Patterns, State, Story, Util */\n\nvar Scripting = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/* eslint-disable no-unused-vars */\n\n\t/*******************************************************************************************************************\n\t\tDeprecated Legacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Returns the jQuery-wrapped target element(s) after making them accessible\n\t\tclickables (ARIA compatibility).\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction addAccessibleClickHandler(targets, selector, handler, one, namespace) {\n\t\tif (arguments.length < 2) {\n\t\t\tthrow new Error('addAccessibleClickHandler insufficient number of parameters');\n\t\t}\n\n\t\tlet fn;\n\t\tlet opts;\n\n\t\tif (typeof selector === 'function') {\n\t\t\tfn = selector;\n\t\t\topts = {\n\t\t\t\tnamespace : one,\n\t\t\t\tone       : !!handler\n\t\t\t};\n\t\t}\n\t\telse {\n\t\t\tfn = handler;\n\t\t\topts = {\n\t\t\t\tnamespace,\n\t\t\t\tone : !!one,\n\t\t\t\tselector\n\t\t\t};\n\t\t}\n\n\t\tif (typeof fn !== 'function') {\n\t\t\tthrow new TypeError('addAccessibleClickHandler handler parameter must be a function');\n\t\t}\n\n\t\treturn jQuery(targets).ariaClick(opts, fn);\n\t}\n\n\t/*\n\t\t[DEPRECATED] Returns a new DOM element, optionally appending it to the passed DOM element, if any.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction insertElement(place, type, id, classNames, text, title) { // eslint-disable-line max-params\n\t\tconst $el = jQuery(document.createElement(type));\n\n\t\t// Add attributes/properties.\n\t\tif (id) {\n\t\t\t$el.attr('id', id);\n\t\t}\n\n\t\tif (classNames) {\n\t\t\t$el.addClass(classNames);\n\t\t}\n\n\t\tif (title) {\n\t\t\t$el.attr('title', title);\n\t\t}\n\n\t\t// Add text content.\n\t\tif (text) {\n\t\t\t$el.text(text);\n\t\t}\n\n\t\t// Append it to the given node.\n\t\tif (place) {\n\t\t\t$el.appendTo(place);\n\t\t}\n\n\t\treturn $el[0];\n\t}\n\n\t/*\n\t\t[DEPRECATED] Creates a new text node and appends it to the passed DOM element.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction insertText(place, text) {\n\t\tjQuery(place).append(document.createTextNode(text));\n\t}\n\n\t/*\n\t\t[DEPRECATED] Removes all children from the passed DOM node.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction removeChildren(node) {\n\t\tjQuery(node).empty();\n\t}\n\n\t/*\n\t\t[DEPRECATED] Removes the passed DOM node.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction removeElement(node) {\n\t\tjQuery(node).remove();\n\t}\n\n\t/*\n\t\t[DEPRECATED] Fades a DOM element in or out.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction fade(el, options) {\n\t\t/* eslint-disable no-param-reassign */\n\t\tconst direction = options.fade === 'in' ? 1 : -1;\n\t\tlet current;\n\t\tlet proxy      = el.cloneNode(true);\n\t\tlet intervalId; // eslint-disable-line prefer-const\n\n\t\tfunction tick() {\n\t\t\tcurrent += 0.05 * direction;\n\t\t\tsetOpacity(proxy, Math.easeInOut(current));\n\n\t\t\tif (direction === 1 && current >= 1 || direction === -1 && current <= 0) {\n\t\t\t\tel.style.visibility = options.fade === 'in' ? 'visible' : 'hidden';\n\t\t\t\tproxy.parentNode.replaceChild(el, proxy);\n\t\t\t\tproxy = null;\n\t\t\t\twindow.clearInterval(intervalId);\n\n\t\t\t\tif (options.onComplete) {\n\t\t\t\t\toptions.onComplete();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction setOpacity(el, opacity) {\n\t\t\t// Old IE.\n\t\t\tel.style.zoom = 1;\n\t\t\tel.style.filter = `alpha(opacity=${Math.floor(opacity * 100)})`;\n\n\t\t\t// CSS.\n\t\t\tel.style.opacity = opacity;\n\t\t}\n\n\t\tel.parentNode.replaceChild(proxy, el);\n\n\t\tif (options.fade === 'in') {\n\t\t\tcurrent = 0;\n\t\t\tproxy.style.visibility = 'visible';\n\t\t}\n\t\telse {\n\t\t\tcurrent = 1;\n\t\t}\n\n\t\tsetOpacity(proxy, current);\n\t\tintervalId = window.setInterval(tick, 25);\n\t\t/* eslint-enable no-param-reassign */\n\t}\n\n\t/*\n\t\t[DEPRECATED] Scrolls the browser window to ensure that a DOM element is in view.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction scrollWindowTo(el, incrementBy) {\n\t\t/* eslint-disable no-param-reassign */\n\t\tlet increment = incrementBy != null ? Number(incrementBy) : 0.1; // lazy equality for null\n\n\t\tif (Number.isNaN(increment) || !Number.isFinite(increment) || increment < 0) {\n\t\t\tincrement = 0.1;\n\t\t}\n\t\telse if (increment > 1) {\n\t\t\tincrement = 1;\n\t\t}\n\n\t\tconst start     = window.scrollY ? window.scrollY : document.body.scrollTop;\n\t\tconst end       = ensureVisible(el);\n\t\tconst distance  = Math.abs(start - end);\n\t\tconst direction = start > end ? -1 : 1;\n\t\tlet progress   = 0;\n\t\tlet intervalId; // eslint-disable-line prefer-const\n\n\t\tfunction tick() {\n\t\t\tprogress += increment;\n\t\t\twindow.scroll(0, start + direction * (distance * Math.easeInOut(progress)));\n\n\t\t\tif (progress >= 1) {\n\t\t\t\twindow.clearInterval(intervalId);\n\t\t\t}\n\t\t}\n\n\t\tfunction findPosY(el) { // eslint-disable-line no-shadow\n\t\t\tlet curtop = 0;\n\n\t\t\twhile (el.offsetParent) {\n\t\t\t\tcurtop += el.offsetTop;\n\t\t\t\tel = el.offsetParent;\n\t\t\t}\n\n\t\t\treturn curtop;\n\t\t}\n\n\t\tfunction ensureVisible(el) { // eslint-disable-line no-shadow\n\t\t\tconst posTop    = findPosY(el);\n\t\t\tconst posBottom = posTop + el.offsetHeight;\n\t\t\tconst winTop    = window.scrollY ? window.scrollY : document.body.scrollTop;\n\t\t\tconst winHeight = window.innerHeight ? window.innerHeight : document.body.clientHeight;\n\t\t\tconst winBottom = winTop + winHeight;\n\n\t\t\treturn posTop >= winTop && posBottom > winBottom && el.offsetHeight < winHeight\n\t\t\t\t? posTop - (winHeight - el.offsetHeight) + 20\n\t\t\t\t: posTop;\n\t\t}\n\n\t\tintervalId = window.setInterval(tick, 25);\n\t\t/* eslint-enable no-param-reassign */\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUser Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a random value from its given arguments.\n\t*/\n\tfunction either(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn Array.prototype.concat.apply([], arguments).random();\n\t}\n\n\t/*\n\t\tRemoves the given key, and its value, from the story metadata store.\n\t*/\n\tfunction forget(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`forget key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\tState.metadata.delete(key);\n\t}\n\n\t/*\n\t\tReturns whether a passage with the given title exists within the story\n\t\thistory.  If multiple passage titles are given, returns the logical-AND\n\t\taggregate of the set.\n\t*/\n\tfunction hasVisited(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('hasVisited called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst played  = State.passages;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend; ++i) {\n\t\t\tif (!played.includes(needles[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/*\n\t\tReturns the number of turns that have passed since the last instance of the given passage\n\t\toccurred within the story history or `-1` if it does not exist.  If multiple passages are\n\t\tgiven, returns the lowest count (which can be `-1`).\n\t*/\n\tfunction lastVisited(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('lastVisited called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn -1;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst played  = State.passages;\n\t\tconst uBound  = played.length - 1;\n\t\tlet turns = State.turns;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend && turns > -1; ++i) {\n\t\t\tconst lastIndex = played.lastIndexOf(needles[i]);\n\t\t\tturns = Math.min(turns, lastIndex === -1 ? -1 : uBound - lastIndex);\n\t\t}\n\n\t\treturn turns;\n\t}\n\n\t/*\n\t\tSets the given key/value pair within the story metadata store.\n\t*/\n\tfunction memorize(key, value) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`memorize key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\tState.metadata.set(key, value);\n\t}\n\n\t/*\n\t\tReturns the title of the current passage.\n\t*/\n\tfunction passage() {\n\t\treturn State.passage;\n\t}\n\n\t/*\n\t\tReturns the title of a previous passage, either the most recent one whose title does not\n\t\tmatch that of the active passage or the one at the optional offset, or an empty string,\n\t\tif there is no such passage.\n\t*/\n\tfunction previous(/* legacy: offset */) {\n\t\tconst passages = State.passages;\n\n\t\t/* legacy: behavior with an offset */\n\t\tif (arguments.length > 0) {\n\t\t\tconst offset = Number(arguments[0]);\n\n\t\t\tif (!Number.isSafeInteger(offset) || offset < 1) {\n\t\t\t\tthrow new RangeError('previous offset parameter must be a positive integer greater than zero');\n\t\t\t}\n\n\t\t\treturn passages.length > offset ? passages[passages.length - 1 - offset] : '';\n\t\t}\n\t\t/* /legacy */\n\n\t\tfor (let i = passages.length - 2; i >= 0; --i) {\n\t\t\tif (passages[i] !== State.passage) {\n\t\t\t\treturn passages[i];\n\t\t\t}\n\t\t}\n\n\t\treturn '';\n\t}\n\n\t/*\n\t\tReturns a pseudo-random whole number (integer) within the range of the given bounds.\n\t*/\n\tfunction random(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('random called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = Math.trunc(arguments[0]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Math.trunc(arguments[0]);\n\t\t\tmax = Math.trunc(arguments[1]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (!Number.isInteger(min)) {\n\t\t\tthrow new Error('random min parameter must be an integer');\n\t\t}\n\t\tif (!Number.isInteger(max)) {\n\t\t\tthrow new Error('random max parameter must be an integer');\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn Math.floor(State.random() * (max - min + 1)) + min;\n\t}\n\n\t/*\n\t\tReturns a pseudo-random real number (floating-point) within the range of the given bounds.\n\n\t\tNOTE: Unlike with its sibling function `random()`, the `max` parameter\n\t\tis exclusive, not inclusive—i.e. the range goes to, but does not include,\n\t\tthe given value.\n\t*/\n\tfunction randomFloat(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('randomFloat called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0.0;\n\t\t\tmax = Number(arguments[0]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Number(arguments[0]);\n\t\t\tmax = Number(arguments[1]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (Number.isNaN(min) || !Number.isFinite(min)) {\n\t\t\tthrow new Error('randomFloat min parameter must be a number');\n\t\t}\n\t\tif (Number.isNaN(max) || !Number.isFinite(max)) {\n\t\t\tthrow new Error('randomFloat max parameter must be a number');\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn State.random() * (max - min) + min;\n\t}\n\n\t/*\n\t\tReturns the value of the given key from the story metadata store\n\t\tor the given default value if the key does not exist.\n\t*/\n\tfunction recall(key, defaultValue) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`recall key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\treturn State.metadata.has(key) ? State.metadata.get(key) : defaultValue;\n\t}\n\n\t/*\n\t\tReturns a new array consisting of all of the tags of the given passages.\n\t*/\n\tfunction tags(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\treturn Story.get(State.passage).tags.slice(0);\n\t\t}\n\n\t\tconst passages = Array.prototype.concat.apply([], arguments);\n\t\tlet tags = [];\n\n\t\tfor (let i = 0, iend = passages.length; i < iend; ++i) {\n\t\t\ttags = tags.concat(Story.get(passages[i]).tags);\n\t\t}\n\n\t\treturn tags;\n\t}\n\n\t/*\n\t\tReturns a reference to the current temporary _variables store.\n\t*/\n\tfunction temporary() {\n\t\treturn State.temporary;\n\t}\n\n\t/*\n\t\tReturns the number of milliseconds which have passed since the current passage was rendered.\n\t*/\n\tfunction time() {\n\t\treturn Engine.lastPlay === null ? 0 : Util.now() - Engine.lastPlay;\n\t}\n\n\t/*\n\t\tReturns the number of passages that the player has visited.\n\n\t\tNOTE: Passages which were visited but have been undone—e.g. via the backward\n\t\tbutton or the `<<back>>` macro—are no longer part of the in-play story\n\t\thistory and thus are not tallied.  Passages which were visited but have\n\t\texpired from the story history, on the other hand, are tallied.\n\t*/\n\tfunction turns() {\n\t\treturn State.turns;\n\t}\n\n\t/*\n\t\tReturns a reference to the current story $variables store.\n\t*/\n\tfunction variables() {\n\t\treturn State.variables;\n\t}\n\n\t/*\n\t\tReturns the number of times that the passage with the given title exists within the story\n\t\thistory.  If multiple passage titles are given, returns the lowest count.\n\t*/\n\tfunction visited(/* variadic */) {\n\t\tif (State.isEmpty()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments.length === 0 ? [State.passage] : arguments);\n\t\tconst played  = State.passages;\n\t\tlet count = State.turns;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend && count > 0; ++i) {\n\t\t\tcount = Math.min(count, played.count(needles[i]));\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/*\n\t\tReturns the number of passages within the story history which are tagged with all of the given tags.\n\t*/\n\tfunction visitedTags(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('visitedTags called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst nLength = needles.length;\n\t\tconst played  = State.passages;\n\t\tconst seen    = new Map();\n\t\tlet count = 0;\n\n\t\tfor (let i = 0, iend = played.length; i < iend; ++i) {\n\t\t\tconst title = played[i];\n\n\t\t\tif (seen.has(title)) {\n\t\t\t\tif (seen.get(title)) {\n\t\t\t\t\t++count;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst tags = Story.get(title).tags;\n\n\t\t\t\tif (tags.length > 0) {\n\t\t\t\t\tlet found = 0;\n\n\t\t\t\t\tfor (let j = 0; j < nLength; ++j) {\n\t\t\t\t\t\tif (tags.includes(needles[j])) {\n\t\t\t\t\t\t\t++found;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (found === nLength) {\n\t\t\t\t\t\t++count;\n\t\t\t\t\t\tseen.set(title, true);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tseen.set(title, false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/* eslint-enable no-unused-vars */\n\n\n\t/*******************************************************************************************************************\n\t\tImport Functions.\n\t*******************************************************************************************************************/\n\tvar { // eslint-disable-line no-var\n\t\t/* eslint-disable no-unused-vars */\n\t\timportScripts,\n\t\timportStyles\n\t\t/* eslint-enable no-unused-vars */\n\t} = (() => {\n\t\t// Slugify the given URL.\n\t\tfunction slugifyUrl(url) {\n\t\t\treturn Util.parseUrl(url).path\n\t\t\t\t.replace(/^[^\\w]+|[^\\w]+$/g, '')\n\t\t\t\t.replace(/[^\\w]+/g, '-')\n\t\t\t\t.toLocaleLowerCase();\n\t\t}\n\n\t\t// Add a <script> element which will load the script from the given URL.\n\t\tfunction addScript(url) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t/*\n\t\t\t\t\tWARNING: The ordering of the code within this function is important,\n\t\t\t\t\tas some browsers don't play well with different arrangements, so\n\t\t\t\t\tbe careful when mucking around with it.\n\n\t\t\t\t\tThe best supported ordering seems be: events → DOM append → attributes.\n\t\t\t\t*/\n\t\t\t\tjQuery(document.createElement('script'))\n\t\t\t\t\t.one('load abort error', ev => {\n\t\t\t\t\t\tjQuery(ev.target).off();\n\n\t\t\t\t\t\tif (ev.type === 'load') {\n\t\t\t\t\t\t\tresolve(ev.target);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treject(new Error(`importScripts failed to load the script \"${url}\".`));\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo(document.head)\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid   : `script-imported-${slugifyUrl(url)}`,\n\t\t\t\t\t\ttype : 'text/javascript',\n\t\t\t\t\t\tsrc  : url\n\t\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\t// Add a <link> element which will load the stylesheet from the given URL.\n\t\tfunction addStyle(url) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t/*\n\t\t\t\t\tWARNING: The ordering of the code within this function is important,\n\t\t\t\t\tas some browsers don't play well with different arrangements, so\n\t\t\t\t\tbe careful when mucking around with it.\n\n\t\t\t\t\tThe best supported ordering seems be: events → DOM append → attributes.\n\t\t\t\t*/\n\t\t\t\tjQuery(document.createElement('link'))\n\t\t\t\t\t.one('load abort error', ev => {\n\t\t\t\t\t\tjQuery(ev.target).off();\n\n\t\t\t\t\t\tif (ev.type === 'load') {\n\t\t\t\t\t\t\tresolve(ev.target);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treject(new Error(`importStyles failed to load the stylesheet \"${url}\".`));\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo(document.head)\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid   : `style-imported-${slugifyUrl(url)}`,\n\t\t\t\t\t\trel  : 'stylesheet',\n\t\t\t\t\t\thref : url\n\t\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\t// Turn a list of callbacks into a sequential chain of `Promise` objects.\n\t\tfunction sequence(callbacks) {\n\t\t\treturn callbacks.reduce((seq, fn) => seq = seq.then(fn), Promise.resolve()); // eslint-disable-line no-param-reassign\n\t\t}\n\n\t\t/*\n\t\t\tImport scripts from a URL.\n\t\t*/\n\t\tfunction importScripts(...urls) {\n\t\t\treturn Promise.all(urls.map(oneOrSeries => {\n\t\t\t\t// Array of URLs to be imported in sequence.\n\t\t\t\tif (Array.isArray(oneOrSeries)) {\n\t\t\t\t\treturn sequence(oneOrSeries.map(url => () => addScript(url)));\n\t\t\t\t}\n\n\t\t\t\t// Single URL to be imported.\n\t\t\t\treturn addScript(oneOrSeries);\n\t\t\t}));\n\t\t}\n\n\t\t/*\n\t\t\tImport stylesheets from a URL.\n\t\t*/\n\t\tfunction importStyles(...urls) {\n\t\t\treturn Promise.all(urls.map(oneOrSeries => {\n\t\t\t\t// Array of URLs to be imported in sequence.\n\t\t\t\tif (Array.isArray(oneOrSeries)) {\n\t\t\t\t\treturn sequence(oneOrSeries.map(url => () => addStyle(url)));\n\t\t\t\t}\n\n\t\t\t\t// Single URL to be imported.\n\t\t\t\treturn addStyle(oneOrSeries);\n\t\t\t}));\n\t\t}\n\n\t\t// Exports.\n\t\treturn {\n\t\t\timportScripts,\n\t\t\timportStyles\n\t\t};\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tParsing Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the given string after converting all TwineScript syntactical sugars to\n\t\ttheir native JavaScript counterparts.\n\t*/\n\tconst parse = (() => {\n\t\tconst parseMap = Object.freeze({\n\t\t\t/* eslint-disable quote-props */\n\t\t\t// Story $variable sigil-prefix.\n\t\t\t'$'     : 'State.variables.',\n\t\t\t// Temporary _variable sigil-prefix.\n\t\t\t'_'     : 'State.temporary.',\n\t\t\t// Assignment operators.\n\t\t\t'to'    : '=',\n\t\t\t// Equality operators.\n\t\t\t'eq'    : '==',\n\t\t\t'neq'   : '!=',\n\t\t\t'is'    : '===',\n\t\t\t'isnot' : '!==',\n\t\t\t// Relational operators.\n\t\t\t'gt'    : '>',\n\t\t\t'gte'   : '>=',\n\t\t\t'lt'    : '<',\n\t\t\t'lte'   : '<=',\n\t\t\t// Logical operators.\n\t\t\t'and'   : '&&',\n\t\t\t'or'    : '||',\n\t\t\t// Unary operators.\n\t\t\t'not'   : '!',\n\t\t\t'def'   : '\"undefined\" !== typeof',\n\t\t\t'ndef'  : '\"undefined\" === typeof'\n\t\t\t/* eslint-enable quote-props */\n\t\t});\n\t\tconst parseRe = new RegExp([\n\t\t\t'(\"\"|\\'\\')',                                          // 1=Empty quotes\n\t\t\t'(\"(?:\\\\\\\\.|[^\"\\\\\\\\])+\")',                            // 2=Double quoted, non-empty\n\t\t\t\"('(?:\\\\\\\\.|[^'\\\\\\\\])+')\",                            // 3=Single quoted, non-empty\n\t\t\t'([=+\\\\-*\\\\/%<>&\\\\|\\\\^~!?:,;\\\\(\\\\)\\\\[\\\\]{}]+)',       // 4=Operator delimiters\n\t\t\t'([^\"\\'=+\\\\-*\\\\/%<>&\\\\|\\\\^~!?:,;\\\\(\\\\)\\\\[\\\\]{}\\\\s]+)' // 5=Barewords\n\t\t].join('|'), 'g');\n\t\tconst varTest = new RegExp(`^${Patterns.variable}`);\n\n\t\tfunction parse(rawCodeString) {\n\t\t\tif (parseRe.lastIndex !== 0) {\n\t\t\t\tthrow new RangeError('Scripting.parse last index is non-zero at start');\n\t\t\t}\n\n\t\t\tlet code  = rawCodeString;\n\t\t\tlet match;\n\n\t\t\twhile ((match = parseRe.exec(code)) !== null) {\n\t\t\t\t// no-op: Empty quotes | Double quoted | Single quoted | Operator delimiters\n\n\t\t\t\t/*\n\t\t\t\t\tBarewords.\n\t\t\t\t*/\n\t\t\t\tif (match[5]) {\n\t\t\t\t\tlet token = match[5];\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is simply a dollar-sign or underscore, then it's either\n\t\t\t\t\t\tjust the raw character or, probably, a function alias, so skip it.\n\t\t\t\t\t*/\n\t\t\t\t\tif (token === '$' || token === '_') {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is a story $variable or temporary _variable, reset it\n\t\t\t\t\t\tto just its sigil—for later mapping.\n\t\t\t\t\t*/\n\t\t\t\t\telse if (varTest.test(token)) {\n\t\t\t\t\t\ttoken = token[0];\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is `is`, check to see if it's followed by `not`, if so,\n\t\t\t\t\t\tconvert them into the `isnot` operator.\n\n\t\t\t\t\t\tNOTE: This is a safety feature, since `$a is not $b` probably sounds\n\t\t\t\t\t\treasonable to most users.\n\t\t\t\t\t*/\n\t\t\t\t\telse if (token === 'is') {\n\t\t\t\t\t\tconst start = parseRe.lastIndex;\n\t\t\t\t\t\tconst part  = code.slice(start);\n\n\t\t\t\t\t\tif (/^\\s+not\\b/.test(part)) {\n\t\t\t\t\t\t\tcode = code.splice(start, part.search(/\\S/));\n\t\t\t\t\t\t\ttoken = 'isnot';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the finalized token has a mapping, replace it within the code string\n\t\t\t\t\t\twith its counterpart.\n\n\t\t\t\t\t\tNOTE: We must use `parseMap.hasOwnProperty(token)` here, rather than\n\t\t\t\t\t\tsimply using something like `parseMap[token]`, otherwise tokens which\n\t\t\t\t\t\tmatch properties from the prototype chain will cause shenanigans.\n\t\t\t\t\t*/\n\t\t\t\t\tif (parseMap.hasOwnProperty(token)) {\n\t\t\t\t\t\tcode = code.splice(\n\t\t\t\t\t\t\tmatch.index,    // starting index\n\t\t\t\t\t\t\ttoken.length,   // replace how many\n\t\t\t\t\t\t\tparseMap[token] // replacement string\n\t\t\t\t\t\t);\n\t\t\t\t\t\tparseRe.lastIndex += parseMap[token].length - token.length;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn code;\n\t\t}\n\n\t\treturn parse;\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tEval Functions.\n\t*******************************************************************************************************************/\n\t/* eslint-disable no-eval, no-extra-parens, no-unused-vars */\n\t/*\n\t\tEvaluates the given JavaScript code and returns the result, throwing if there were errors.\n\t*/\n\tfunction evalJavaScript(code, output) {\n\t\treturn (function (code, output) {\n\t\t\treturn eval(code);\n\t\t}).call(output ? { output } : null, String(code), output);\n\t}\n\n\t/*\n\t\tEvaluates the given TwineScript code and returns the result, throwing if there were errors.\n\t*/\n\tfunction evalTwineScript(code, output) {\n\t\treturn (function (code, output) {\n\t\t\treturn eval(code);\n\t\t}).call(output ? { output } : null, parse(String(code)), output);\n\t}\n\t/* eslint-enable no-eval, no-extra-parens, no-unused-vars */\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tparse           : { value : parse },\n\t\tevalJavaScript  : { value : evalJavaScript },\n\t\tevalTwineScript : { value : evalTwineScript }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/lexer.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar { // eslint-disable-line no-var\n\t/* eslint-disable no-unused-vars */\n\tEOF,\n\tLexer\n\t/* eslint-enable no-unused-vars */\n} = (() => {\n\t'use strict';\n\n\t// End of file (string, actually).\n\tconst EOF = -1;\n\n\n\t/*******************************************************************************************************************\n\t\tLexer Class.\n\t*******************************************************************************************************************/\n\tclass Lexer {\n\t\tconstructor(source, initialState) {\n\t\t\tif (arguments.length < 2) {\n\t\t\t\tthrow new Error('Lexer constructor called with too few parameters (source:string , initialState:function)');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tthis.source  → the string to be scanned\n\t\t\t\tthis.initial → initial state\n\t\t\t\tthis.state   → current state\n\t\t\t\tthis.start   → start position of an item\n\t\t\t\tthis.pos     → current position in the source string\n\t\t\t\tthis.depth   → current brace/bracket/parenthesis nesting depth\n\t\t\t\tthis.items   → scanned item queue\n\t\t\t\tthis.data    → lexing data\n\t\t\t*/\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : source\n\t\t\t\t},\n\n\t\t\t\tinitial : {\n\t\t\t\t\tvalue : initialState\n\t\t\t\t},\n\n\t\t\t\tstate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : initialState\n\t\t\t\t},\n\n\t\t\t\tstart : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\tpos : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\tdepth : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\titems : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : []\n\t\t\t\t},\n\n\t\t\t\tdata : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : {}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treset() {\n\t\t\tthis.state  = this.initial;\n\t\t\tthis.start  = 0;\n\t\t\tthis.pos    = 0;\n\t\t\tthis.depth  = 0;\n\t\t\tthis.items  = [];\n\t\t\tthis.data   = {};\n\t\t}\n\n\t\trun() {\n\t\t\t// scan the source string until no states remain\n\t\t\twhile (this.state !== null) {\n\t\t\t\tthis.state = this.state(this);\n\t\t\t}\n\n\t\t\t// return the array of items\n\t\t\treturn this.items;\n\t\t}\n\n\t\tnextItem() {\n\t\t\t// scan the source string until we have an item or no states remain\n\t\t\twhile (this.items.length === 0 && this.state !== null) {\n\t\t\t\tthis.state = this.state(this);\n\t\t\t}\n\n\t\t\t// return the current item\n\t\t\treturn this.items.shift();\n\t\t}\n\n\t\tnext() {\n\t\t\tif (this.pos >= this.source.length) {\n\t\t\t\treturn EOF;\n\t\t\t}\n\n\t\t\treturn this.source[this.pos++];\n\t\t}\n\n\t\tpeek() {\n\t\t\tif (this.pos >= this.source.length) {\n\t\t\t\treturn EOF;\n\t\t\t}\n\n\t\t\treturn this.source[this.pos];\n\t\t}\n\n\t\tbackup(num) {\n\t\t\t// if (num) {\n\t\t\t// \tthis.pos -= num;\n\t\t\t// }\n\t\t\t// else {\n\t\t\t// \t--this.pos;\n\t\t\t// }\n\t\t\tthis.pos -= num || 1;\n\t\t}\n\n\t\tforward(num) {\n\t\t\t// if (num) {\n\t\t\t// \tthis.pos += num;\n\t\t\t// }\n\t\t\t// else {\n\t\t\t// \t++this.pos;\n\t\t\t// }\n\t\t\tthis.pos += num || 1;\n\t\t}\n\n\t\tignore() {\n\t\t\tthis.start = this.pos;\n\t\t}\n\n\t\taccept(valid) {\n\t\t\tconst ch = this.next();\n\n\t\t\tif (ch === EOF) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (valid.includes(ch)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t\treturn false;\n\t\t}\n\n\t\tacceptRe(validRe) {\n\t\t\tconst ch = this.next();\n\n\t\t\tif (ch === EOF) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (validRe.test(ch)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t\treturn false;\n\t\t}\n\n\t\tacceptRun(valid) {\n\t\t\tfor (;;) {\n\t\t\t\tconst ch = this.next();\n\n\t\t\t\tif (ch === EOF) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!valid.includes(ch)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t}\n\n\t\tacceptRunRe(validRe) {\n\t\t\tfor (;;) {\n\t\t\t\tconst ch = this.next();\n\n\t\t\t\tif (ch === EOF) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!validRe.test(ch)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t}\n\n\t\temit(type) {\n\t\t\tthis.items.push({\n\t\t\t\ttype,\n\t\t\t\ttext  : this.source.slice(this.start, this.pos),\n\t\t\t\tstart : this.start,\n\t\t\t\tpos   : this.pos\n\t\t\t});\n\t\t\tthis.start = this.pos;\n\t\t}\n\n\t\terror(type, message) {\n\t\t\tif (arguments.length < 2) {\n\t\t\t\tthrow new Error('Lexer.prototype.error called with too few parameters (type:number , message:string)');\n\t\t\t}\n\n\t\t\tthis.items.push({\n\t\t\t\ttype,\n\t\t\t\tmessage,\n\t\t\t\ttext  : this.source.slice(this.start, this.pos),\n\t\t\t\tstart : this.start,\n\t\t\t\tpos   : this.pos\n\t\t\t});\n\t\t\treturn null;\n\t\t}\n\n\t\tstatic enumFromNames(names) {\n\t\t\tconst obj = names.reduce((obj, name, i) => {\n\t\t\t\tobj[name] = i; // eslint-disable-line no-param-reassign\n\t\t\t\treturn obj;\n\t\t\t}, {});\n\t\t\treturn Object.freeze(Object.assign(Object.create(null), obj));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn {\n\t\tEOF,\n\t\tLexer\n\t};\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/wikifier.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, EOF, Engine, Lexer, Patterns, Scripting, State, Story, TempState, Util, convertBreaks,\n\t       errorPrologRegExp\n*/\n\n/*\n\tTODO: The Wikifier, and associated code, could stand to receive a serious refactoring.\n*/\n/* eslint-disable max-len */\nvar Wikifier = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Wikifier call depth.\n\tlet _callDepth = 0;\n\n\n\t/*******************************************************************************************************************\n\t\tWikifier Class.\n\t*******************************************************************************************************************/\n\tclass Wikifier {\n\t\tconstructor(destination, source, options) {\n\t\t\tif (Wikifier.Parser.Profile.isEmpty()) {\n\t\t\t\tWikifier.Parser.Profile.compile();\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// General Wikifier properties.\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : String(source)\n\t\t\t\t},\n\n\t\t\t\toptions : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : Object.assign({\n\t\t\t\t\t\tprofile : 'all'\n\t\t\t\t\t}, options)\n\t\t\t\t},\n\n\t\t\t\tnextMatch : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\toutput : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t// Macro parser ('macro') related properties.\n\t\t\t\t_rawArgs : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : ''\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// No destination specified.  Create a fragment to act as the output buffer.\n\t\t\tif (destination == null) { // lazy equality for null\n\t\t\t\tthis.output = document.createDocumentFragment();\n\t\t\t}\n\n\t\t\t// jQuery-wrapped destination.  Grab the first element.\n\t\t\telse if (destination.jquery) { // cannot use `hasOwnProperty()` here as `jquery` is from jQuery's prototype\n\t\t\t\tthis.output = destination[0];\n\t\t\t}\n\n\t\t\t// Normal destination.\n\t\t\telse {\n\t\t\t\tthis.output = destination;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tWikify the source into the output buffer element, possibly converting line\n\t\t\t\tbreaks into paragraphs.\n\n\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\tto ensure that the call depth is properly restored in the event that an\n\t\t\t\tuncaught exception is thrown during the call to `subWikify()`.\n\t\t\t*/\n\t\t\ttry {\n\t\t\t\t++_callDepth;\n\n\t\t\t\tthis.subWikify(this.output);\n\n\t\t\t\t// Limit line break conversion to non-recursive calls.\n\t\t\t\tif (_callDepth === 1 && Config.cleanupWikifierOutput) {\n\t\t\t\t\tconvertBreaks(this.output);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\t--_callDepth;\n\t\t\t}\n\t\t}\n\n\t\tsubWikify(output, terminator, options) {\n\t\t\t// Cache and temporarily replace the current output buffer.\n\t\t\tconst oldOutput = this.output;\n\t\t\tthis.output = output;\n\n\t\t\tlet newOptions;\n\t\t\tlet oldOptions;\n\n\t\t\t// Parser option overrides.\n\t\t\tif (Wikifier.Option.length > 0) {\n\t\t\t\tnewOptions = Object.assign(newOptions || {}, Wikifier.Option.options);\n\t\t\t}\n\t\t\t// Local parameter option overrides.\n\t\t\tif (options !== null && typeof options === 'object') {\n\t\t\t\tnewOptions = Object.assign(newOptions || {}, options);\n\t\t\t}\n\t\t\t// If new options exist, cache and temporarily replace the current options.\n\t\t\tif (newOptions) {\n\t\t\t\toldOptions = this.options;\n\t\t\t\tthis.options = Object.assign({}, this.options, newOptions);\n\t\t\t}\n\n\t\t\tconst parsersProfile   = Wikifier.Parser.Profile.get(this.options.profile);\n\t\t\tconst terminatorRegExp = terminator\n\t\t\t\t? new RegExp(`(?:${terminator})`, this.options.ignoreTerminatorCase ? 'gim' : 'gm')\n\t\t\t\t: null;\n\t\t\tlet terminatorMatch;\n\t\t\tlet parserMatch;\n\n\t\t\tdo {\n\t\t\t\t// Prepare the RegExp match positions.\n\t\t\t\tparsersProfile.parserRegExp.lastIndex = this.nextMatch;\n\n\t\t\t\tif (terminatorRegExp) {\n\t\t\t\t\tterminatorRegExp.lastIndex = this.nextMatch;\n\t\t\t\t}\n\n\t\t\t\t// Get the first matches.\n\t\t\t\tparserMatch     = parsersProfile.parserRegExp.exec(this.source);\n\t\t\t\tterminatorMatch = terminatorRegExp ? terminatorRegExp.exec(this.source) : null;\n\n\t\t\t\t// Try for a terminator match, unless there's a closer parser match.\n\t\t\t\tif (terminatorMatch && (!parserMatch || terminatorMatch.index <= parserMatch.index)) {\n\t\t\t\t\t// Output any text before the match.\n\t\t\t\t\tif (terminatorMatch.index > this.nextMatch) {\n\t\t\t\t\t\tthis.outputText(this.output, this.nextMatch, terminatorMatch.index);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set the match parameters.\n\t\t\t\t\tthis.matchStart  = terminatorMatch.index;\n\t\t\t\t\tthis.matchLength = terminatorMatch[0].length;\n\t\t\t\t\tthis.matchText   = terminatorMatch[0];\n\t\t\t\t\tthis.nextMatch   = terminatorRegExp.lastIndex;\n\n\t\t\t\t\t// Restore the original output buffer and options.\n\t\t\t\t\tthis.output = oldOutput;\n\n\t\t\t\t\tif (oldOptions) {\n\t\t\t\t\t\tthis.options = oldOptions;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Exit.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Try for a parser match.\n\t\t\t\telse if (parserMatch) {\n\t\t\t\t\t// Output any text before the match.\n\t\t\t\t\tif (parserMatch.index > this.nextMatch) {\n\t\t\t\t\t\tthis.outputText(this.output, this.nextMatch, parserMatch.index);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set the match parameters.\n\t\t\t\t\tthis.matchStart  = parserMatch.index;\n\t\t\t\t\tthis.matchLength = parserMatch[0].length;\n\t\t\t\t\tthis.matchText   = parserMatch[0];\n\t\t\t\t\tthis.nextMatch   = parsersProfile.parserRegExp.lastIndex;\n\n\t\t\t\t\t// Figure out which parser matched.\n\t\t\t\t\tlet matchingParser;\n\n\t\t\t\t\tfor (let i = 1, iend = parserMatch.length; i < iend; ++i) {\n\t\t\t\t\t\tif (parserMatch[i]) {\n\t\t\t\t\t\t\tmatchingParser = i - 1;\n\t\t\t\t\t\t\tbreak; // stop once we've found the matching parser\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Call the parser.\n\t\t\t\t\tparsersProfile.parsers[matchingParser].handler(this);\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} while (terminatorMatch || parserMatch);\n\n\t\t\t// Output any text after the last match.\n\t\t\tif (TempState.break == null) { // lazy equality for null\n\t\t\t\tif (this.nextMatch < this.source.length) {\n\t\t\t\t\tthis.outputText(this.output, this.nextMatch, this.source.length);\n\t\t\t\t\tthis.nextMatch = this.source.length;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// In case of <<break>>/<<continue>>, remove the last <br>.\n\t\t\telse if (\n\t\t\t\t   this.output.lastChild\n\t\t\t\t&& this.output.lastChild.nodeType === Node.ELEMENT_NODE\n\t\t\t\t&& this.output.lastChild.nodeName.toUpperCase() === 'BR'\n\t\t\t) {\n\t\t\t\tjQuery(this.output.lastChild).remove();\n\t\t\t}\n\n\t\t\t// Restore the original output buffer and options.\n\t\t\tthis.output = oldOutput;\n\n\t\t\tif (oldOptions) {\n\t\t\t\tthis.options = oldOptions;\n\t\t\t}\n\t\t}\n\n\t\toutputText(destination, startPos, endPos) {\n\t\t\tdestination.appendChild(document.createTextNode(this.source.substring(startPos, endPos)));\n\t\t}\n\n\t\t/*\n\t\t\t[DEPRECATED] Meant to be called by legacy macros, this returns the raw, unprocessed\n\t\t\ttext given to the currently executing macro.\n\t\t*/\n\t\trawArgs() {\n\t\t\treturn this._rawArgs;\n\t\t}\n\n\t\t/*\n\t\t\t[DEPRECATED] Meant to be called by legacy macros, this returns the text given to\n\t\t\tthe currently executing macro after doing TwineScript-to-JavaScript transformations.\n\t\t*/\n\t\tfullArgs() {\n\t\t\treturn Scripting.parse(this._rawArgs);\n\t\t}\n\n\t\t/*\n\t\t\tReturns the output generated by wikifying the given text, throwing if there were errors.\n\t\t*/\n\t\tstatic wikifyEval(text) {\n\t\t\tconst output = document.createDocumentFragment();\n\n\t\t\tnew Wikifier(output, text);\n\n\t\t\tconst errors = output.querySelector('.error');\n\n\t\t\tif (errors !== null) {\n\t\t\t\tthrow new Error(errors.textContent.replace(errorPrologRegExp, ''));\n\t\t\t}\n\n\t\t\treturn output;\n\t\t}\n\n\t\t/*\n\t\t\tCreate and return an internal link.\n\t\t*/\n\t\tstatic createInternalLink(destination, passage, text, callback) {\n\t\t\tconst $link = jQuery(document.createElement('a'));\n\n\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t$link.attr('data-passage', passage);\n\n\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t$link.addClass('link-internal');\n\n\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t$link.addClass('link-visited');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$link.addClass('link-broken');\n\t\t\t\t}\n\n\t\t\t\t$link.ariaClick({ one : true }, () => {\n\t\t\t\t\tif (typeof callback === 'function') {\n\t\t\t\t\t\tcallback();\n\t\t\t\t\t}\n\n\t\t\t\t\tEngine.play(passage);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (text) {\n\t\t\t\t$link.append(document.createTextNode(text));\n\t\t\t}\n\n\t\t\tif (destination) {\n\t\t\t\t$link.appendTo(destination);\n\t\t\t}\n\n\t\t\t// For legacy-compatibility we must return the DOM node.\n\t\t\treturn $link[0];\n\t\t}\n\n\t\t/*\n\t\t\tCreate and return an external link.\n\t\t*/\n\t\tstatic createExternalLink(destination, url, text) {\n\t\t\tconst $link = jQuery(document.createElement('a'))\n\t\t\t\t.attr('target', '_blank')\n\t\t\t\t.addClass('link-external')\n\t\t\t\t.text(text)\n\t\t\t\t.appendTo(destination);\n\n\t\t\tif (url != null) { // lazy equality for null\n\t\t\t\t$link.attr({\n\t\t\t\t\thref     : url,\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// For legacy-compatibility we must return the DOM node.\n\t\t\treturn $link[0];\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the given link source is external (probably).\n\t\t*/\n\t\tstatic isExternalLink(link) {\n\t\t\tif (Story.has(link)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst urlRegExp = new RegExp(`^${Patterns.url}`, 'gim');\n\t\t\treturn urlRegExp.test(link) || /[/.?#]/.test(link);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tOption Static Object.\n\t*******************************************************************************************************************/\n\tObject.defineProperty(Wikifier, 'Option', {\n\t\tvalue : (() => {\n\t\t\t// Options array (stack).\n\t\t\tlet _optionsStack = [];\n\n\n\t\t\t/*\n\t\t\t\tGlobalOption Functions.\n\t\t\t*/\n\t\t\tfunction optionLength() {\n\t\t\t\treturn _optionsStack.length;\n\t\t\t}\n\n\t\t\tfunction optionGetter() {\n\t\t\t\treturn Object.assign({}, ..._optionsStack);\n\t\t\t}\n\n\t\t\tfunction optionClear() {\n\t\t\t\t_optionsStack = [];\n\t\t\t}\n\n\t\t\tfunction optionGet(idx) {\n\t\t\t\treturn _optionsStack[idx];\n\t\t\t}\n\n\t\t\tfunction optionPop() {\n\t\t\t\treturn _optionsStack.pop();\n\t\t\t}\n\n\t\t\tfunction optionPush(options) {\n\t\t\t\tif (typeof options !== 'object' || options === null) {\n\t\t\t\t\tthrow new TypeError(`Wikifier.Option.push options parameter must be an object (received: ${Util.getType(options)})`);\n\t\t\t\t}\n\n\t\t\t\treturn _optionsStack.push(options);\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tExports.\n\t\t\t*/\n\t\t\treturn Object.freeze(Object.defineProperties({}, {\n\t\t\t\tlength  : { get : optionLength },\n\t\t\t\toptions : { get : optionGetter },\n\t\t\t\tclear   : { value : optionClear },\n\t\t\t\tget     : { value : optionGet },\n\t\t\t\tpop     : { value : optionPop },\n\t\t\t\tpush    : { value : optionPush }\n\t\t\t}));\n\t\t})()\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tParser Static Object.\n\t*******************************************************************************************************************/\n\tObject.defineProperty(Wikifier, 'Parser', {\n\t\tvalue : (() => {\n\t\t\t// Parser definition array.  Ordering matters, so this must be an ordered list.\n\t\t\tconst _parsers = [];\n\n\t\t\t// Parser profiles object.\n\t\t\tlet _profiles;\n\n\n\t\t\t/*\n\t\t\t\tParser Functions.\n\t\t\t*/\n\t\t\tfunction parsersGetter() {\n\t\t\t\treturn _parsers;\n\t\t\t}\n\n\t\t\tfunction parsersAdd(parser) {\n\t\t\t\t// Parser object sanity checks.\n\t\t\t\tif (typeof parser !== 'object') {\n\t\t\t\t\tthrow new Error('Wikifier.Parser.add parser parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('name')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"name\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.name !== 'string') {\n\t\t\t\t\tthrow new Error('parser object \"name\" property must be a string');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('match')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"match\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.match !== 'string') {\n\t\t\t\t\tthrow new Error('parser object \"match\" property must be a string');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('handler')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"handler\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.handler !== 'function') {\n\t\t\t\t\tthrow new Error('parser object \"handler\" property must be a function');\n\t\t\t\t}\n\n\t\t\t\tif (parser.hasOwnProperty('profiles') && !Array.isArray(parser.profiles)) {\n\t\t\t\t\tthrow new Error('parser object \"profiles\" property must be an array');\n\t\t\t\t}\n\n\t\t\t\t// Check for an existing parser with the same name.\n\t\t\t\tif (parsersHas(parser.name)) {\n\t\t\t\t\tthrow new Error(`cannot clobber existing parser \"${parser.name}\"`);\n\t\t\t\t}\n\n\t\t\t\t// Add the parser to the end of the array.\n\t\t\t\t_parsers.push(parser);\n\t\t\t}\n\n\t\t\tfunction parsersDelete(name) {\n\t\t\t\tconst parser = _parsers.find(parser => parser.name === name);\n\n\t\t\t\tif (parser) {\n\t\t\t\t\t_parsers.delete(parser);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction parsersIsEmpty() {\n\t\t\t\treturn _parsers.length === 0;\n\t\t\t}\n\n\t\t\tfunction parsersHas(name) {\n\t\t\t\treturn !!_parsers.find(parser => parser.name === name);\n\t\t\t}\n\n\t\t\tfunction parsersGet(name) {\n\t\t\t\treturn _parsers.find(parser => parser.name === name) || null;\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tParser Profile Functions.\n\t\t\t*/\n\t\t\tfunction profilesGetter() {\n\t\t\t\treturn _profiles;\n\t\t\t}\n\n\t\t\tfunction profilesCompile() {\n\t\t\t\tif (DEBUG) { console.log('[Wikifier.Parser/profilesCompile()]'); }\n\n\t\t\t\tconst all  = _parsers;\n\t\t\t\tconst core = all.filter(parser => !Array.isArray(parser.profiles) || parser.profiles.includes('core'));\n\n\t\t\t\t_profiles = Object.freeze({\n\t\t\t\t\tall : {\n\t\t\t\t\t\tparsers      : all,\n\t\t\t\t\t\tparserRegExp : new RegExp(all.map(parser => `(${parser.match})`).join('|'), 'gm')\n\t\t\t\t\t},\n\t\t\t\t\tcore : {\n\t\t\t\t\t\tparsers      : core,\n\t\t\t\t\t\tparserRegExp : new RegExp(core.map(parser => `(${parser.match})`).join('|'), 'gm')\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\treturn _profiles;\n\t\t\t}\n\n\t\t\tfunction profilesIsEmpty() {\n\t\t\t\treturn typeof _profiles !== 'object' || Object.keys(_profiles).length === 0;\n\t\t\t}\n\n\t\t\tfunction profilesGet(profile) {\n\t\t\t\tif (typeof _profiles !== 'object' || !_profiles.hasOwnProperty(profile)) {\n\t\t\t\t\tthrow new Error(`nonexistent parser profile \"${profile}\"`);\n\t\t\t\t}\n\n\t\t\t\treturn _profiles[profile];\n\t\t\t}\n\n\t\t\tfunction profilesHas(profile) {\n\t\t\t\treturn typeof _profiles === 'object' && _profiles.hasOwnProperty(profile);\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tExports.\n\t\t\t*/\n\t\t\treturn Object.freeze(Object.defineProperties({}, {\n\t\t\t\t/*\n\t\t\t\t\tParser Containers.\n\t\t\t\t*/\n\t\t\t\tparsers : { get : parsersGetter },\n\n\t\t\t\t/*\n\t\t\t\t\tParser Functions.\n\t\t\t\t*/\n\t\t\t\tadd     : { value : parsersAdd },\n\t\t\t\tdelete  : { value : parsersDelete },\n\t\t\t\tisEmpty : { value : parsersIsEmpty },\n\t\t\t\thas     : { value : parsersHas },\n\t\t\t\tget     : { value : parsersGet },\n\n\t\t\t\t/*\n\t\t\t\t\tParser Profile.\n\t\t\t\t*/\n\t\t\t\tProfile : {\n\t\t\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tProfiles Containers.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tprofiles : { get : profilesGetter },\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tProfiles Functions.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tcompile : { value : profilesCompile },\n\t\t\t\t\t\tisEmpty : { value : profilesIsEmpty },\n\t\t\t\t\t\thas     : { value : profilesHas },\n\t\t\t\t\t\tget     : { value : profilesGet }\n\t\t\t\t\t}))\n\t\t\t\t}\n\t\t\t}));\n\t\t})()\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAdditional Static Properties.\n\t*******************************************************************************************************************/\n\tObject.defineProperties(Wikifier, {\n\t\thelpers : { value : {} },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tgetValue       : { value : State.getVar },              // SEE: `state.js`.\n\t\tsetValue       : { value : State.setVar },              // SEE: `state.js`.\n\t\tparse          : { value : Scripting.parse },           // SEE: `markup/scripting.js`.\n\t\tevalExpression : { value : Scripting.evalTwineScript }, // SEE: `markup/scripting.js`.\n\t\tevalStatements : { value : Scripting.evalTwineScript }, // SEE: `markup/scripting.js`.\n\t\ttextPrimitives : { value : Patterns }                   // SEE: `lib/patterns.js`.\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tHelper Static Methods.\n\t*******************************************************************************************************************/\n\tObject.defineProperties(Wikifier.helpers, {\n\t\tinlineCss : {\n\t\t\tvalue : (() => {\n\t\t\t\tconst lookaheadRe = new RegExp(Patterns.inlineCss, 'gm');\n\t\t\t\tconst idOrClassRe = new RegExp(`(${Patterns.cssIdOrClassSigil})(${Patterns.anyLetter}+)`, 'g');\n\n\t\t\t\tfunction helperInlineCss(w) {\n\t\t\t\t\tconst css = { classes : [], id : '', styles : {} };\n\t\t\t\t\tlet matched;\n\n\t\t\t\t\tdo {\n\t\t\t\t\t\tlookaheadRe.lastIndex = w.nextMatch;\n\n\t\t\t\t\t\tconst match = lookaheadRe.exec(w.source);\n\n\t\t\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\t\t\tif (matched) {\n\t\t\t\t\t\t\tif (match[1]) {\n\t\t\t\t\t\t\t\tcss.styles[Util.fromCssProperty(match[1])] = match[2].trim();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (match[3]) {\n\t\t\t\t\t\t\t\tcss.styles[Util.fromCssProperty(match[3])] = match[4].trim();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (match[5]) {\n\t\t\t\t\t\t\t\tlet subMatch;\n\n\t\t\t\t\t\t\t\tidOrClassRe.lastIndex = 0; // NOTE: Guard against buggy implementations.\n\n\t\t\t\t\t\t\t\twhile ((subMatch = idOrClassRe.exec(match[5])) !== null) {\n\t\t\t\t\t\t\t\t\tif (subMatch[1] === '.') {\n\t\t\t\t\t\t\t\t\t\tcss.classes.push(subMatch[2]);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tcss.id = subMatch[2];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tw.nextMatch = lookaheadRe.lastIndex; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\t\t\t\t\t} while (matched);\n\n\t\t\t\t\treturn css;\n\t\t\t\t}\n\n\t\t\t\treturn helperInlineCss;\n\t\t\t})()\n\t\t},\n\n\t\tevalText : {\n\t\t\tvalue(text) {\n\t\t\t\tlet result;\n\n\t\t\t\ttry {\n\t\t\t\t\tresult = Scripting.evalTwineScript(text);\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAttempt to prevent the leakage of auto-globals by enforcing that\n\t\t\t\t\t\tthe resultant value be either a string or a number.\n\n\t\t\t\t\t\tNOTE: This is not a foolproof solution to the problem of auto-global\n\t\t\t\t\t\tleakage.  Various auto-globals, which return strings or numbers, can\n\t\t\t\t\t\tstill leak through—e.g. `window.status` → string.\n\t\t\t\t\t*/\n\t\t\t\t\tswitch (typeof result) {\n\t\t\t\t\tcase 'string':\n\t\t\t\t\t\tif (result.trim() === '') {\n\t\t\t\t\t\t\tresult = text;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'number':\n\t\t\t\t\t\tresult = String(result);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tresult = text;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\tresult = text;\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}\n\t\t},\n\n\t\tevalPassageId : {\n\t\t\tvalue(passage) {\n\t\t\t\tif (passage == null || Story.has(passage)) { // lazy equality for null; `0` is a valid name, so we cannot simply evaluate `passage`\n\t\t\t\t\treturn passage;\n\t\t\t\t}\n\n\t\t\t\treturn Wikifier.helpers.evalText(passage);\n\t\t\t}\n\t\t},\n\n\t\thasBlockContext : {\n\t\t\tvalue(nodes) {\n\t\t\t\tconst hasGCS = typeof window.getComputedStyle === 'function';\n\n\t\t\t\tfor (let i = nodes.length - 1; i >= 0; --i) {\n\t\t\t\t\tconst node = nodes[i];\n\n\t\t\t\t\tswitch (node.nodeType) {\n\t\t\t\t\tcase Node.ELEMENT_NODE:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst tagName = node.nodeName.toUpperCase();\n\n\t\t\t\t\t\t\tif (tagName === 'BR') {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst styles = hasGCS ? window.getComputedStyle(node, null) : node.currentStyle;\n\n\t\t\t\t\t\t\tif (styles && styles.display) {\n\t\t\t\t\t\t\t\tif (styles.display === 'none') {\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn styles.display === 'block';\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tWebKit/Blink-based browsers do not attach any computed style\n\t\t\t\t\t\t\t\tinformation to elements until they're inserted into the DOM\n\t\t\t\t\t\t\t\t(and probably visible), not even the default browser styles\n\t\t\t\t\t\t\t\tand any user styles.  So, we make an assumption based on the\n\t\t\t\t\t\t\t\telement.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tswitch (tagName) {\n\t\t\t\t\t\t\tcase 'ADDRESS':\n\t\t\t\t\t\t\tcase 'ARTICLE':\n\t\t\t\t\t\t\tcase 'ASIDE':\n\t\t\t\t\t\t\tcase 'BLOCKQUOTE':\n\t\t\t\t\t\t\tcase 'CENTER':\n\t\t\t\t\t\t\tcase 'DIV':\n\t\t\t\t\t\t\tcase 'DL':\n\t\t\t\t\t\t\tcase 'FIGURE':\n\t\t\t\t\t\t\tcase 'FOOTER':\n\t\t\t\t\t\t\tcase 'FORM':\n\t\t\t\t\t\t\tcase 'H1':\n\t\t\t\t\t\t\tcase 'H2':\n\t\t\t\t\t\t\tcase 'H3':\n\t\t\t\t\t\t\tcase 'H4':\n\t\t\t\t\t\t\tcase 'H5':\n\t\t\t\t\t\t\tcase 'H6':\n\t\t\t\t\t\t\tcase 'HEADER':\n\t\t\t\t\t\t\tcase 'HR':\n\t\t\t\t\t\t\tcase 'MAIN':\n\t\t\t\t\t\t\tcase 'NAV':\n\t\t\t\t\t\t\tcase 'OL':\n\t\t\t\t\t\t\tcase 'P':\n\t\t\t\t\t\t\tcase 'PRE':\n\t\t\t\t\t\t\tcase 'SECTION':\n\t\t\t\t\t\t\tcase 'TABLE':\n\t\t\t\t\t\t\tcase 'UL':\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn false;\n\n\t\t\t\t\tcase Node.COMMENT_NODE:\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t},\n\n\t\tcreateShadowSetterCallback : {\n\t\t\tvalue : (() => {\n\t\t\t\tlet macroParser = null;\n\n\t\t\t\tfunction cacheMacroParser() {\n\t\t\t\t\tif (!macroParser) {\n\t\t\t\t\t\tmacroParser = Wikifier.Parser.get('macro');\n\n\t\t\t\t\t\tif (!macroParser) {\n\t\t\t\t\t\t\tthrow new Error('cannot find \"macro\" parser');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn macroParser;\n\t\t\t\t}\n\n\t\t\t\tfunction getMacroContextShadowView() {\n\t\t\t\t\tconst macro = macroParser || cacheMacroParser();\n\t\t\t\t\tconst view  = new Set();\n\n\t\t\t\t\tfor (let context = macro.context; context !== null; context = context.parent) {\n\t\t\t\t\t\tif (context._shadows) {\n\t\t\t\t\t\t\tcontext._shadows.forEach(name => view.add(name));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn [...view];\n\t\t\t\t}\n\n\t\t\t\tfunction helperCreateShadowSetterCallback(code) {\n\t\t\t\t\tconst shadowStore = {};\n\n\t\t\t\t\tgetMacroContextShadowView().forEach(varName => {\n\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\t\t\t\t\t});\n\n\t\t\t\t\treturn function () {\n\t\t\t\t\t\tconst shadowNames = Object.keys(shadowStore);\n\t\t\t\t\t\tconst valueCache  = shadowNames.length > 0 ? {} : null;\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t\t\tevaluation.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tCache the existing values of the variables to be shadowed and assign the\n\t\t\t\t\t\t\t\tshadow values.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tstore[varKey] = shadowStore[varName];\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t// Evaluate the JavaScript.\n\t\t\t\t\t\t\treturn Scripting.evalJavaScript(code);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t// Revert the variable shadowing.\n\t\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tUpdate the shadow store with the variable's current value, in case it\n\t\t\t\t\t\t\t\t\twas modified during the callback.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\n\t\t\t\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn helperCreateShadowSetterCallback;\n\t\t\t})()\n\t\t},\n\n\t\tparseSquareBracketedMarkup : {\n\t\t\tvalue : (() => {\n\t\t\t\t/* eslint-disable no-param-reassign */\n\t\t\t\tconst Item = Lexer.enumFromNames([ // lex item types object (pseudo-enumeration)\n\t\t\t\t\t'Error',     // error\n\t\t\t\t\t'DelimLTR',  // '|' or '->'\n\t\t\t\t\t'DelimRTL',  // '<-'\n\t\t\t\t\t'InnerMeta', // ']['\n\t\t\t\t\t'ImageMeta', // '[img[', '[<img[', or '[>img['\n\t\t\t\t\t'LinkMeta',  // '[['\n\t\t\t\t\t'Link',      // link destination\n\t\t\t\t\t'RightMeta', // ']]'\n\t\t\t\t\t'Setter',    // setter expression\n\t\t\t\t\t'Source',    // image source\n\t\t\t\t\t'Text'       // link text or image alt text\n\t\t\t\t]);\n\t\t\t\tconst Delim = Lexer.enumFromNames([ // delimiter state object (pseudo-enumeration)\n\t\t\t\t\t'None', // no delimiter encountered\n\t\t\t\t\t'LTR',  // '|' or '->'\n\t\t\t\t\t'RTL'   // '<-'\n\t\t\t\t]);\n\n\t\t\t\t// Lexing functions.\n\t\t\t\tfunction slurpQuote(lexer, endQuote) {\n\t\t\t\t\tloop: for (;;) {\n\t\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/* falls through */\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn EOF;\n\n\t\t\t\t\t\tcase endQuote:\n\t\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t\t}\n\n\t\t\t\t\treturn lexer.pos;\n\t\t\t\t}\n\n\t\t\t\tfunction lexLeftMeta(lexer) {\n\t\t\t\t\tif (!lexer.accept('[')) {\n\t\t\t\t\t\treturn lexer.error(Item.Error, 'malformed square-bracketed markup');\n\t\t\t\t\t}\n\n\t\t\t\t\t// Is link markup.\n\t\t\t\t\tif (lexer.accept('[')) {\n\t\t\t\t\t\tlexer.data.isLink = true;\n\t\t\t\t\t\tlexer.emit(Item.LinkMeta);\n\t\t\t\t\t}\n\n\t\t\t\t\t// May be image markup.\n\t\t\t\t\telse {\n\t\t\t\t\t\tlexer.accept('<>'); // aligner syntax\n\n\t\t\t\t\t\tif (!lexer.accept('Ii') || !lexer.accept('Mm') || !lexer.accept('Gg') || !lexer.accept('[')) {\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, 'malformed square-bracketed markup');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlexer.data.isLink = false;\n\t\t\t\t\t\tlexer.emit(Item.ImageMeta);\n\t\t\t\t\t}\n\n\t\t\t\t\tlexer.depth = 2; // account for both initial left square brackets\n\t\t\t\t\treturn lexCoreComponents;\n\t\t\t\t}\n\n\t\t\t\tfunction lexCoreComponents(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\t\t\t\t\tlet delim = Delim.None;\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tThis is not entirely reliable within sections that allow raw strings, since\n\t\t\t\t\t\t\t\tit's possible, however unlikely, for a raw string to contain unpaired double\n\t\t\t\t\t\t\t\tquotes.  The likelihood is low enough, however, that I'm deeming the risk as\n\t\t\t\t\t\t\t\tacceptable—for now, at least.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '|': // possible pipe ('|') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None) {\n\t\t\t\t\t\t\t\tdelim = Delim.LTR;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\tlexer.forward();\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimLTR);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '-': // possible right arrow ('->') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None && lexer.peek() === '>') {\n\t\t\t\t\t\t\t\tdelim = Delim.LTR;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimLTR);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '<': // possible left arrow ('<-') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None && lexer.peek() === '-') {\n\t\t\t\t\t\t\t\tdelim = Delim.RTL;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimRTL);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tswitch (lexer.peek()) {\n\t\t\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\n\t\t\t\t\t\t\t\t\tif (delim === Delim.RTL) {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.InnerMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn lexer.data.isLink ? lexSetter : lexImageLink;\n\n\t\t\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\n\t\t\t\t\t\t\t\t\tif (delim === Delim.RTL) {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfunction lexImageLink(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tThis is not entirely reliable within sections that allow raw strings, since\n\t\t\t\t\t\t\t\tit's possible, however unlikely, for a raw string to contain unpaired double\n\t\t\t\t\t\t\t\tquotes.  The likelihood is low enough, however, that I'm deeming the risk as\n\t\t\t\t\t\t\t\tacceptable—for now, at least.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup link component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tswitch (lexer.peek()) {\n\t\t\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.Link);\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.InnerMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn lexSetter;\n\n\t\t\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.Link);\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfunction lexSetter(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup setter component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase \"'\":\n\t\t\t\t\t\t\tif (slurpQuote(lexer, \"'\") === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated single quoted string in ${what} markup setter component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tif (lexer.peek() !== ']') {\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Setter);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Parse function.\n\t\t\t\tfunction parseSquareBracketedMarkup(w) {\n\t\t\t\t\t// Initialize the lexer.\n\t\t\t\t\tconst lexer  = new Lexer(w.source, lexLeftMeta);\n\n\t\t\t\t\t// Set the initial positions within the source string.\n\t\t\t\t\tlexer.start = lexer.pos = w.matchStart;\n\n\t\t\t\t\t// Lex the raw argument string.\n\t\t\t\t\tconst markup = {};\n\t\t\t\t\tconst items  = lexer.run();\n\t\t\t\t\tconst last   = items.last();\n\n\t\t\t\t\tif (last && last.type === Item.Error) {\n\t\t\t\t\t\tmarkup.error = last.message;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\titems.forEach(item => {\n\t\t\t\t\t\t\tconst text = item.text.trim();\n\n\t\t\t\t\t\t\tswitch (item.type) {\n\t\t\t\t\t\t\tcase Item.ImageMeta:\n\t\t\t\t\t\t\t\tmarkup.isImage = true;\n\n\t\t\t\t\t\t\t\tif (text[1] === '<') {\n\t\t\t\t\t\t\t\t\tmarkup.align = 'left';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (text[1] === '>') {\n\t\t\t\t\t\t\t\t\tmarkup.align = 'right';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.LinkMeta:\n\t\t\t\t\t\t\t\tmarkup.isLink = true;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Link:\n\t\t\t\t\t\t\t\tif (text[0] === '~') {\n\t\t\t\t\t\t\t\t\tmarkup.forceInternal = true;\n\t\t\t\t\t\t\t\t\tmarkup.link = text.slice(1);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tmarkup.link = text;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Setter:\n\t\t\t\t\t\t\t\tmarkup.setter = text;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Source:\n\t\t\t\t\t\t\t\tmarkup.source = text;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Text:\n\t\t\t\t\t\t\t\tmarkup.text = text;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tmarkup.pos = lexer.pos;\n\t\t\t\t\treturn markup;\n\t\t\t\t}\n\n\t\t\t\treturn parseSquareBracketedMarkup;\n\t\t\t\t/* eslint-enable no-param-reassign */\n\t\t\t})()\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Wikifier;\n})();\n/* eslint-enable max-len */\n\n/***********************************************************************************************************************\n\n\tmarkup/parserlib.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, DebugView, EOF, Engine, Lexer, Macro, MacroContext, Patterns, Scripting, State, Story, Template,\n\t       Wikifier, toStringOrDefault, throwError\n*/\n/* eslint \"no-param-reassign\": [ 2, { \"props\" : false } ] */\n\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _verbatimTagHandler(w) {\n\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\tconst match = this.lookahead.exec(w.source);\n\n\t\tif (match && match.index === w.matchStart) {\n\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t.append(match[1])\n\t\t\t\t.appendTo(w.output);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tParsers.\n\t*******************************************************************************************************************/\n\tWikifier.Parser.add({\n\t\tname       : 'quoteByBlock',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^<<<\\\\n',\n\t\tterminator : '^<<<\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.subWikify(\n\t\t\t\tjQuery(document.createElement('blockquote'))\n\t\t\t\t\t.appendTo(w.output)\n\t\t\t\t\t.get(0),\n\t\t\t\tthis.terminator\n\t\t\t);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'quoteByLine',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^>+',\n\t\tlookahead  : /^>+/gm,\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst destStack = [w.output];\n\t\t\tlet curLevel = 0;\n\t\t\tlet newLevel = w.matchLength;\n\t\t\tlet matched;\n\t\t\tlet i;\n\n\t\t\tdo {\n\t\t\t\tif (newLevel > curLevel) {\n\t\t\t\t\tfor (i = curLevel; i < newLevel; ++i) {\n\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\tjQuery(document.createElement('blockquote'))\n\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (newLevel < curLevel) {\n\t\t\t\t\tfor (i = curLevel; i > newLevel; --i) {\n\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcurLevel = newLevel;\n\t\t\t\tw.subWikify(destStack[destStack.length - 1], this.terminator);\n\t\t\t\tjQuery(document.createElement('br')).appendTo(destStack[destStack.length - 1]);\n\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tnewLevel = match[0].length;\n\t\t\t\t\tw.nextMatch += match[0].length;\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'macro',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<<',\n\t\tlookahead : new RegExp(`<<(/?${Patterns.macroName})(?:\\\\s*)((?:(?:\\`(?:\\\\\\\\.|[^\\`\\\\\\\\])*\\`)|(?:\"(?:\\\\\\\\.|[^\"\\\\\\\\])*\")|(?:'(?:\\\\\\\\.|[^'\\\\\\\\])*')|(?:\\\\[(?:[<>]?[Ii][Mm][Gg])?\\\\[[^\\\\r\\\\n]*?\\\\]\\\\]+)|[^>]|(?:>(?!>)))*)>>`, 'gm'),\n\t\tworking   : { source : '', name : '', arguments : '', index : 0 }, // the working parse object\n\t\tcontext   : null, // last execution context object (top-level macros, hierarchically, have a null context)\n\n\t\thandler(w) {\n\t\t\tconst matchStart = this.lookahead.lastIndex = w.matchStart;\n\n\t\t\tif (this.parseTag(w)) {\n\t\t\t\t/*\n\t\t\t\t\tIf `parseBody()` is called below, it will modify the current working\n\t\t\t\t\tvalues, so we must cache them now.\n\t\t\t\t*/\n\t\t\t\tconst nextMatch = w.nextMatch;\n\t\t\t\tconst name      = this.working.name;\n\t\t\t\tconst rawArgs   = this.working.arguments;\n\t\t\t\tlet macro;\n\n\t\t\t\ttry {\n\t\t\t\t\tmacro = Macro.get(name);\n\n\t\t\t\t\tif (macro) {\n\t\t\t\t\t\tlet payload = null;\n\n\t\t\t\t\t\tif (macro.hasOwnProperty('tags')) {\n\t\t\t\t\t\t\tpayload = this.parseBody(w, macro);\n\n\t\t\t\t\t\t\tif (!payload) {\n\t\t\t\t\t\t\t\tw.nextMatch = nextMatch; // we must reset `w.nextMatch` here, as `parseBody()` modifies it\n\t\t\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t\t`cannot find a closing tag for macro <<${name}>>`,\n\t\t\t\t\t\t\t\t\t`${w.source.slice(matchStart, w.nextMatch)}\\u2026`\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (typeof macro.handler === 'function') {\n\t\t\t\t\t\t\tconst args = !payload\n\t\t\t\t\t\t\t\t? this.createArgs(rawArgs, this.skipArgs(macro, macro.name))\n\t\t\t\t\t\t\t\t: payload[0].args;\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tNew-style macros.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (macro.hasOwnProperty('_MACRO_API')) {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tAdd the macro's execution context to the context chain.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tthis.context = new MacroContext({\n\t\t\t\t\t\t\t\t\tmacro,\n\t\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\t\targs,\n\t\t\t\t\t\t\t\t\tpayload,\n\t\t\t\t\t\t\t\t\tsource : w.source.slice(matchStart, w.nextMatch),\n\t\t\t\t\t\t\t\t\tparent : this.context,\n\t\t\t\t\t\t\t\t\tparser : w\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tCall the handler.\n\n\t\t\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\t\t\t\t\t\tto ensure that the execution context is properly restored in the event\n\t\t\t\t\t\t\t\t\tthat an uncaught exception is thrown during the handler call.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tmacro.handler.call(this.context);\n\t\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\t\tQUESTION: Swap to the following, which passes macro arguments in\n\t\t\t\t\t\t\t\t\t\tas parameters to the handler function, in addition to them being\n\t\t\t\t\t\t\t\t\t\tavailable on its `this`?  If so, it might still be something to\n\t\t\t\t\t\t\t\t\t\thold off on until v3, when the legacy macro API is removed.\n\n\t\t\t\t\t\t\t\t\t\tmacro.handler.apply(this.context, this.context.args);\n\t\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t\tthis.context = this.context.parent;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t[DEPRECATED] Old-style/legacy macros.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tSet up the raw arguments string.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tconst prevRawArgs = w._rawArgs;\n\t\t\t\t\t\t\t\tw._rawArgs = rawArgs;\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tCall the handler.\n\n\t\t\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\t\t\t\t\t\tto ensure that the previous raw arguments string is properly restored in\n\t\t\t\t\t\t\t\t\tthe event that an uncaught exception is thrown during the handler call.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tmacro.handler(w.output, name, args, w, payload);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t\tw._rawArgs = prevRawArgs;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t`macro <<${name}>> handler function ${macro.hasOwnProperty('handler') ? 'is not a function' : 'does not exist'}`,\n\t\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (Macro.tags.has(name)) {\n\t\t\t\t\t\tconst tags = Macro.tags.get(name);\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`child tag <<${name}>> was found outside of a call to its parent macro${tags.length === 1 ? '' : 's'} <<${tags.join('>>, <<')}>>`,\n\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`macro <<${name}>> does not exist`,\n\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot execute ${macro && macro.isWidget ? 'widget' : 'macro'} <<${name}>>: ${ex.message}`,\n\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\tthis.working.source    = '';\n\t\t\t\t\tthis.working.name      = '';\n\t\t\t\t\tthis.working.arguments = '';\n\t\t\t\t\tthis.working.index     = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t}\n\t\t},\n\n\t\tparseTag(w) {\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart && match[1]) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tthis.working.source    = w.source.slice(match.index, this.lookahead.lastIndex);\n\t\t\t\tthis.working.name      = match[1];\n\t\t\t\tthis.working.arguments = match[2];\n\t\t\t\tthis.working.index     = match.index;\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t},\n\n\t\tparseBody(w, macro) {\n\t\t\tconst openTag  = this.working.name;\n\t\t\tconst closeTag = `/${openTag}`;\n\t\t\tconst closeAlt = `end${openTag}`;\n\t\t\tconst bodyTags = Array.isArray(macro.tags) ? macro.tags : false;\n\t\t\tconst payload  = [];\n\t\t\tlet end          = -1;\n\t\t\tlet opened       = 1;\n\t\t\tlet curSource    = this.working.source;\n\t\t\tlet curTag       = this.working.name;\n\t\t\tlet curArgument  = this.working.arguments;\n\t\t\tlet contentStart = w.nextMatch;\n\n\t\t\twhile ((w.matchStart = w.source.indexOf(this.match, w.nextMatch)) !== -1) {\n\t\t\t\tif (!this.parseTag(w)) {\n\t\t\t\t\tthis.lookahead.lastIndex = w.nextMatch = w.matchStart + this.match.length;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst tagSource = this.working.source;\n\t\t\t\tconst tagName   = this.working.name;\n\t\t\t\tconst tagArgs   = this.working.arguments;\n\t\t\t\tconst tagBegin  = this.working.index;\n\t\t\t\tconst tagEnd    = w.nextMatch;\n\n\t\t\t\tswitch (tagName) {\n\t\t\t\tcase openTag:\n\t\t\t\t\t++opened;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase closeAlt:\n\t\t\t\tcase closeTag:\n\t\t\t\t\t--opened;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tif (opened === 1 && bodyTags) {\n\t\t\t\t\t\tfor (let i = 0, iend = bodyTags.length; i < iend; ++i) {\n\t\t\t\t\t\t\tif (tagName === bodyTags[i]) {\n\t\t\t\t\t\t\t\tpayload.push({\n\t\t\t\t\t\t\t\t\tsource    : curSource,\n\t\t\t\t\t\t\t\t\tname      : curTag,\n\t\t\t\t\t\t\t\t\targuments : curArgument,\n\t\t\t\t\t\t\t\t\targs      : this.createArgs(curArgument, this.skipArgs(macro, curTag)),\n\t\t\t\t\t\t\t\t\tcontents  : w.source.slice(contentStart, tagBegin)\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tcurSource    = tagSource;\n\t\t\t\t\t\t\t\tcurTag       = tagName;\n\t\t\t\t\t\t\t\tcurArgument  = tagArgs;\n\t\t\t\t\t\t\t\tcontentStart = tagEnd;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (opened === 0) {\n\t\t\t\t\tpayload.push({\n\t\t\t\t\t\tsource    : curSource,\n\t\t\t\t\t\tname      : curTag,\n\t\t\t\t\t\targuments : curArgument,\n\t\t\t\t\t\targs      : this.createArgs(curArgument, this.skipArgs(macro, curTag)),\n\t\t\t\t\t\tcontents  : w.source.slice(contentStart, tagBegin)\n\t\t\t\t\t});\n\t\t\t\t\tend = tagEnd;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (end !== -1) {\n\t\t\t\tw.nextMatch = end;\n\t\t\t\treturn payload;\n\t\t\t}\n\n\t\t\treturn null;\n\t\t},\n\n\t\tcreateArgs(rawArgsString, skipArgs) {\n\t\t\tconst args = skipArgs ? [] : this.parseArgs(rawArgsString);\n\n\t\t\t// Extend the args array with the raw and full argument strings.\n\t\t\tObject.defineProperties(args, {\n\t\t\t\traw : {\n\t\t\t\t\tvalue : rawArgsString\n\t\t\t\t},\n\t\t\t\tfull : {\n\t\t\t\t\tvalue : Scripting.parse(rawArgsString)\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn args;\n\t\t},\n\n\t\tskipArgs(macro, tagName) {\n\t\t\tif (macro.hasOwnProperty('skipArgs')) {\n\t\t\t\tconst sa = macro.skipArgs;\n\n\t\t\t\treturn typeof sa === 'boolean' && sa || Array.isArray(sa) && sa.includes(tagName);\n\t\t\t}\n\t\t\t/* legacy */\n\t\t\telse if (macro.hasOwnProperty('skipArg0')) {\n\t\t\t\treturn macro.skipArg0 && macro.name === tagName;\n\t\t\t}\n\t\t\t/* /legacy */\n\n\t\t\treturn false;\n\t\t},\n\n\t\tparseArgs : (() => {\n\t\t\tconst Item = Lexer.enumFromNames([ // lex item types object (pseudo-enumeration)\n\t\t\t\t'Error',        // error\n\t\t\t\t'Bareword',     // bare identifier\n\t\t\t\t'Expression',   // expression (backquoted)\n\t\t\t\t'String',       // quoted string (single or double)\n\t\t\t\t'SquareBracket' // [[…]] or [img[…]]\n\t\t\t]);\n\t\t\tconst spaceRe    = new RegExp(Patterns.space);\n\t\t\tconst notSpaceRe = new RegExp(Patterns.notSpace);\n\t\t\tconst varTest    = new RegExp(`^${Patterns.variable}`);\n\n\t\t\t// Lexing functions.\n\t\t\tfunction slurpQuote(lexer, endQuote) {\n\t\t\t\tloop: for (;;) {\n\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* falls through */\n\t\t\t\t\tcase EOF:\n\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\treturn EOF;\n\n\t\t\t\t\tcase endQuote:\n\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t}\n\n\t\t\t\treturn lexer.pos;\n\t\t\t}\n\n\t\t\tfunction lexSpace(lexer) {\n\t\t\t\tconst offset = lexer.source.slice(lexer.pos).search(notSpaceRe);\n\n\t\t\t\tif (offset === EOF) {\n\t\t\t\t\t// no non-whitespace characters, so bail\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\telse if (offset !== 0) {\n\t\t\t\t\tlexer.pos += offset;\n\t\t\t\t\tlexer.ignore();\n\t\t\t\t}\n\n\t\t\t\t// determine what the next state is\n\t\t\t\tswitch (lexer.next()) {\n\t\t\t\tcase '`':\n\t\t\t\t\treturn lexExpression;\n\t\t\t\tcase '\"':\n\t\t\t\t\treturn lexDoubleQuote;\n\t\t\t\tcase \"'\":\n\t\t\t\t\treturn lexSingleQuote;\n\t\t\t\tcase '[':\n\t\t\t\t\treturn lexSquareBracket;\n\t\t\t\tdefault:\n\t\t\t\t\treturn lexBareword;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction lexExpression(lexer) {\n\t\t\t\tif (slurpQuote(lexer, '`') === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated backquote expression');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.Expression);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexDoubleQuote(lexer) {\n\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated double quoted string');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.String);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexSingleQuote(lexer) {\n\t\t\t\tif (slurpQuote(lexer, \"'\") === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated single quoted string');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.String);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexSquareBracket(lexer) {\n\t\t\t\tconst imgMeta = '<>IiMmGg';\n\t\t\t\tlet what;\n\n\t\t\t\tif (lexer.accept(imgMeta)) {\n\t\t\t\t\twhat = 'image';\n\t\t\t\t\tlexer.acceptRun(imgMeta);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\twhat = 'link';\n\t\t\t\t}\n\n\t\t\t\tif (!lexer.accept('[')) {\n\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t}\n\n\t\t\t\tlexer.depth = 2; // account for both initial left square brackets\n\n\t\t\t\tloop: for (;;) {\n\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* falls through */\n\t\t\t\t\tcase EOF:\n\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\tcase '[':\n\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase ']':\n\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\tif (lexer.depth < 0) {\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, \"unexpected right square bracket ']'\");\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\tif (lexer.next() === ']') {\n\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.SquareBracket);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexBareword(lexer) {\n\t\t\t\tconst offset = lexer.source.slice(lexer.pos).search(spaceRe);\n\t\t\t\tlexer.pos = offset === EOF ? lexer.source.length : lexer.pos + offset;\n\t\t\t\tlexer.emit(Item.Bareword);\n\t\t\t\treturn offset === EOF ? null : lexSpace;\n\t\t\t}\n\n\t\t\t// Parse function.\n\t\t\tfunction parseMacroArgs(rawArgsString) {\n\t\t\t\t// Initialize the lexer.\n\t\t\t\tconst lexer = new Lexer(rawArgsString, lexSpace);\n\t\t\t\tconst args  = [];\n\n\t\t\t\t// Lex the raw argument string.\n\t\t\t\tlexer.run().forEach(item => {\n\t\t\t\t\tlet arg = item.text;\n\n\t\t\t\t\tswitch (item.type) {\n\t\t\t\t\tcase Item.Error:\n\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${item.message}`);\n\n\t\t\t\t\tcase Item.Bareword:\n\t\t\t\t\t\t// A variable, so substitute its value.\n\t\t\t\t\t\tif (varTest.test(arg)) {\n\t\t\t\t\t\t\targ = State.getVar(arg);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Property access on the settings or setup objects, so try to evaluate it.\n\t\t\t\t\t\telse if (/^(?:settings|setup)[.[]/.test(arg)) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\targ = Scripting.evalTwineScript(arg);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Null literal, so convert it into null.\n\t\t\t\t\t\telse if (arg === 'null') {\n\t\t\t\t\t\t\targ = null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Undefined literal, so convert it into undefined.\n\t\t\t\t\t\telse if (arg === 'undefined') {\n\t\t\t\t\t\t\targ = undefined;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Boolean true literal, so convert it into true.\n\t\t\t\t\t\telse if (arg === 'true') {\n\t\t\t\t\t\t\targ = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Boolean false literal, so convert it into false.\n\t\t\t\t\t\telse if (arg === 'false') {\n\t\t\t\t\t\t\targ = false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// NaN literal, so convert it into NaN.\n\t\t\t\t\t\telse if (arg === 'NaN') {\n\t\t\t\t\t\t\targ = NaN;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Attempt to convert it into a number, in case it's a numeric literal.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst argAsNum = Number(arg);\n\n\t\t\t\t\t\t\tif (!Number.isNaN(argAsNum)) {\n\t\t\t\t\t\t\t\targ = argAsNum;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.Expression:\n\t\t\t\t\t\targ = arg.slice(1, -1).trim(); // remove the backquotes and trim the expression\n\n\t\t\t\t\t\t// Empty backquotes.\n\t\t\t\t\t\tif (arg === '') {\n\t\t\t\t\t\t\targ = undefined;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Evaluate the expression.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tThe enclosing parenthesis here are necessary to force a code string\n\t\t\t\t\t\t\t\t\tconsisting solely of an object literal to be evaluated as such, rather\n\t\t\t\t\t\t\t\t\tthan as a code block.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\targ = Scripting.evalTwineScript(`(${arg})`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument expression \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.String:\n\t\t\t\t\t\t// Evaluate the string to handle escaped characters.\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\targ = Scripting.evalJavaScript(arg);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument string \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.SquareBracket:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\t\t\tsource     : arg,\n\t\t\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${markup.error}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (markup.pos < arg.length) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": unexpected character(s) \"${arg.slice(markup.pos)}\" (pos: ${markup.pos})`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert to a link or image object.\n\t\t\t\t\t\t\tif (markup.isLink) {\n\t\t\t\t\t\t\t\t// .isLink, [.text], [.forceInternal], .link, [.setter]\n\t\t\t\t\t\t\t\targ = { isLink : true };\n\t\t\t\t\t\t\t\targ.count    = markup.hasOwnProperty('text') ? 2 : 1;\n\t\t\t\t\t\t\t\targ.link     = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\t\t\t\t\t\targ.text     = markup.hasOwnProperty('text') ? Wikifier.helpers.evalText(markup.text) : arg.link;\n\t\t\t\t\t\t\t\targ.external = !markup.forceInternal && Wikifier.isExternalLink(arg.link);\n\t\t\t\t\t\t\t\targ.setFn    = markup.hasOwnProperty('setter')\n\t\t\t\t\t\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (markup.isImage) {\n\t\t\t\t\t\t\t\t// .isImage, [.align], [.title], .source, [.forceInternal], [.link], [.setter]\n\t\t\t\t\t\t\t\targ = (source => {\n\t\t\t\t\t\t\t\t\tconst imgObj = {\n\t\t\t\t\t\t\t\t\t\tsource,\n\t\t\t\t\t\t\t\t\t\tisImage : true\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t\t// Check for Twine 1.4 Base64 image passage transclusion.\n\t\t\t\t\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t\t\t\t\timgObj.source  = passage.text;\n\t\t\t\t\t\t\t\t\t\t\timgObj.passage = passage.title;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturn imgObj;\n\t\t\t\t\t\t\t\t})(Wikifier.helpers.evalPassageId(markup.source));\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('align')) {\n\t\t\t\t\t\t\t\t\targ.align = markup.align;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('text')) {\n\t\t\t\t\t\t\t\t\targ.title = Wikifier.helpers.evalText(markup.text);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('link')) {\n\t\t\t\t\t\t\t\t\targ.link     = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\t\t\t\t\t\t\targ.external = !markup.forceInternal && Wikifier.isExternalLink(arg.link);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\targ.setFn = markup.hasOwnProperty('setter')\n\t\t\t\t\t\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\targs.push(arg);\n\t\t\t\t});\n\n\t\t\t\treturn args;\n\t\t\t}\n\n\t\t\treturn parseMacroArgs;\n\t\t})()\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'link',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\[\\\\[[^[]',\n\n\t\thandler(w) {\n\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup(w);\n\n\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = markup.pos;\n\n\t\t\t// text=(text), forceInternal=(~), link=link, setter=(setter)\n\t\t\tconst link  = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\tconst text  = markup.hasOwnProperty('text') ? Wikifier.helpers.evalText(markup.text) : link;\n\t\t\tconst setFn = markup.hasOwnProperty('setter')\n\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t: null;\n\n\t\t\t// Debug view setup.\n\t\t\tconst output = (Config.debug\n\t\t\t\t? new DebugView(w.output, 'link-markup', '[[link]]', w.source.slice(w.matchStart, w.nextMatch))\n\t\t\t\t: w\n\t\t\t).output;\n\n\t\t\tif (markup.forceInternal || !Wikifier.isExternalLink(link)) {\n\t\t\t\tWikifier.createInternalLink(output, link, text, setFn);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tWikifier.createExternalLink(output, link, text);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'urlLink',\n\t\tprofiles : ['core'],\n\t\tmatch    : Patterns.url,\n\n\t\thandler(w) {\n\t\t\tw.outputText(Wikifier.createExternalLink(w.output, w.matchText), w.matchStart, w.nextMatch);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'image',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\[[<>]?[Ii][Mm][Gg]\\\\[',\n\n\t\thandler(w) {\n\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup(w);\n\n\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = markup.pos;\n\n\t\t\t// Debug view setup.\n\t\t\tlet debugView;\n\n\t\t\tif (Config.debug) {\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tw.output,\n\t\t\t\t\t'image-markup',\n\t\t\t\t\tmarkup.hasOwnProperty('link') ? '[img[][link]]' : '[img[]]',\n\t\t\t\t\tw.source.slice(w.matchStart, w.nextMatch)\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ block : true });\n\t\t\t}\n\n\t\t\t// align=(left|right), title=(title), source=source, forceInternal=(~), link=(link), setter=(setter)\n\t\t\tconst setFn = markup.hasOwnProperty('setter')\n\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t: null;\n\t\t\tlet el     = (Config.debug ? debugView : w).output;\n\t\t\tlet source;\n\n\t\t\tif (markup.hasOwnProperty('link')) {\n\t\t\t\tconst link = Wikifier.helpers.evalPassageId(markup.link);\n\n\t\t\t\tif (markup.forceInternal || !Wikifier.isExternalLink(link)) {\n\t\t\t\t\tel = Wikifier.createInternalLink(el, link, null, setFn);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tel = Wikifier.createExternalLink(el, link);\n\t\t\t\t}\n\n\t\t\t\tel.classList.add('link-image');\n\t\t\t}\n\n\t\t\tel = jQuery(document.createElement('img'))\n\t\t\t\t.appendTo(el)\n\t\t\t\t.get(0);\n\t\t\tsource = Wikifier.helpers.evalPassageId(markup.source);\n\n\t\t\t// Check for image passage transclusion.\n\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\tel.setAttribute('data-passage', passage.title);\n\t\t\t\t\tsource = passage.text.trim();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tel.src = source;\n\n\t\t\tif (markup.hasOwnProperty('text')) {\n\t\t\t\tel.title = Wikifier.helpers.evalText(markup.text);\n\t\t\t}\n\n\t\t\tif (markup.hasOwnProperty('align')) {\n\t\t\t\tel.align = markup.align;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'monospacedByBlock',\n\t\tprofiles  : ['block'],\n\t\tmatch     : '^\\\\{\\\\{\\\\{\\\\n',\n\t\tlookahead : /^\\{\\{\\{\\n((?:^[^\\n]*\\n)+?)(^\\}\\}\\}$\\n?)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tconst pre = jQuery(document.createElement('pre'));\n\t\t\t\tjQuery(document.createElement('code'))\n\t\t\t\t\t.text(match[1])\n\t\t\t\t\t.appendTo(pre);\n\t\t\t\tpre.appendTo(w.output);\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'formatByChar',\n\t\tprofiles : ['core'],\n\t\tmatch    : \"''|//|__|\\\\^\\\\^|~~|==|\\\\{\\\\{\\\\{\",\n\n\t\thandler(w) {\n\t\t\tswitch (w.matchText) {\n\t\t\tcase \"''\":\n\t\t\t\tw.subWikify(jQuery(document.createElement('strong')).appendTo(w.output).get(0), \"''\");\n\t\t\t\tbreak;\n\n\t\t\tcase '//':\n\t\t\t\tw.subWikify(jQuery(document.createElement('em')).appendTo(w.output).get(0), '//');\n\t\t\t\tbreak;\n\n\t\t\tcase '__':\n\t\t\t\tw.subWikify(jQuery(document.createElement('u')).appendTo(w.output).get(0), '__');\n\t\t\t\tbreak;\n\n\t\t\tcase '^^':\n\t\t\t\tw.subWikify(jQuery(document.createElement('sup')).appendTo(w.output).get(0), '\\\\^\\\\^');\n\t\t\t\tbreak;\n\n\t\t\tcase '~~':\n\t\t\t\tw.subWikify(jQuery(document.createElement('sub')).appendTo(w.output).get(0), '~~');\n\t\t\t\tbreak;\n\n\t\t\tcase '==':\n\t\t\t\tw.subWikify(jQuery(document.createElement('s')).appendTo(w.output).get(0), '==');\n\t\t\t\tbreak;\n\n\t\t\tcase '{{{':\n\t\t\t\t{\n\t\t\t\t\tconst lookahead = /\\{\\{\\{((?:.|\\n)*?)\\}\\}\\}/gm;\n\n\t\t\t\t\tlookahead.lastIndex = w.matchStart;\n\n\t\t\t\t\tconst match = lookahead.exec(w.source);\n\n\t\t\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\t\t\tjQuery(document.createElement('code'))\n\t\t\t\t\t\t\t.text(match[1])\n\t\t\t\t\t\t\t.appendTo(w.output);\n\t\t\t\t\t\tw.nextMatch = lookahead.lastIndex;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'customStyle',\n\t\tprofiles   : ['core'],\n\t\tmatch      : '@@',\n\t\tterminator : '@@',\n\t\tblockRe    : /\\s*\\n/gm,\n\n\t\thandler(w) {\n\t\t\tconst css = Wikifier.helpers.inlineCss(w);\n\n\t\t\tthis.blockRe.lastIndex = w.nextMatch; // must follow the call to `inlineCss()`\n\n\t\t\tconst blockMatch = this.blockRe.exec(w.source);\n\t\t\tconst blockLevel = blockMatch && blockMatch.index === w.nextMatch;\n\t\t\tconst $el        = jQuery(document.createElement(blockLevel ? 'div' : 'span'))\n\t\t\t\t.appendTo(w.output);\n\n\t\t\tif (css.classes.length === 0 && css.id === '' && Object.keys(css.styles).length === 0) {\n\t\t\t\t$el.addClass('marked');\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcss.classes.forEach(className => $el.addClass(className));\n\n\t\t\t\tif (css.id !== '') {\n\t\t\t\t\t$el.attr('id', css.id);\n\t\t\t\t}\n\n\t\t\t\t$el.css(css.styles);\n\t\t\t}\n\n\t\t\tif (blockLevel) {\n\t\t\t\t// Skip the leading and, if it exists, trailing newlines.\n\t\t\t\tw.nextMatch += blockMatch[0].length;\n\t\t\t\tw.subWikify($el[0], `\\\\n?${this.terminator}`);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tw.subWikify($el[0], this.terminator);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimText',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '\"{3}|<[Nn][Oo][Ww][Ii][Kk][Ii]>',\n\t\tlookahead : /(?:\"{3}((?:.|\\n)*?)\"{3})|(?:<[Nn][Oo][Ww][Ii][Kk][Ii]>((?:.|\\n)*?)<\\/[Nn][Oo][Ww][Ii][Kk][Ii]>)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tjQuery(document.createElement('span'))\n\t\t\t\t\t.addClass('verbatim')\n\t\t\t\t\t.text(match[1] || match[2])\n\t\t\t\t\t.appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'horizontalRule',\n\t\tprofiles : ['core'],\n\t\tmatch    : '^----+$\\\\n?|<[Hh][Rr]\\\\s*/?>\\\\n?',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createElement('hr')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'emdash',\n\t\tprofiles : ['core'],\n\t\tmatch    : '--',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createTextNode('\\u2014')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'doubleDollarSign',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\${2}', // eslint-disable-line no-template-curly-in-string\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createTextNode('$')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\t/*\n\t\t\tSupported syntax:\n\t\t\t\t$variable\n\t\t\t\t$variable.property\n\t\t\t\t$variable[numericIndex]\n\t\t\t\t$variable[\"property\"]\n\t\t\t\t$variable['property']\n\t\t\t\t$variable[$indexOrPropertyVariable]\n\t\t*/\n\t\tname     : 'nakedVariable',\n\t\tprofiles : ['core'],\n\t\tmatch    : `${Patterns.variable}(?:(?:\\\\.${Patterns.identifier})|(?:\\\\[\\\\d+\\\\])|(?:\\\\[\"(?:\\\\\\\\.|[^\"\\\\\\\\])+\"\\\\])|(?:\\\\['(?:\\\\\\\\.|[^'\\\\\\\\])+'\\\\])|(?:\\\\[${Patterns.variable}\\\\]))*`,\n\n\t\thandler(w) {\n\t\t\tconst result = toStringOrDefault(State.getVar(w.matchText), null);\n\n\t\t\tif (result === null) {\n\t\t\t\tjQuery(document.createTextNode(w.matchText)).appendTo(w.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnew Wikifier(\n\t\t\t\t\t(Config.debug\n\t\t\t\t\t\t? new DebugView(w.output, 'variable', w.matchText, w.matchText) // Debug view setup.\n\t\t\t\t\t\t: w\n\t\t\t\t\t).output,\n\t\t\t\t\tresult\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'template',\n\t\tprofiles : ['core'],\n\t\tmatch    : `\\\\?${Patterns.templateName}`,\n\n\t\thandler(w) {\n\t\t\tconst name = w.matchText.slice(1);\n\t\t\tlet template = Template.get(name);\n\t\t\tlet result   = null;\n\n\t\t\t// If we have an array of templates, randomly choose one.\n\t\t\tif (template instanceof Array) {\n\t\t\t\ttemplate = template.random();\n\t\t\t}\n\n\t\t\tswitch (typeof template) {\n\t\t\tcase 'function':\n\t\t\t\ttry {\n\t\t\t\t\tresult = toStringOrDefault(template.call({ name }), null);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot execute function template ?${name}: ${ex.message}`,\n\t\t\t\t\t\tw.source.slice(w.matchStart, w.nextMatch)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'string':\n\t\t\t\tresult = template;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (result === null) {\n\t\t\t\tjQuery(document.createTextNode(w.matchText)).appendTo(w.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnew Wikifier(\n\t\t\t\t\t(Config.debug\n\t\t\t\t\t\t? new DebugView(w.output, 'template', w.matchText, w.matchText) // Debug view setup.\n\t\t\t\t\t\t: w\n\t\t\t\t\t).output,\n\t\t\t\t\tresult\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'heading',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^!{1,6}',\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.subWikify(\n\t\t\t\tjQuery(document.createElement(`h${w.matchLength}`)).appendTo(w.output).get(0),\n\t\t\t\tthis.terminator\n\t\t\t);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname           : 'table',\n\t\tprofiles       : ['block'],\n\t\tmatch          : '^\\\\|(?:[^\\\\n]*)\\\\|(?:[fhck]?)$',\n\t\tlookahead      : /^\\|([^\\n]*)\\|([fhck]?)$/gm,\n\t\trowTerminator  : '\\\\|(?:[cfhk]?)$\\\\n?',\n\t\tcellPattern    : '(?:\\\\|([^\\\\n\\\\|]*)\\\\|)|(\\\\|[cfhk]?$\\\\n?)',\n\t\tcellTerminator : '(?:\\\\u0020*)\\\\|',\n\t\trowTypes       : { c : 'caption', f : 'tfoot', h : 'thead', '' : 'tbody' }, // eslint-disable-line id-length\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst table       = jQuery(document.createElement('table')).appendTo(w.output).get(0);\n\t\t\tconst prevColumns = [];\n\t\t\tlet curRowType    = null;\n\t\t\tlet $rowContainer = null;\n\t\t\tlet rowCount      = 0;\n\t\t\tlet matched;\n\n\t\t\tw.nextMatch = w.matchStart;\n\n\t\t\tdo {\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tconst nextRowType = match[2];\n\n\t\t\t\t\tif (nextRowType === 'k') {\n\t\t\t\t\t\ttable.className = match[1];\n\t\t\t\t\t\tw.nextMatch += match[0].length + 1;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (nextRowType !== curRowType) {\n\t\t\t\t\t\t\tcurRowType = nextRowType;\n\t\t\t\t\t\t\t$rowContainer = jQuery(document.createElement(this.rowTypes[nextRowType]))\n\t\t\t\t\t\t\t\t.appendTo(table);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (curRowType === 'c') {\n\t\t\t\t\t\t\t$rowContainer.css('caption-side', rowCount === 0 ? 'top' : 'bottom');\n\t\t\t\t\t\t\tw.nextMatch += 1;\n\t\t\t\t\t\t\tw.subWikify($rowContainer[0], this.rowTerminator);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tthis.rowHandler(\n\t\t\t\t\t\t\t\tw,\n\t\t\t\t\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t\t\t\t\t.appendTo($rowContainer)\n\t\t\t\t\t\t\t\t\t.get(0),\n\t\t\t\t\t\t\t\tprevColumns\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t++rowCount;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t},\n\n\t\trowHandler(w, rowEl, prevColumns) {\n\t\t\tconst cellRe = new RegExp(this.cellPattern, 'gm');\n\t\t\tlet col         = 0;\n\t\t\tlet curColCount = 1;\n\t\t\tlet matched;\n\n\t\t\tdo {\n\t\t\t\tcellRe.lastIndex = w.nextMatch;\n\n\t\t\t\tconst cellMatch = cellRe.exec(w.source);\n\n\t\t\t\tmatched = cellMatch && cellMatch.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tif (cellMatch[1] === '~') {\n\t\t\t\t\t\tconst last = prevColumns[col];\n\n\t\t\t\t\t\tif (last) {\n\t\t\t\t\t\t\t++last.rowCount;\n\t\t\t\t\t\t\tlast.$element\n\t\t\t\t\t\t\t\t.attr('rowspan', last.rowCount)\n\t\t\t\t\t\t\t\t.css('vertical-align', 'middle');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length - 1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (cellMatch[1] === '>') {\n\t\t\t\t\t\t++curColCount;\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length - 1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (cellMatch[2]) {\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t++w.nextMatch;\n\n\t\t\t\t\t\tconst css = Wikifier.helpers.inlineCss(w);\n\t\t\t\t\t\tlet spaceLeft  = false;\n\t\t\t\t\t\tlet spaceRight = false;\n\t\t\t\t\t\tlet $cell;\n\n\t\t\t\t\t\twhile (w.source.substr(w.nextMatch, 1) === ' ') {\n\t\t\t\t\t\t\tspaceLeft = true;\n\t\t\t\t\t\t\t++w.nextMatch;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (w.source.substr(w.nextMatch, 1) === '!') {\n\t\t\t\t\t\t\t$cell = jQuery(document.createElement('th')).appendTo(rowEl);\n\t\t\t\t\t\t\t++w.nextMatch;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t$cell = jQuery(document.createElement('td')).appendTo(rowEl);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tprevColumns[col] = {\n\t\t\t\t\t\t\trowCount : 1,\n\t\t\t\t\t\t\t$element : $cell\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (curColCount > 1) {\n\t\t\t\t\t\t\t$cell.attr('colspan', curColCount);\n\t\t\t\t\t\t\tcurColCount = 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tw.subWikify($cell[0], this.cellTerminator);\n\n\t\t\t\t\t\tif (w.matchText.substr(w.matchText.length - 2, 1) === ' ') {\n\t\t\t\t\t\t\tspaceRight = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcss.classes.forEach(className => $cell.addClass(className));\n\n\t\t\t\t\t\tif (css.id !== '') {\n\t\t\t\t\t\t\t$cell.attr('id', css.id);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (spaceLeft && spaceRight) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'center';\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (spaceLeft) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'right';\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (spaceRight) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'left';\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$cell.css(css.styles);\n\n\t\t\t\t\t\tw.nextMatch = w.nextMatch - 1;\n\t\t\t\t\t}\n\n\t\t\t\t\t++col;\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'list',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^(?:(?:\\\\*+)|(?:#+))',\n\t\tlookahead  : /^(?:(\\*+)|(#+))/gm,\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = w.matchStart;\n\n\t\t\tconst destStack = [w.output];\n\t\t\tlet curType  = null;\n\t\t\tlet curLevel = 0;\n\t\t\tlet matched;\n\t\t\tlet i;\n\n\t\t\tdo {\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tconst newType  = match[2] ? 'ol' : 'ul';\n\t\t\t\t\tconst newLevel = match[0].length;\n\n\t\t\t\t\tw.nextMatch += match[0].length;\n\n\t\t\t\t\tif (newLevel > curLevel) {\n\t\t\t\t\t\tfor (i = curLevel; i < newLevel; ++i) {\n\t\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\t\tjQuery(document.createElement(newType))\n\t\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (newLevel < curLevel) {\n\t\t\t\t\t\tfor (i = curLevel; i > newLevel; --i) {\n\t\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (newLevel === curLevel && newType !== curType) {\n\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\tjQuery(document.createElement(newType))\n\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tcurLevel = newLevel;\n\t\t\t\t\tcurType = newType;\n\t\t\t\t\tw.subWikify(\n\t\t\t\t\t\tjQuery(document.createElement('li'))\n\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t.get(0),\n\t\t\t\t\t\tthis.terminator\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'commentByBlock',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '(?:/(?:%|\\\\*))|(?:<!--)',\n\t\tlookahead : /(?:\\/(%|\\*)(?:(?:.|\\n)*?)\\1\\/)|(?:<!--(?:(?:.|\\n)*?)-->)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'lineContinuation',\n\t\tprofiles : ['core'],\n\n\t\t// WARNING: The ordering here is important: end-of-line, start-of-line, end-of-string, start-of-string.\n\t\tmatch : `\\\\\\\\${Patterns.spaceNoTerminator}*\\\\n|\\\\n${Patterns.spaceNoTerminator}*\\\\\\\\|\\\\n?\\\\\\\\${Patterns.spaceNoTerminator}*$|^${Patterns.spaceNoTerminator}*\\\\\\\\\\\\n?`,\n\n\t\thandler(w) {\n\t\t\tw.nextMatch = w.matchStart + w.matchLength;\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'lineBreak',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\n|<[Bb][Rr]\\\\s*/?>',\n\n\t\thandler(w) {\n\t\t\tif (!w.options.nobr) {\n\t\t\t\tjQuery(document.createElement('br')).appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'htmlCharacterReference',\n\t\tprofiles : ['core'],\n\t\tmatch    : '(?:(?:&#?[0-9A-Za-z]{2,8};|.)(?:&#?(?:x0*(?:3[0-6][0-9A-Fa-f]|1D[C-Fc-f][0-9A-Fa-f]|20[D-Fd-f][0-9A-Fa-f]|FE2[0-9A-Fa-f])|0*(?:76[89]|7[7-9][0-9]|8[0-7][0-9]|761[6-9]|76[2-7][0-9]|84[0-3][0-9]|844[0-7]|6505[6-9]|6506[0-9]|6507[0-1]));)+|&#?[0-9A-Za-z]{2,8};)',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t.append(w.matchText)\n\t\t\t\t.appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'xmlProlog',\n\t\tprofiles : ['core'],\n\t\tmatch    : '<\\\\?[Xx][Mm][Ll][^>]*\\\\?>',\n\n\t\thandler(w) {\n\t\t\tw.nextMatch = w.matchStart + w.matchLength;\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimHtml',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Hh][Tt][Mm][Ll]>',\n\t\tlookahead : /<[Hh][Tt][Mm][Ll]>((?:.|\\n)*?)<\\/[Hh][Tt][Mm][Ll]>/gm,\n\t\thandler   : _verbatimTagHandler\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimScriptTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Ss][Cc][Rr][Ii][Pp][Tt][^>]*>',\n\t\tlookahead : /(<[Ss][Cc][Rr][Ii][Pp][Tt]*>(?:.|\\n)*?<\\/[Ss][Cc][Rr][Ii][Pp][Tt]>)/gm,\n\t\thandler   : _verbatimTagHandler\n\t});\n\n\tWikifier.Parser.add({\n\t\tname           : 'styleTag',\n\t\tprofiles       : ['core'],\n\t\tmatch          : '<[Ss][Tt][Yy][Ll][Ee][^>]*>',\n\t\tlookahead      : /(<[Ss][Tt][Yy][Ll][Ee]*>)((?:.|\\n)*?)(<\\/[Ss][Tt][Yy][Ll][Ee]>)/gm,\n\t\timageMarkup    : new RegExp(Patterns.cssImage, 'g'),\n\t\thasImageMarkup : new RegExp(Patterns.cssImage),\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tlet css = match[2];\n\n\t\t\t\t// Check for wiki image transclusion.\n\t\t\t\tif (this.hasImageMarkup.test(css)) {\n\t\t\t\t\tthis.imageMarkup.lastIndex = 0;\n\n\t\t\t\t\tcss = css.replace(this.imageMarkup, wikiImage => {\n\t\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\t\tsource     : wikiImage,\n\t\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (markup.hasOwnProperty('error') || markup.pos < wikiImage.length) {\n\t\t\t\t\t\t\treturn wikiImage;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet source = markup.source;\n\n\t\t\t\t\t\t// Handle image passage transclusion.\n\t\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t\tsource = passage.text;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tThe source may be URI- or Base64-encoded, so we cannot use `encodeURIComponent()`\n\t\t\t\t\t\t\there.  Instead, we simply encode any double quotes, since the URI will be\n\t\t\t\t\t\t\tdelimited by them.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\treturn `url(\"${source.replace(/\"/g, '%22')}\")`;\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t\t.append(match[1] + css + match[3])\n\t\t\t\t\t.appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'svgTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Ss][Vv][Gg][^>]*>',\n\t\tlookahead : /(<[Ss][Vv][Gg][^>]*>(?:.|\\n)*?<\\/[Ss][Vv][Gg]>)/gm,\n\t\tnamespace : 'http://www.w3.org/2000/svg',\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tconst $frag = jQuery(document.createDocumentFragment()).append(match[1]);\n\n\t\t\t\t// Postprocess the relevant SVG element nodes.\n\t\t\t\t$frag.find('a[data-passage],image[data-passage]').each((_, el) => {\n\t\t\t\t\tconst tagName = el.tagName.toLowerCase();\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.processAttributeDirectives(el);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`svg|<${tagName}>: ${ex.message}`,\n\t\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (el.hasAttribute('data-passage')) {\n\t\t\t\t\t\tthis.processDataAttributes(el, tagName);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\t$frag.appendTo(w.output);\n\t\t\t}\n\t\t},\n\n\t\tprocessAttributeDirectives(el) {\n\t\t\t// NOTE: The `.attributes` property yields a live collection, so we\n\t\t\t// must make a non-live copy of it as we will be adding and removing\n\t\t\t// members of said collection if any directives are found.\n\t\t\t[...el.attributes].forEach(({ name, value }) => {\n\t\t\t\tconst evalShorthand = name[0] === '@';\n\n\t\t\t\tif (evalShorthand || name.startsWith('sc-eval:')) {\n\t\t\t\t\tconst newName = name.slice(evalShorthand ? 1 : 8); // Remove eval directive prefix.\n\n\t\t\t\t\tif (newName === 'data-setter') {\n\t\t\t\t\t\tthrow new Error(`evaluation directive is not allowed on the data-setter attribute: \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\t// Evaluate the value as TwineScript.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = Scripting.evalTwineScript(value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`bad evaluation from attribute directive \"${name}\": ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Assign the result to the new attribute and remove the old one.\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: Most browsers (ca. Nov 2017) have broken `setAttribute()`\n\t\t\t\t\t\t\tmethod implementations that throw on attribute names that start\n\t\t\t\t\t\t\twith, or contain, various symbols that are completely valid per\n\t\t\t\t\t\t\tthe specification.  Thus this code could fail if the user chooses\n\t\t\t\t\t\t\tattribute names that, after removing the directive prefix, are\n\t\t\t\t\t\t\tunpalatable to `setAttribute()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tel.setAttribute(newName, result);\n\t\t\t\t\t\tel.removeAttribute(name);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`cannot transform attribute directive \"${name}\" into attribute \"${newName}\"`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tprocessDataAttributes(el, tagName) {\n\t\t\tlet passage = el.getAttribute('data-passage');\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst evaluated = Wikifier.helpers.evalPassageId(passage);\n\n\t\t\tif (evaluated !== passage) {\n\t\t\t\tpassage = evaluated;\n\t\t\t\tel.setAttribute('data-passage', evaluated);\n\t\t\t}\n\n\t\t\tif (passage !== '') {\n\t\t\t\t// '<image>' element, so attempt media passage transclusion.\n\t\t\t\tif (tagName === 'image') {\n\t\t\t\t\tif (passage.slice(0, 5) !== 'data:' && Story.has(passage)) {\n\t\t\t\t\t\tpassage = Story.get(passage);\n\n\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t// NOTE: SVG `.href` IDL attribute is read-only,\n\t\t\t\t\t\t\t// so set its `href` content attribute instead.\n\t\t\t\t\t\t\tel.setAttribute('href', passage.text.trim());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Elsewise, assume a link element of some type—e.g., '<a>'.\n\t\t\t\telse {\n\t\t\t\t\tlet setter = el.getAttribute('data-setter');\n\t\t\t\t\tlet setFn;\n\n\t\t\t\t\tif (setter != null) { // lazy equality for null\n\t\t\t\t\t\tsetter = String(setter).trim();\n\n\t\t\t\t\t\tif (setter !== '') {\n\t\t\t\t\t\t\tsetFn = Wikifier.helpers.createShadowSetterCallback(Scripting.parse(setter));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tel.classList.add('link-internal');\n\n\t\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t\tel.classList.add('link-visited');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tel.classList.add('link-broken');\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery(el).ariaClick({ one : true }, function () {\n\t\t\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\t\t\tsetFn.call(this);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\t/*\n\t\t\tNOTE: This parser MUST come after any parser which handles HTML tag-\n\t\t\tlike constructs—e.g. 'verbatimText', 'horizontalRule', 'lineBreak',\n\t\t\t'xmlProlog', 'verbatimHtml', 'verbatimSvgTag', 'verbatimScriptTag',\n\t\t\tand 'styleTag'.\n\t\t*/\n\t\tname      : 'htmlTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<\\\\w+(?:\\\\s+[^\\\\u0000-\\\\u001F\\\\u007F-\\\\u009F\\\\s\"\\'>\\\\/=]+(?:\\\\s*=\\\\s*(?:\"[^\"]*?\"|\\'[^\\']*?\\'|[^\\\\s\"\\'=<>`]+))?)*\\\\s*\\\\/?>',\n\t\ttagRe     : /^<(\\w+)/,\n\t\tmediaTags : ['audio', 'img', 'source', 'track', 'video'], // NOTE: The `<picture>` element should not be in this list.\n\t\tnobrTags  : ['audio', 'colgroup', 'datalist', 'dl', 'figure', 'meter', 'ol', 'optgroup', 'picture', 'progress', 'ruby', 'select', 'table', 'tbody', 'tfoot', 'thead', 'tr', 'ul', 'video'],\n\t\tvoidTags  : ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'],\n\n\t\thandler(w) {\n\t\t\tconst tagMatch = this.tagRe.exec(w.matchText);\n\t\t\tconst tag      = tagMatch && tagMatch[1];\n\t\t\tconst tagName  = tag && tag.toLowerCase();\n\n\t\t\tif (tagName) {\n\t\t\t\tconst isVoid = this.voidTags.includes(tagName) || w.matchText.endsWith('/>');\n\t\t\t\tconst isNobr = this.nobrTags.includes(tagName);\n\t\t\t\tlet terminator;\n\t\t\t\tlet terminatorMatch;\n\n\t\t\t\tif (!isVoid) {\n\t\t\t\t\tterminator = `<\\\\/${tagName}\\\\s*>`;\n\n\t\t\t\t\tconst terminatorRe = new RegExp(terminator, 'gim'); // ignore case during match\n\n\t\t\t\t\tterminatorRe.lastIndex = w.matchStart;\n\t\t\t\t\tterminatorMatch = terminatorRe.exec(w.source);\n\t\t\t\t}\n\n\t\t\t\tif (isVoid || terminatorMatch) {\n\t\t\t\t\tlet output    = w.output;\n\t\t\t\t\tlet el        = document.createElement(w.output.tagName);\n\t\t\t\t\tlet debugView;\n\n\t\t\t\t\tel.innerHTML = w.matchText;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tNOTE: The use of a `while` statement here is curious, however,\n\t\t\t\t\t\tI'm hesitant to change it for fear of breaking some edge case.\n\t\t\t\t\t*/\n\t\t\t\t\twhile (el.firstChild) {\n\t\t\t\t\t\tel = el.firstChild;\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.processAttributeDirectives(el);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`<${tagName}>: ${ex.message}`,\n\t\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (el.hasAttribute('data-passage')) {\n\t\t\t\t\t\tthis.processDataAttributes(el, tagName);\n\n\t\t\t\t\t\t// Debug view setup.\n\t\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t`html-${tagName}`,\n\t\t\t\t\t\t\t\ttagName,\n\t\t\t\t\t\t\t\tw.matchText\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tdebugView.modes({\n\t\t\t\t\t\t\t\tblock   : tagName === 'img',\n\t\t\t\t\t\t\t\tnonvoid : terminatorMatch\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\toutput = debugView.output;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (terminatorMatch) {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists\n\t\t\t\t\t\t\tsolely to ensure that the options stack is properly restored in\n\t\t\t\t\t\t\tthe event that an uncaught exception is thrown during the call to\n\t\t\t\t\t\t\t`subWikify()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tWikifier.Option.push({ nobr : isNobr });\n\t\t\t\t\t\t\tw.subWikify(el, terminator, { ignoreTerminatorCase : true });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\tWikifier.Option.pop();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tDebug view modification.  If the current element has any debug\n\t\t\t\t\t\t\tview descendants who have \"block\" mode set, then set its debug\n\t\t\t\t\t\t\tview to the same.  It just makes things look a bit nicer.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tif (debugView && jQuery(el).find('.debug.block').length > 0) {\n\t\t\t\t\t\t\tdebugView.modes({ block : true });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tNOTE: The use of `cloneNode(true)` here for `<track>` elements\n\t\t\t\t\t\tis necessary to workaround a poorly understood rehoming issue.\n\t\t\t\t\t*/\n\t\t\t\t\toutput.appendChild(tagName === 'track' ? el.cloneNode(true) : el);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot find a closing tag for HTML <${tag}>`,\n\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tprocessAttributeDirectives(el) {\n\t\t\t// NOTE: The `.attributes` property yields a live collection, so we\n\t\t\t// must make a non-live copy of it as we will be adding and removing\n\t\t\t// members of said collection if any directives are found.\n\t\t\t[...el.attributes].forEach(({ name, value }) => {\n\t\t\t\tconst evalShorthand = name[0] === '@';\n\n\t\t\t\tif (evalShorthand || name.startsWith('sc-eval:')) {\n\t\t\t\t\tconst newName = name.slice(evalShorthand ? 1 : 8); // Remove eval directive prefix.\n\n\t\t\t\t\tif (newName === 'data-setter') {\n\t\t\t\t\t\tthrow new Error(`evaluation directive is not allowed on the data-setter attribute: \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\t// Evaluate the value as TwineScript.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = Scripting.evalTwineScript(value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`bad evaluation from attribute directive \"${name}\": ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Assign the result to the new attribute and remove the old one.\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: Most browsers (ca. Nov 2017) have broken `setAttribute()`\n\t\t\t\t\t\t\tmethod implementations that throw on attribute names that start\n\t\t\t\t\t\t\twith, or contain, various symbols that are completely valid per\n\t\t\t\t\t\t\tthe specification.  Thus this code could fail if the user chooses\n\t\t\t\t\t\t\tattribute names that, after removing the directive prefix, are\n\t\t\t\t\t\t\tunpalatable to `setAttribute()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tel.setAttribute(newName, result);\n\t\t\t\t\t\tel.removeAttribute(name);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`cannot transform attribute directive \"${name}\" into attribute \"${newName}\"`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tprocessDataAttributes(el, tagName) {\n\t\t\tlet passage = el.getAttribute('data-passage');\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst evaluated = Wikifier.helpers.evalPassageId(passage);\n\n\t\t\tif (evaluated !== passage) {\n\t\t\t\tpassage = evaluated;\n\t\t\t\tel.setAttribute('data-passage', evaluated);\n\t\t\t}\n\n\t\t\tif (passage !== '') {\n\t\t\t\t// Media element, so attempt media passage transclusion.\n\t\t\t\tif (this.mediaTags.includes(tagName)) {\n\t\t\t\t\tif (passage.slice(0, 5) !== 'data:' && Story.has(passage)) {\n\t\t\t\t\t\tpassage = Story.get(passage);\n\n\t\t\t\t\t\tlet parentName;\n\t\t\t\t\t\tlet twineTag;\n\n\t\t\t\t\t\tswitch (tagName) {\n\t\t\t\t\t\tcase 'audio':\n\t\t\t\t\t\tcase 'video':\n\t\t\t\t\t\t\ttwineTag = `Twine.${tagName}`;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'img':\n\t\t\t\t\t\t\ttwineTag = 'Twine.image';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'track':\n\t\t\t\t\t\t\ttwineTag = 'Twine.vtt';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'source':\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst $parent = $(el).closest('audio,picture,video');\n\n\t\t\t\t\t\t\t\tif ($parent.length) {\n\t\t\t\t\t\t\t\t\tparentName = $parent.get(0).tagName.toLowerCase();\n\t\t\t\t\t\t\t\t\ttwineTag = `Twine.${parentName === 'picture' ? 'image' : parentName}`;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (passage.tags.includes(twineTag)) {\n\t\t\t\t\t\t\tel[parentName === 'picture' ? 'srcset' : 'src'] = passage.text.trim();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Elsewise, assume a link element of some type—e.g., '<a>', '<area>', '<button>', etc.\n\t\t\t\telse {\n\t\t\t\t\tlet setter = el.getAttribute('data-setter');\n\t\t\t\t\tlet setFn;\n\n\t\t\t\t\tif (setter != null) { // lazy equality for null\n\t\t\t\t\t\tsetter = String(setter).trim();\n\n\t\t\t\t\t\tif (setter !== '') {\n\t\t\t\t\t\t\tsetFn = Wikifier.helpers.createShadowSetterCallback(Scripting.parse(setter));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tel.classList.add('link-internal');\n\n\t\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t\tel.classList.add('link-visited');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tel.classList.add('link-broken');\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery(el).ariaClick({ one : true }, function () {\n\t\t\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\t\t\tsetFn.call(this);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/template.js\n\n\tCopyright © 2019–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns */\n\nvar Template = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Template definitions.\n\tconst _templates = new Map();\n\n\t// Valid template name regular expression.\n\tconst _validNameRe = new RegExp(`^(?:${Patterns.templateName})$`);\n\n\t// Valid template type predicate.\n\tconst _validType = template => {\n\t\tconst templateType = typeof template;\n\t\treturn templateType === 'function' || templateType === 'string';\n\t};\n\n\n\t/*******************************************************************************\n\t\tTemplate Functions.\n\t*******************************************************************************/\n\n\tfunction templateAdd(name, template) {\n\t\tif (\n\t\t\t   !_validType(template)\n\t\t\t&& !(template instanceof Array && template.length > 0 && template.every(_validType))\n\t\t) {\n\t\t\tthrow new TypeError(`invalid template type (${name}); templates must be: functions, strings, or an array of either`);\n\t\t}\n\n\t\t(name instanceof Array ? name : [name]).forEach(name => {\n\t\t\tif (!_validNameRe.test(name)) {\n\t\t\t\tthrow new Error(`invalid template name \"${name}\"`);\n\t\t\t}\n\t\t\tif (_templates.has(name)) {\n\t\t\t\tthrow new Error(`cannot clobber existing template ?${name}`);\n\t\t\t}\n\n\t\t\t_templates.set(name, template);\n\t\t});\n\t}\n\n\tfunction templateDelete(name) {\n\t\t(name instanceof Array ? name : [name]).forEach(name => _templates.delete(name));\n\t}\n\n\tfunction templateGet(name) {\n\t\treturn _templates.has(name) ? _templates.get(name) : null;\n\t}\n\n\tfunction templateHas(name) {\n\t\treturn _templates.has(name);\n\t}\n\n\tfunction templateSize() {\n\t\treturn _templates.size;\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tadd    : { value : templateAdd },\n\t\tdelete : { value : templateDelete },\n\t\tget    : { value : templateGet },\n\t\thas    : { value : templateHas },\n\t\tsize   : { get : templateSize }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macro.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns, Scripting, clone, macros */\n\nvar Macro = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Macro definitions.\n\tconst _macros = {};\n\n\t// Map of all macro tags and their parents (key: 'tag name' => value: ['list of parent names']).\n\tconst _tags = {};\n\n\t// Valid macro name regular expression.\n\tconst _validNameRe = new RegExp(`^(?:${Patterns.macroName})$`);\n\n\n\t/*******************************************************************************************************************\n\t\tMacros Functions.\n\t*******************************************************************************************************************/\n\tfunction macrosAdd(name, def, deep) {\n\t\tif (Array.isArray(name)) {\n\t\t\tname.forEach(name => macrosAdd(name, def, deep));\n\t\t\treturn;\n\t\t}\n\n\t\tif (!_validNameRe.test(name)) {\n\t\t\tthrow new Error(`invalid macro name \"${name}\"`);\n\t\t}\n\n\t\tif (macrosHas(name)) {\n\t\t\tthrow new Error(`cannot clobber existing macro <<${name}>>`);\n\t\t}\n\t\telse if (tagsHas(name)) {\n\t\t\tthrow new Error(`cannot clobber child tag <<${name}>> of parent macro${_tags[name].length === 1 ? '' : 's'} <<${_tags[name].join('>>, <<')}>>`);\n\t\t}\n\n\t\ttry {\n\t\t\tif (typeof def === 'object') {\n\t\t\t\t// Add the macro definition.\n\t\t\t\t_macros[name] = deep ? clone(def) : def;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Add the macro alias.\n\t\t\t\tif (macrosHas(def)) {\n\t\t\t\t\t_macros[name] = deep ? clone(_macros[def]) : _macros[def];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new Error(`cannot create alias of nonexistent macro <<${def}>>`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tObject.defineProperty(_macros, name, { writable : false });\n\n\t\t\t/* legacy */\n\t\t\t/*\n\t\t\t\tSince `macrosGet()` may return legacy macros, we have to add a flag to (modern)\n\t\t\t\tAPI macros, so that the macro formatter will know how to call the macro.\n\t\t\t*/\n\t\t\t_macros[name]._MACRO_API = true;\n\t\t\t/* /legacy */\n\t\t}\n\t\tcatch (ex) {\n\t\t\tif (ex.name === 'TypeError') {\n\t\t\t\tthrow new Error(`cannot clobber protected macro <<${name}>>`);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error(`unknown error when attempting to add macro <<${name}>>: [${ex.name}] ${ex.message}`);\n\t\t\t}\n\t\t}\n\n\t\t// Tags post-processing.\n\t\tif (_macros[name].hasOwnProperty('tags')) {\n\t\t\tif (_macros[name].tags == null) { // lazy equality for null\n\t\t\t\ttagsRegister(name);\n\t\t\t}\n\t\t\telse if (Array.isArray(_macros[name].tags)) {\n\t\t\t\ttagsRegister(name, _macros[name].tags);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error(`bad value for \"tags\" property of macro <<${name}>>`);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction macrosDelete(name) {\n\t\tif (Array.isArray(name)) {\n\t\t\tname.forEach(name => macrosDelete(name));\n\t\t\treturn;\n\t\t}\n\n\t\tif (macrosHas(name)) {\n\t\t\t// Tags pre-processing.\n\t\t\tif (_macros[name].hasOwnProperty('tags')) {\n\t\t\t\ttagsUnregister(name);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t// Remove the macro definition.\n\t\t\t\tObject.defineProperty(_macros, name, { writable : true });\n\t\t\t\tdelete _macros[name];\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tthrow new Error(`unknown error removing macro <<${name}>>: ${ex.message}`);\n\t\t\t}\n\t\t}\n\t\telse if (tagsHas(name)) {\n\t\t\tthrow new Error(`cannot remove child tag <<${name}>> of parent macro <<${_tags[name]}>>`);\n\t\t}\n\t}\n\n\tfunction macrosIsEmpty() {\n\t\treturn Object.keys(_macros).length === 0;\n\t}\n\n\tfunction macrosHas(name) {\n\t\treturn _macros.hasOwnProperty(name);\n\t}\n\n\tfunction macrosGet(name) {\n\t\tlet macro = null;\n\n\t\tif (macrosHas(name) && typeof _macros[name].handler === 'function') {\n\t\t\tmacro = _macros[name];\n\t\t}\n\t\t/* legacy macro support */\n\t\telse if (macros.hasOwnProperty(name) && typeof macros[name].handler === 'function') {\n\t\t\tmacro = macros[name];\n\t\t}\n\t\t/* /legacy macro support */\n\n\t\treturn macro;\n\t}\n\n\tfunction macrosInit(handler = 'init') { // eslint-disable-line no-unused-vars\n\t\tObject.keys(_macros).forEach(name => {\n\t\t\tif (typeof _macros[name][handler] === 'function') {\n\t\t\t\t_macros[name][handler](name);\n\t\t\t}\n\t\t});\n\n\t\t/* legacy macro support */\n\t\tObject.keys(macros).forEach(name => {\n\t\t\tif (typeof macros[name][handler] === 'function') {\n\t\t\t\tmacros[name][handler](name);\n\t\t\t}\n\t\t});\n\t\t/* /legacy macro support */\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTags Functions.\n\t*******************************************************************************************************************/\n\tfunction tagsRegister(parent, bodyTags) {\n\t\tif (!parent) {\n\t\t\tthrow new Error('no parent specified');\n\t\t}\n\n\t\tconst endTags = [`/${parent}`, `end${parent}`]; // automatically create the closing tags\n\t\tconst allTags = [].concat(endTags, Array.isArray(bodyTags) ? bodyTags : []);\n\n\t\tfor (let i = 0; i < allTags.length; ++i) {\n\t\t\tconst tag = allTags[i];\n\n\t\t\tif (macrosHas(tag)) {\n\t\t\t\tthrow new Error('cannot register tag for an existing macro');\n\t\t\t}\n\n\t\t\tif (tagsHas(tag)) {\n\t\t\t\tif (!_tags[tag].includes(parent)) {\n\t\t\t\t\t_tags[tag].push(parent);\n\t\t\t\t\t_tags[tag].sort();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_tags[tag] = [parent];\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction tagsUnregister(parent) {\n\t\tif (!parent) {\n\t\t\tthrow new Error('no parent specified');\n\t\t}\n\n\t\tObject.keys(_tags).forEach(tag => {\n\t\t\tconst i = _tags[tag].indexOf(parent);\n\n\t\t\tif (i !== -1) {\n\t\t\t\tif (_tags[tag].length === 1) {\n\t\t\t\t\tdelete _tags[tag];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_tags[tag].splice(i, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction tagsHas(name) {\n\t\treturn _tags.hasOwnProperty(name);\n\t}\n\n\tfunction tagsGet(name) {\n\t\treturn tagsHas(name) ? _tags[name] : null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tMacro Functions.\n\t\t*/\n\t\tadd     : { value : macrosAdd },\n\t\tdelete  : { value : macrosDelete },\n\t\tisEmpty : { value : macrosIsEmpty },\n\t\thas     : { value : macrosHas },\n\t\tget     : { value : macrosGet },\n\t\tinit    : { value : macrosInit },\n\n\t\t/*\n\t\t\tTags Functions.\n\t\t*/\n\t\ttags : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tregister   : { value : tagsRegister },\n\t\t\t\tunregister : { value : tagsUnregister },\n\t\t\t\thas        : { value : tagsHas },\n\t\t\t\tget        : { value : tagsGet }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tevalStatements : { value : (...args) => Scripting.evalJavaScript(...args) } // SEE: `markup/scripting.js`.\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macrocontext.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, DebugView, Patterns, State, Wikifier, throwError */\n\nvar MacroContext = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tMacroContext Class.\n\t*******************************************************************************************************************/\n\tclass MacroContext {\n\t\tconstructor(contextData) {\n\t\t\tconst context = Object.assign({\n\t\t\t\tparent  : null,\n\t\t\t\tmacro   : null,\n\t\t\t\tname    : '',\n\t\t\t\targs    : null,\n\t\t\t\tpayload : null,\n\t\t\t\tparser  : null,\n\t\t\t\tsource  : ''\n\t\t\t}, contextData);\n\n\t\t\tif (context.macro === null || context.name === '' || context.parser === null) {\n\t\t\t\tthrow new TypeError('context object missing required properties');\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tself : {\n\t\t\t\t\tvalue : context.macro\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : context.name\n\t\t\t\t},\n\n\t\t\t\targs : {\n\t\t\t\t\tvalue : context.args\n\t\t\t\t},\n\n\t\t\t\tpayload : {\n\t\t\t\t\tvalue : context.payload\n\t\t\t\t},\n\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : context.source\n\t\t\t\t},\n\n\t\t\t\tparent : {\n\t\t\t\t\tvalue : context.parent\n\t\t\t\t},\n\n\t\t\t\tparser : {\n\t\t\t\t\tvalue : context.parser\n\t\t\t\t},\n\n\t\t\t\t_output : {\n\t\t\t\t\tvalue : context.parser.output\n\t\t\t\t},\n\n\t\t\t\t_shadows : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_debugView : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_debugViewEnabled : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : Config.debug\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tget output() {\n\t\t\treturn this._debugViewEnabled ? this.debugView.output : this._output;\n\t\t}\n\n\t\tget shadows() {\n\t\t\treturn [...this._shadows];\n\t\t}\n\n\t\tget shadowView() {\n\t\t\tconst view = new Set();\n\t\t\tthis.contextSelectAll(ctx => ctx._shadows)\n\t\t\t\t.forEach(ctx => ctx._shadows.forEach(name => view.add(name)));\n\t\t\treturn [...view];\n\t\t}\n\n\t\tget debugView() {\n\t\t\tif (this._debugViewEnabled) {\n\t\t\t\treturn this._debugView !== null ? this._debugView : this.createDebugView();\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tcontextHas(filter) {\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tcontextSelect(filter) {\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\treturn context;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tcontextSelectAll(filter) {\n\t\t\tconst result = [];\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\tresult.push(context);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\taddShadow(...names) {\n\t\t\tif (!this._shadows) {\n\t\t\t\tthis._shadows = new Set();\n\t\t\t}\n\n\t\t\tconst varRe = new RegExp(`^${Patterns.variable}$`);\n\n\t\t\tnames\n\t\t\t\t.flat(Infinity)\n\t\t\t\t.forEach(name => {\n\t\t\t\t\tif (typeof name !== 'string') {\n\t\t\t\t\t\tthrow new TypeError(`variable name must be a string; type: ${typeof name}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!varRe.test(name)) {\n\t\t\t\t\t\tthrow new Error(`invalid variable name \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._shadows.add(name);\n\t\t\t\t});\n\t\t}\n\n\t\tcreateShadowWrapper(callback, doneCallback, startCallback) {\n\t\t\tconst shadowContext = this;\n\t\t\tlet shadowStore;\n\n\t\t\tif (typeof callback === 'function') {\n\t\t\t\tshadowStore = {};\n\t\t\t\tthis.shadowView.forEach(varName => {\n\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\t\t\tshadowStore[varName] = store[varKey];\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn function (...args) {\n\t\t\t\tif (typeof startCallback === 'function') {\n\t\t\t\t\tstartCallback.apply(this, args);\n\t\t\t\t}\n\n\t\t\t\tif (typeof callback === 'function') {\n\t\t\t\t\tconst shadowNames = Object.keys(shadowStore);\n\t\t\t\t\tconst valueCache  = shadowNames.length > 0 ? {} : null;\n\t\t\t\t\tconst macroParser = Wikifier.Parser.get('macro');\n\t\t\t\t\tlet contextCache;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t\tcallback.\n\t\t\t\t\t*/\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tCache the existing values of the variables to be shadowed and assign the\n\t\t\t\t\t\t\tshadow values.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tstore[varKey] = shadowStore[varName];\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Cache the existing macro execution context and assign the shadow context.\n\t\t\t\t\t\tcontextCache = macroParser.context;\n\t\t\t\t\t\tmacroParser.context = shadowContext;\n\n\t\t\t\t\t\t// Call the callback function.\n\t\t\t\t\t\tcallback.apply(this, args);\n\t\t\t\t\t}\n\t\t\t\t\tfinally {\n\t\t\t\t\t\t// Revert the macro execution context shadowing.\n\t\t\t\t\t\tif (contextCache !== undefined) {\n\t\t\t\t\t\t\tmacroParser.context = contextCache;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Revert the variable shadowing.\n\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tUpdate the shadow store with the variable's current value, in case it\n\t\t\t\t\t\t\t\twas modified during the callback.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\n\t\t\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (typeof doneCallback === 'function') {\n\t\t\t\t\tdoneCallback.apply(this, args);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tcreateDebugView(name, title) {\n\t\t\tthis._debugView = new DebugView(\n\t\t\t\tthis._output,\n\t\t\t\t'macro',\n\t\t\t\tname ? name : this.name,\n\t\t\t\ttitle ? title : this.source\n\t\t\t);\n\n\t\t\tif (this.payload !== null && this.payload.length > 0) {\n\t\t\t\tthis._debugView.modes({ nonvoid : true });\n\t\t\t}\n\n\t\t\tthis._debugViewEnabled = true;\n\t\t\treturn this._debugView;\n\t\t}\n\n\t\tremoveDebugView() {\n\t\t\tif (this._debugView !== null) {\n\t\t\t\tthis._debugView.remove();\n\t\t\t\tthis._debugView = null;\n\t\t\t}\n\n\t\t\tthis._debugViewEnabled = false;\n\t\t}\n\n\t\terror(message, source, stack) {\n\t\t\treturn throwError(this._output, `<<${this.name}>>: ${message}`, source ? source : this.source, stack);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn MacroContext;\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macrolib.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, DebugView, Engine, Has, L10n, Macro, Patterns, Scripting, SimpleAudio, State, Story,\n\t       TempState, Util, Wikifier, postdisplay, prehistory, storage, toStringOrDefault\n*/\n\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tVariables Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<capture>>\n\t*/\n\tMacro.add('capture', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tif (this.args.raw.length === 0) {\n\t\t\t\treturn this.error('no story/temporary variable list specified');\n\t\t\t}\n\n\t\t\tconst valueCache = {};\n\n\t\t\t/*\n\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t`Wikifier` call.\n\t\t\t*/\n\t\t\ttry {\n\t\t\t\tconst varRe = new RegExp(`(${Patterns.variable})`,'g');\n\t\t\t\tlet match;\n\n\t\t\t\t/*\n\t\t\t\t\tCache the existing values of the variables and add a shadow.\n\t\t\t\t*/\n\t\t\t\twhile ((match = varRe.exec(this.args.raw)) !== null) {\n\t\t\t\t\tconst varName = match[1];\n\t\t\t\t\tconst varKey  = varName.slice(1);\n\t\t\t\t\tconst store   = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.addShadow(varName);\n\t\t\t\t}\n\n\t\t\t\tnew Wikifier(this.output, this.payload[0].contents);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\t// Revert the variable shadowing.\n\t\t\t\tthis.shadows.forEach(varName => {\n\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<set>>\n\t*/\n\tMacro.add('set', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<unset>>\n\t*/\n\tMacro.add('unset', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no story/temporary variable list specified');\n\t\t\t}\n\n\t\t\tconst re = new RegExp(\n\t\t\t\t`State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})`,\n\t\t\t\t'g'\n\t\t\t);\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst store = State[match[1]];\n\t\t\t\tconst name  = match[2];\n\n\t\t\t\tif (store.hasOwnProperty(name)) {\n\t\t\t\t\tdelete store[name];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<remember>>\n\t*/\n\tMacro.add('remember', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\tconst remember = storage.get('remember') || {};\n\t\t\tconst re       = new RegExp(`State\\\\.variables\\\\.(${Patterns.identifier})`, 'g');\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst name = match[1];\n\t\t\t\tremember[name] = State.variables[name];\n\t\t\t}\n\n\t\t\tif (!storage.set('remember', remember)) {\n\t\t\t\treturn this.error(`unknown error, cannot remember: ${this.args.raw}`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t},\n\n\t\tinit() {\n\t\t\tconst remember = storage.get('remember');\n\n\t\t\tif (remember) {\n\t\t\t\tObject.keys(remember).forEach(name => State.variables[name] = remember[name]);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<forget>>\n\t*/\n\tMacro.add('forget', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no story variable list specified');\n\t\t\t}\n\n\t\t\tconst remember = storage.get('remember');\n\t\t\tconst re       = new RegExp(`State\\\\.variables\\\\.(${Patterns.identifier})`, 'g');\n\t\t\tlet match;\n\t\t\tlet needStore = false;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst name = match[1];\n\n\t\t\t\tif (State.variables.hasOwnProperty(name)) {\n\t\t\t\t\tdelete State.variables[name];\n\t\t\t\t}\n\n\t\t\t\tif (remember && remember.hasOwnProperty(name)) {\n\t\t\t\t\tneedStore = true;\n\t\t\t\t\tdelete remember[name];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (needStore) {\n\t\t\t\tif (Object.keys(remember).length === 0) {\n\t\t\t\t\tif (!storage.delete('remember')) {\n\t\t\t\t\t\treturn this.error('unknown error, cannot update remember store');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (!storage.set('remember', remember)) {\n\t\t\t\t\treturn this.error('unknown error, cannot update remember store');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tScripting Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<run>>\n\t*/\n\tMacro.add('run', 'set'); // add <<run>> as an alias of <<set>>\n\n\t/*\n\t\t<<script>>\n\t*/\n\tMacro.add('script', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tconst output = document.createDocumentFragment();\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.payload[0].contents, output);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.createDebugView();\n\t\t\t}\n\n\t\t\tif (output.hasChildNodes()) {\n\t\t\t\tthis.output.appendChild(output);\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tDisplay Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<include>>\n\t*/\n\tMacro.add('include', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = this.args[0].link;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the passage name.\n\t\t\t\tpassage = this.args[0];\n\t\t\t}\n\n\t\t\tif (!Story.has(passage)) {\n\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tpassage = Story.get(passage);\n\t\t\tlet $el;\n\n\t\t\tif (this.args[1]) {\n\t\t\t\t$el = jQuery(document.createElement(this.args[1]))\n\t\t\t\t\t.addClass(`${passage.domId} macro-${this.name}`)\n\t\t\t\t\t.attr('data-passage', passage.title)\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$el = jQuery(this.output);\n\t\t\t}\n\n\t\t\t$el.wiki(passage.processText());\n\t\t}\n\t});\n\n\t/*\n\t\t<<nobr>>\n\t*/\n\tMacro.add('nobr', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\t/*\n\t\t\t\tWikify the contents, after removing all leading & trailing newlines and compacting\n\t\t\t\tall internal sequences of newlines into single spaces.\n\t\t\t*/\n\t\t\tnew Wikifier(this.output, this.payload[0].contents.replace(/^\\n+|\\n+$/g, '').replace(/\\n+/g, ' '));\n\t\t}\n\t});\n\n\t/*\n\t\t<<print>>, <<=>>, & <<->>\n\t*/\n\tMacro.add(['print', '=', '-'], {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = toStringOrDefault(Scripting.evalJavaScript(this.args.full), null);\n\n\t\t\t\tif (result !== null) {\n\t\t\t\t\tnew Wikifier(this.output, this.name === '-' ? Util.escape(result) : result);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<silently>>\n\t*/\n\tMacro.add('silently', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, this.payload[0].contents.trim());\n\n\t\t\tif (Config.debug) {\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tthis.debugView.modes({ block : true, hidden : true });\n\t\t\t\tthis.output.appendChild(frag);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Discard the output, unless there were errors.\n\t\t\t\tconst errList = [...frag.querySelectorAll('.error')].map(errEl => errEl.textContent);\n\n\t\t\t\tif (errList.length > 0) {\n\t\t\t\t\treturn this.error(`error${errList.length === 1 ? '' : 's'} within contents (${errList.join('; ')})`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] <<display>>\n\t*/\n\tMacro.add('display', 'include'); // add <<display>> as an alias of <<include>>\n\n\n\t/*******************************************************************************************************************\n\t\tControl Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<if>>, <<elseif>>, & <<else>>\n\t*/\n\tMacro.add('if', {\n\t\tskipArgs : true,\n\t\ttags     : ['elseif', 'else'],\n\n\t\thandler() {\n\t\t\tlet i;\n\n\t\t\ttry {\n\t\t\t\tconst len = this.payload.length;\n\n\t\t\t\t// Sanity checks.\n\t\t\t\tfor (/* declared previously */ i = 0; i < len; ++i) {\n\t\t\t\t\t/* eslint-disable prefer-template */\n\t\t\t\t\tswitch (this.payload[i].name) {\n\t\t\t\t\tcase 'else':\n\t\t\t\t\t\tif (this.payload[i].args.raw.length > 0) {\n\t\t\t\t\t\t\tif (/^\\s*if\\b/i.test(this.payload[i].args.raw)) {\n\t\t\t\t\t\t\t\treturn this.error(`whitespace is not allowed between the \"else\" and \"if\" in <<elseif>> clause${i > 0 ? ' (#' + i + ')' : ''}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn this.error(`<<else>> does not accept a conditional expression (perhaps you meant to use <<elseif>>), invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (i + 1 !== len) {\n\t\t\t\t\t\t\treturn this.error('<<else>> must be the final clause');\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif (this.payload[i].args.full.length === 0) {\n\t\t\t\t\t\t\treturn this.error(`no conditional expression specified for <<${this.payload[i].name}>> clause${i > 0 ? ' (#' + i + ')' : ''}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (\n\t\t\t\t\t\t\t   Config.macros.ifAssignmentError\n\t\t\t\t\t\t\t&& /[^!=&^|<>*/%+-]=[^=>]/.test(this.payload[i].args.full)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn this.error(`assignment operator found within <<${this.payload[i].name}>> clause${i > 0 ? ' (#' + i + ')' : ''} (perhaps you meant to use an equality operator: ==, ===, eq, is), invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable prefer-template */\n\t\t\t\t}\n\n\t\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\t\tlet success = false;\n\n\t\t\t\t// Evaluate the clauses.\n\t\t\t\tfor (/* declared previously */ i = 0; i < len; ++i) {\n\t\t\t\t\t// Custom debug view setup for the current clause.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({ nonvoid : false });\n\t\t\t\t\t}\n\n\t\t\t\t\t// Conditional test.\n\t\t\t\t\tif (this.payload[i].name === 'else' || !!evalJavaScript(this.payload[i].args.full)) {\n\t\t\t\t\t\tsuccess = true;\n\t\t\t\t\t\tnew Wikifier(this.output, this.payload[i].contents);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse if (Config.debug) {\n\t\t\t\t\t\t// Custom debug view setup for a failed conditional.\n\t\t\t\t\t\tthis.debugView.modes({\n\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup for the remaining clauses.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tfor (++i; i < len; ++i) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tFake a debug view for `<</if>>`.  We do this to aid the checking of nesting\n\t\t\t\t\t\tand as a quick indicator of if any of the clauses matched.\n\t\t\t\t\t*/\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : !success,\n\t\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad conditional expression in <<${i === 0 ? 'if' : 'elseif'}>> clause${i > 0 ? ' (#' + i + ')' : ''}: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack); // eslint-disable-line prefer-template\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<switch>>, <<case>>, & <<default>>\n\t*/\n\tMacro.add('switch', {\n\t\tskipArgs : ['switch'],\n\t\ttags     : ['case', 'default'],\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\tconst len = this.payload.length;\n\n\t\t\t// if (len === 1 || !this.payload.some(p => p.name === 'case')) {\n\t\t\tif (len === 1) {\n\t\t\t\treturn this.error('no cases specified');\n\t\t\t}\n\n\t\t\tlet i;\n\n\t\t\t// Sanity checks.\n\t\t\tfor (/* declared previously */ i = 1; i < len; ++i) {\n\t\t\t\tswitch (this.payload[i].name) {\n\t\t\t\tcase 'default':\n\t\t\t\t\tif (this.payload[i].args.length > 0) {\n\t\t\t\t\t\treturn this.error(`<<default>> does not accept values, invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (i + 1 !== len) {\n\t\t\t\t\t\treturn this.error('<<default>> must be the final case');\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tif (this.payload[i].args.length === 0) {\n\t\t\t\t\t\treturn this.error(`no value(s) specified for <<${this.payload[i].name}>> (#${i})`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet result;\n\n\t\t\ttry {\n\t\t\t\tresult = Scripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\tconst debugView = this.debugView; // cache it now, to be modified later\n\t\t\tlet success = false;\n\n\t\t\t// Initial debug view setup for `<<switch>>`.\n\t\t\tif (Config.debug) {\n\t\t\t\tdebugView\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true\n\t\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Evaluate the clauses.\n\t\t\tfor (/* declared previously */ i = 1; i < len; ++i) {\n\t\t\t\t// Custom debug view setup for the current case.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t.modes({ nonvoid : false });\n\t\t\t\t}\n\n\t\t\t\t// Case test(s).\n\t\t\t\tif (this.payload[i].name === 'default' || this.payload[i].args.some(val => val === result)) {\n\t\t\t\t\tsuccess = true;\n\t\t\t\t\tnew Wikifier(this.output, this.payload[i].contents);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (Config.debug) {\n\t\t\t\t\t// Custom debug view setup for a failed case.\n\t\t\t\t\tthis.debugView.modes({\n\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup for the remaining cases.\n\t\t\tif (Config.debug) {\n\t\t\t\tfor (++i; i < len; ++i) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t/*\n\t\t\t\t\tFinalize the debug view for `<<switch>>` and fake a debug view for `<</switch>>`.\n\t\t\t\t\tWe do both as a quick indicator of if any of the cases matched and the latter\n\t\t\t\t\tto aid the checking of nesting.\n\t\t\t\t*/\n\t\t\t\tdebugView\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true, // !success,\n\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t});\n\t\t\t\tthis\n\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true, // !success,\n\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<for>>, <<break>>, & <<continue>>\n\t*/\n\tMacro.add('for', {\n\t\t/* eslint-disable max-len */\n\t\tskipArgs    : true,\n\t\ttags        : null,\n\t\t_hasRangeRe : new RegExp(`^\\\\S${Patterns.anyChar}*?\\\\s+range\\\\s+\\\\S${Patterns.anyChar}*?$`),\n\t\t_rangeRe    : new RegExp(`^(?:State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})\\\\s*,\\\\s*)?State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})\\\\s+range\\\\s+(\\\\S${Patterns.anyChar}*?)$`),\n\t\t_3PartRe    : /^([^;]*?)\\s*;\\s*([^;]*?)\\s*;\\s*([^;]*?)$/,\n\t\t/* eslint-enable max-len */\n\n\t\thandler() {\n\t\t\tconst argsStr = this.args.full.trim();\n\t\t\tconst payload = this.payload[0].contents.replace(/\\n$/, '');\n\n\t\t\t// Empty form.\n\t\t\tif (argsStr.length === 0) {\n\t\t\t\tthis.self._handleFor.call(this, payload, null, true, null);\n\t\t\t}\n\n\t\t\t// Range form.\n\t\t\telse if (this.self._hasRangeRe.test(argsStr)) {\n\t\t\t\tconst parts = argsStr.match(this.self._rangeRe);\n\n\t\t\t\tif (parts === null) {\n\t\t\t\t\treturn this.error('invalid range form syntax, format: [index ,] value range collection');\n\t\t\t\t}\n\n\t\t\t\tthis.self._handleForRange.call(\n\t\t\t\t\tthis,\n\t\t\t\t\tpayload,\n\t\t\t\t\t{ type : parts[1], name : parts[2] },\n\t\t\t\t\t{ type : parts[3], name : parts[4] },\n\t\t\t\t\tparts[5]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Conditional forms.\n\t\t\telse {\n\t\t\t\tlet init;\n\t\t\t\tlet condition;\n\t\t\t\tlet post;\n\n\t\t\t\t// Conditional-only form.\n\t\t\t\tif (argsStr.indexOf(';') === -1) {\n\t\t\t\t\t// Sanity checks.\n\t\t\t\t\tif (/^\\S+\\s+in\\s+\\S+/i.test(argsStr)) {\n\t\t\t\t\t\treturn this.error('invalid syntax, for…in is not supported; see: for…range');\n\t\t\t\t\t}\n\t\t\t\t\telse if (/^\\S+\\s+of\\s+\\S+/i.test(argsStr)) {\n\t\t\t\t\t\treturn this.error('invalid syntax, for…of is not supported; see: for…range');\n\t\t\t\t\t}\n\n\t\t\t\t\tcondition = argsStr;\n\t\t\t\t}\n\n\t\t\t\t// 3-part conditional form.\n\t\t\t\telse {\n\t\t\t\t\tconst parts = argsStr.match(this.self._3PartRe);\n\n\t\t\t\t\tif (parts === null) {\n\t\t\t\t\t\treturn this.error('invalid 3-part conditional form syntax, format: [init] ; [condition] ; [post]');\n\t\t\t\t\t}\n\n\t\t\t\t\tinit      = parts[1];\n\t\t\t\t\tcondition = parts[2].trim();\n\t\t\t\t\tpost      = parts[3];\n\n\t\t\t\t\tif (condition.length === 0) {\n\t\t\t\t\t\tcondition = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis.self._handleFor.call(this, payload, init, condition, post);\n\t\t\t}\n\t\t},\n\n\t\t_handleFor(payload, init, condition, post) {\n\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\tlet first  = true;\n\t\t\tlet safety = Config.macros.maxLoopIterations;\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tTempState.break = null;\n\n\t\t\t\tif (init) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tevalJavaScript(init);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn this.error(`bad init expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\twhile (evalJavaScript(condition)) {\n\t\t\t\t\tif (--safety < 0) {\n\t\t\t\t\t\treturn this.error(`exceeded configured maximum loop iterations (${Config.macros.maxLoopIterations})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tnew Wikifier(this.output, first ? payload.replace(/^\\n/, '') : payload);\n\n\t\t\t\t\tif (first) {\n\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tif (TempState.break === 1) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (TempState.break === 2) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (post) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tevalJavaScript(post);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\treturn this.error(`bad post expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad conditional expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tTempState.break = null;\n\t\t\t}\n\t\t},\n\n\t\t_handleForRange(payload, indexVar, valueVar, rangeExp) {\n\t\t\tlet first     = true;\n\t\t\tlet rangeList;\n\n\t\t\ttry {\n\t\t\t\trangeList = this.self._toRangeList(rangeExp);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(ex.message);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tTempState.break = null;\n\n\t\t\t\tfor (let i = 0; i < rangeList.length; ++i) {\n\t\t\t\t\tif (indexVar.name) {\n\t\t\t\t\t\tState[indexVar.type][indexVar.name] = rangeList[i][0];\n\t\t\t\t\t}\n\n\t\t\t\t\tState[valueVar.type][valueVar.name] = rangeList[i][1];\n\n\t\t\t\t\tnew Wikifier(this.output, first ? payload.replace(/^\\n/, '') : payload);\n\n\t\t\t\t\tif (first) {\n\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tif (TempState.break === 1) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (TempState.break === 2) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tTempState.break = null;\n\t\t\t}\n\t\t},\n\n\t\t_toRangeList(rangeExp) {\n\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\tlet value;\n\n\t\t\ttry {\n\t\t\t\t/*\n\t\t\t\t\tNOTE: If the first character is the left curly brace, then we\n\t\t\t\t\tassume that it's part of an object literal and wrap it within\n\t\t\t\t\tparenthesis to ensure that it is not mistaken for a block\n\t\t\t\t\tduring evaluation—which would cause an error.\n\t\t\t\t*/\n\t\t\t\tvalue = evalJavaScript(rangeExp[0] === '{' ? `(${rangeExp})` : rangeExp);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tif (typeof ex !== 'object') {\n\t\t\t\t\tthrow new Error(`bad range expression: ${ex}`);\n\t\t\t\t}\n\n\t\t\t\tex.message = `bad range expression: ${ex.message}`;\n\t\t\t\tthrow ex;\n\t\t\t}\n\n\t\t\tlet list;\n\n\t\t\tswitch (typeof value) {\n\t\t\tcase 'string':\n\t\t\t\tlist = [];\n\t\t\t\tfor (let i = 0; i < value.length; /* empty */) {\n\t\t\t\t\tconst obj = Util.charAndPosAt(value, i);\n\t\t\t\t\tlist.push([i, obj.char]);\n\t\t\t\t\ti = 1 + obj.end;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'object':\n\t\t\t\tif (Array.isArray(value)) {\n\t\t\t\t\tlist = value.map((val, i) => [i, val]);\n\t\t\t\t}\n\t\t\t\telse if (value instanceof Set) {\n\t\t\t\t\tlist = [...value].map((val, i) => [i, val]);\n\t\t\t\t}\n\t\t\t\telse if (value instanceof Map) {\n\t\t\t\t\tlist = [...value.entries()];\n\t\t\t\t}\n\t\t\t\telse if (Util.toStringTag(value) === 'Object') {\n\t\t\t\t\tlist = Object.keys(value).map(key => [key, value[key]]);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new Error(`unsupported range expression type: ${Util.toStringTag(value)}`);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unsupported range expression type: ${typeof value}`);\n\t\t\t}\n\n\t\t\treturn list;\n\t\t}\n\t});\n\tMacro.add(['break', 'continue'], {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.contextHas(ctx => ctx.name === 'for')) {\n\t\t\t\tTempState.break = this.name === 'continue' ? 1 : 2;\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn this.error('must only be used in conjunction with its parent macro <<for>>');\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tInteractive Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<button>> & <<link>>\n\t*/\n\tMacro.add(['button', 'link'], {\n\t\tisAsync : true,\n\t\ttags    : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error(`no ${this.name === 'button' ? 'button' : 'link'} text specified`);\n\t\t\t}\n\n\t\t\tconst $link = jQuery(document.createElement(this.name === 'button' ? 'button' : 'a'));\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\tconst $image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t.attr('src', this.args[0].source)\n\t\t\t\t\t\t.appendTo($link);\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t}\n\n\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t$link.append(document.createTextNode(this.args[0].text));\n\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the link text.\n\t\t\t\t$link.wikiWithOptions({ profile : 'core' }, this.args[0]);\n\t\t\t\tpassage = this.args.length > 1 ? this.args[1] : undefined;\n\t\t\t}\n\n\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t$link.attr('data-passage', passage);\n\n\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t$link.addClass('link-internal');\n\n\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t$link.addClass('link-visited');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$link.addClass('link-broken');\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$link.addClass('link-internal');\n\t\t\t}\n\n\t\t\t$link\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tnamespace : '.macros',\n\t\t\t\t\tone       : passage != null // lazy equality for null\n\t\t\t\t}, this.createShadowWrapper(\n\t\t\t\t\tthis.payload[0].contents !== ''\n\t\t\t\t\t\t? () => Wikifier.wikifyEval(this.payload[0].contents.trim())\n\t\t\t\t\t\t: null,\n\t\t\t\t\tpassage != null // lazy equality for null\n\t\t\t\t\t\t? () => Engine.play(passage)\n\t\t\t\t\t\t: null\n\t\t\t\t))\n\t\t\t\t.appendTo(this.output);\n\t\t}\n\t});\n\n\t/*\n\t\t<<checkbox>>\n\t*/\n\tMacro.add('checkbox', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 3) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('unchecked value'); }\n\t\t\t\tif (this.args.length < 3) { errors.push('checked value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst uncheckValue = this.args[1];\n\t\t\tconst checkValue   = this.args[2];\n\t\t\tconst el           = document.createElement('input');\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'checkbox',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.checked ? checkValue : uncheckValue);\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and input element to the appropriate value and state, as requested.\n\t\t\t*/\n\t\t\tif (this.args.length > 3 && this.args[3] === 'checked') {\n\t\t\t\tel.checked = true;\n\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tState.setVar(varName, uncheckValue);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<cycle>>, <<listbox>>, <<option>>, & <<optionsfrom>>\n\t*/\n\tMacro.add(['cycle', 'listbox'], {\n\t\tisAsync  : true,\n\t\tskipArgs : ['optionsfrom'],\n\t\ttags     : ['option', 'optionsfrom'],\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no variable name specified');\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId = Util.slugify(varName);\n\t\t\tconst len   = this.payload.length;\n\n\t\t\tif (len === 1) {\n\t\t\t\treturn this.error('no options specified');\n\t\t\t}\n\n\t\t\tconst autoselect = this.args.length > 1 && this.args[1] === 'autoselect';\n\t\t\tconst options    = [];\n\t\t\tconst tagCount   = { option : 0, optionsfrom : 0 };\n\t\t\tlet selectedIdx = -1;\n\n\t\t\t// Get the options and selected index, if any.\n\t\t\tfor (let i = 1; i < len; ++i) {\n\t\t\t\tconst payload = this.payload[i];\n\n\t\t\t\t// <<option label value [selected]>>\n\t\t\t\tif (payload.name === 'option') {\n\t\t\t\t\t++tagCount.option;\n\n\t\t\t\t\tif (payload.args.length === 0) {\n\t\t\t\t\t\treturn this.error(`no arguments specified for <<${payload.name}>> (#${tagCount.option})`);\n\t\t\t\t\t}\n\n\t\t\t\t\toptions.push({\n\t\t\t\t\t\tlabel : String(payload.args[0]),\n\t\t\t\t\t\tvalue : payload.args.length === 1 ? payload.args[0] : payload.args[1]\n\t\t\t\t\t});\n\n\t\t\t\t\tif (payload.args.length > 2 && payload.args[2] === 'selected') {\n\t\t\t\t\t\tif (autoselect) {\n\t\t\t\t\t\t\treturn this.error('cannot specify both the autoselect and selected keywords');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (selectedIdx !== -1) {\n\t\t\t\t\t\t\treturn this.error(`multiple selected keywords specified for <<${payload.name}>> (#${selectedIdx + 1} & #${tagCount.option})`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tselectedIdx = options.length - 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// <<optionsfrom expression>>\n\t\t\t\telse {\n\t\t\t\t\t++tagCount.optionsfrom;\n\n\t\t\t\t\tif (payload.args.full.length === 0) {\n\t\t\t\t\t\treturn this.error(`no expression specified for <<${payload.name}>> (#${tagCount.optionsfrom})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: If the first character is the left curly brace, then we\n\t\t\t\t\t\t\tassume that it's part of an object literal and wrap it within\n\t\t\t\t\t\t\tparenthesis to ensure that it is not mistaken for a block\n\t\t\t\t\t\t\tduring evaluation—which would cause an error.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tconst exp = payload.args.full;\n\t\t\t\t\t\tresult = Scripting.evalJavaScript(exp[0] === '{' ? `(${exp})` : exp);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (typeof result !== 'object' || result === null) {\n\t\t\t\t\t\treturn this.error(`expression must yield a supported collection or generic object (type: ${result === null ? 'null' : typeof result})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (result instanceof Array || result instanceof Set) {\n\t\t\t\t\t\tresult.forEach(val => options.push({ label : String(val), value : val }));\n\t\t\t\t\t}\n\t\t\t\t\telse if (result instanceof Map) {\n\t\t\t\t\t\tresult.forEach((val, key) => options.push({ label : String(key), value : val }));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tconst oType = Util.toStringTag(result);\n\n\t\t\t\t\t\tif (oType !== 'Object') {\n\t\t\t\t\t\t\treturn this.error(`expression must yield a supported collection or generic object (object type: ${oType})`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tObject.keys(result).forEach(key => options.push({ label : key, value : result[key] }));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// No options were selected by the user, so we must select one.\n\t\t\tif (selectedIdx === -1) {\n\t\t\t\t// Attempt to automatically select an option by matching the variable's current value.\n\t\t\t\tif (autoselect) {\n\t\t\t\t\t// NOTE: This will usually fail for objects due to a variety of reasons.\n\t\t\t\t\tconst sameValueZero = Util.sameValueZero;\n\t\t\t\t\tconst curValue      = State.getVar(varName);\n\t\t\t\t\tconst curValueIdx   = options.findIndex(opt => sameValueZero(opt.value, curValue));\n\t\t\t\t\tselectedIdx = curValueIdx === -1 ? 0 : curValueIdx;\n\t\t\t\t}\n\n\t\t\t\t// Simply select the first option.\n\t\t\t\telse {\n\t\t\t\t\tselectedIdx = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set up and append the appropriate element to the output buffer.\n\t\t\tif (this.name === 'cycle') {\n\t\t\t\tlet cycleIdx = selectedIdx;\n\t\t\t\tjQuery(document.createElement('a'))\n\t\t\t\t\t.wikiWithOptions({ profile : 'core' }, options[selectedIdx].label)\n\t\t\t\t\t.attr('id', `${this.name}-${varId}`)\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.ariaClick({ namespace : '.macros' }, this.createShadowWrapper(function () {\n\t\t\t\t\t\tcycleIdx = (cycleIdx + 1) % options.length;\n\t\t\t\t\t\t$(this).empty().wikiWithOptions({ profile : 'core' }, options[cycleIdx].label);\n\t\t\t\t\t\tState.setVar(varName, options[cycleIdx].value);\n\t\t\t\t\t}))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\t\t\telse { // this.name === 'listbox'\n\t\t\t\tconst $select = jQuery(document.createElement('select'));\n\n\t\t\t\toptions.forEach((opt, i) => {\n\t\t\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t\t\t.val(i)\n\t\t\t\t\t\t.text(opt.label)\n\t\t\t\t\t\t.appendTo($select);\n\t\t\t\t});\n\n\t\t\t\t$select\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t\t})\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.val(selectedIdx)\n\t\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\t\tState.setVar(varName, options[Number(this.value)].value);\n\t\t\t\t\t}))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\n\t\t\t// Set the variable to the appropriate value, as requested.\n\t\t\tState.setVar(varName, options[selectedIdx].value);\n\t\t}\n\t});\n\n\t/*\n\t\t<<linkappend>>, <<linkprepend>>, & <<linkreplace>>\n\t*/\n\tMacro.add(['linkappend', 'linkprepend', 'linkreplace'], {\n\t\tisAsync : true,\n\t\ttags    : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no link text specified');\n\t\t\t}\n\n\t\t\tconst $link      = jQuery(document.createElement('a'));\n\t\t\tconst $insert    = jQuery(document.createElement('span'));\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\n\t\t\t$link\n\t\t\t\t.wikiWithOptions({ profile : 'core' }, this.args[0])\n\t\t\t\t.addClass(`link-internal macro-${this.name}`)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tnamespace : '.macros',\n\t\t\t\t\tone       : true\n\t\t\t\t}, this.createShadowWrapper(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tif (this.name === 'linkreplace') {\n\t\t\t\t\t\t\t$link.remove();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t$link\n\t\t\t\t\t\t\t\t.wrap(`<span class=\"macro-${this.name}\"></span>`)\n\t\t\t\t\t\t\t\t.replaceWith(() => $link.html());\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.payload[0].contents !== '') {\n\t\t\t\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\t\t\t\tnew Wikifier(frag, this.payload[0].contents);\n\t\t\t\t\t\t\t$insert.append(frag);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (transition) {\n\t\t\t\t\t\t\tsetTimeout(() => $insert.removeClass(`macro-${this.name}-in`), Engine.minDomActionDelay);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t$insert.addClass(`macro-${this.name}-insert`);\n\n\t\t\tif (transition) {\n\t\t\t\t$insert.addClass(`macro-${this.name}-in`);\n\t\t\t}\n\n\t\t\tif (this.name === 'linkprepend') {\n\t\t\t\t$insert.insertBefore($link);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$insert.insertAfter($link);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<radiobutton>>\n\t*/\n\tMacro.add('radiobutton', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('checked value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId      = Util.slugify(varName);\n\t\t\tconst checkValue = this.args[1];\n\t\t\tconst el         = document.createElement('input');\n\n\t\t\t/*\n\t\t\t\tSet up and initialize the group counter.\n\t\t\t*/\n\t\t\tif (!TempState.hasOwnProperty(this.name)) {\n\t\t\t\tTempState[this.name] = {};\n\t\t\t}\n\n\t\t\tif (!TempState[this.name].hasOwnProperty(varId)) {\n\t\t\t\tTempState[this.name][varId] = 0;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}-${TempState[this.name][varId]++}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'radio',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tif (this.checked) {\n\t\t\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable to the checked value and the input element to checked, if requested.\n\t\t\t*/\n\t\t\tif (this.args.length > 2 && this.args[2] === 'checked') {\n\t\t\t\tel.checked = true;\n\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<textarea>>\n\t*/\n\tMacro.add('textarea', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('default value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst defaultValue = this.args[1];\n\t\t\tconst autofocus    = this.args[2] === 'autofocus';\n\t\t\tconst el           = document.createElement('textarea');\n\n\t\t\t/*\n\t\t\t\tSet up and append the textarea element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\trows     : 4,\n\t\t\t\t\t// cols     : 68, // instead of setting \"cols\" we set the `min-width` in CSS\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.value);\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and textarea element to the default value.\n\t\t\t*/\n\t\t\tState.setVar(varName, defaultValue);\n\t\t\t// Ideally, we should be setting `.defaultValue` here, but IE doesn't support it,\n\t\t\t// so we have to use `.textContent`, which is equivalent.\n\t\t\tel.textContent = defaultValue;\n\n\t\t\t/*\n\t\t\t\tAutofocus the textarea element, if requested.\n\t\t\t*/\n\t\t\tif (autofocus) {\n\t\t\t\t// Set the element's \"autofocus\" attribute.\n\t\t\t\tel.setAttribute('autofocus', 'autofocus');\n\n\t\t\t\t// Set up a single-use post-display task to autofocus the element.\n\t\t\t\tpostdisplay[`#autofocus:${el.id}`] = task => {\n\t\t\t\t\tdelete postdisplay[task]; // single-use task\n\t\t\t\t\tsetTimeout(() => el.focus(), Engine.minDomActionDelay);\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<textbox>>\n\t*/\n\tMacro.add('textbox', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('default value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst defaultValue = this.args[1];\n\t\t\tconst el           = document.createElement('input');\n\t\t\tlet autofocus = false;\n\t\t\tlet passage;\n\n\t\t\tif (this.args.length > 3) {\n\t\t\t\tpassage   = this.args[2];\n\t\t\t\tautofocus = this.args[3] === 'autofocus';\n\t\t\t}\n\t\t\telse if (this.args.length > 2) {\n\t\t\t\tif (this.args[2] === 'autofocus') {\n\t\t\t\t\tautofocus = true;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tpassage = this.args[2];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (typeof passage === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = passage.link;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'text',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.value);\n\t\t\t\t}))\n\t\t\t\t.on('keypress.macros', this.createShadowWrapper(function (ev) {\n\t\t\t\t\t// If Return/Enter is pressed, set the variable and, optionally, forward to another passage.\n\t\t\t\t\tif (ev.which === 13) { // 13 is Return/Enter\n\t\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t\tState.setVar(varName, this.value);\n\n\t\t\t\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and input element to the default value.\n\t\t\t*/\n\t\t\tState.setVar(varName, defaultValue);\n\t\t\tel.value = defaultValue;\n\n\t\t\t/*\n\t\t\t\tAutofocus the input element, if requested.\n\t\t\t*/\n\t\t\tif (autofocus) {\n\t\t\t\t// Set the element's \"autofocus\" attribute.\n\t\t\t\tel.setAttribute('autofocus', 'autofocus');\n\n\t\t\t\t// Set up a single-use post-display task to autofocus the element.\n\t\t\t\tpostdisplay[`#autofocus:${el.id}`] = task => {\n\t\t\t\t\tdelete postdisplay[task]; // single-use task\n\t\t\t\t\tsetTimeout(() => el.focus(), Engine.minDomActionDelay);\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] <<click>>\n\t*/\n\tMacro.add('click', 'link'); // add <<click>> as an alias of <<link>>\n\n\n\t/*******************************************************************************************************************\n\t\tLinks Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<actions>>\n\t*/\n\tMacro.add('actions', {\n\t\thandler() {\n\t\t\tconst $list = jQuery(document.createElement('ul'))\n\t\t\t\t.addClass(this.name)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\tfor (let i = 0; i < this.args.length; ++i) {\n\t\t\t\tlet passage;\n\t\t\t\tlet text;\n\t\t\t\tlet $image;\n\t\t\t\tlet setFn;\n\n\t\t\t\tif (typeof this.args[i] === 'object') {\n\t\t\t\t\tif (this.args[i].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[i].source);\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[i].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[i].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[i].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tpassage = this.args[i].link;\n\t\t\t\t\t\tsetFn   = this.args[i].setFn;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\ttext    = this.args[i].text;\n\t\t\t\t\t\tpassage = this.args[i].link;\n\t\t\t\t\t\tsetFn   = this.args[i].setFn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\ttext = passage = this.args[i];\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\t   State.variables.hasOwnProperty('#actions')\n\t\t\t\t\t&& State.variables['#actions'].hasOwnProperty(passage)\n\t\t\t\t\t&& State.variables['#actions'][passage]\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tjQuery(Wikifier.createInternalLink(\n\t\t\t\t\tjQuery(document.createElement('li')).appendTo($list),\n\t\t\t\t\tpassage,\n\t\t\t\t\tnull,\n\t\t\t\t\t((passage, fn) => () => {\n\t\t\t\t\t\tif (!State.variables.hasOwnProperty('#actions')) {\n\t\t\t\t\t\t\tState.variables['#actions'] = {};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tState.variables['#actions'][passage] = true;\n\n\t\t\t\t\t\tif (typeof fn === 'function') {\n\t\t\t\t\t\t\tfn();\n\t\t\t\t\t\t}\n\t\t\t\t\t})(passage, setFn)\n\t\t\t\t))\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.append($image || document.createTextNode(text));\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<back>> & <<return>>\n\t*/\n\tMacro.add(['back', 'return'], {\n\t\thandler() {\n\t\t\t/* legacy */\n\t\t\tif (this.args.length > 1) {\n\t\t\t\treturn this.error('too many arguments specified, check the documentation for details');\n\t\t\t}\n\t\t\t/* /legacy */\n\n\t\t\tlet momentIndex = -1;\n\t\t\tlet passage;\n\t\t\tlet text;\n\t\t\tlet $image;\n\n\t\t\tif (this.args.length === 1) {\n\t\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[0].source);\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('link')) {\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\tif (this.args[0].count === 1) {\n\t\t\t\t\t\t\t// Simple link syntax: `[[...]]`.\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Pretty link syntax: `[[...|...]]`.\n\t\t\t\t\t\t\ttext    = this.args[0].text;\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (this.args.length === 1) {\n\t\t\t\t\t// Argument was simply the link text.\n\t\t\t\t\ttext = this.args[0];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\t/*\n\t\t\t\t\tFind the index and title of the most recent moment whose title does not match\n\t\t\t\t\tthat of the active (present) moment's.\n\t\t\t\t*/\n\t\t\t\tfor (let i = State.length - 2; i >= 0; --i) {\n\t\t\t\t\tif (State.history[i].title !== State.passage) {\n\t\t\t\t\t\tmomentIndex = i;\n\t\t\t\t\t\tpassage = State.history[i].title;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If we failed to find a passage and we're `<<return>>`, fallback to `State.expired`.\n\t\t\t\tif (passage == null && this.name === 'return') { // lazy equality for null\n\t\t\t\t\tfor (let i = State.expired.length - 1; i >= 0; --i) {\n\t\t\t\t\t\tif (State.expired[i] !== State.passage) {\n\t\t\t\t\t\t\tpassage = State.expired[i];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (!Story.has(passage)) {\n\t\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tif (this.name === 'back') {\n\t\t\t\t\t/*\n\t\t\t\t\t\tFind the index of the most recent moment whose title matches that of the\n\t\t\t\t\t\tspecified passage.\n\t\t\t\t\t*/\n\t\t\t\t\tfor (let i = State.length - 2; i >= 0; --i) {\n\t\t\t\t\t\tif (State.history[i].title === passage) {\n\t\t\t\t\t\t\tmomentIndex = i;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (momentIndex === -1) {\n\t\t\t\t\t\treturn this.error(`cannot find passage \"${passage}\" in the current story history`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn this.error('cannot find passage');\n\t\t\t}\n\n\t\t\t// if (this.name === \"back\" && momentIndex === -1) {\n\t\t\t// \t// no-op; we're already at the first passage in the current story history\n\t\t\t// \treturn;\n\t\t\t// }\n\n\t\t\tlet $el;\n\n\t\t\tif (this.name !== 'back' || momentIndex !== -1) {\n\t\t\t\t$el = jQuery(document.createElement('a'))\n\t\t\t\t\t.addClass('link-internal')\n\t\t\t\t\t.ariaClick(\n\t\t\t\t\t\t{ one : true },\n\t\t\t\t\t\tthis.name === 'return'\n\t\t\t\t\t\t\t? () => Engine.play(passage)\n\t\t\t\t\t\t\t: () => Engine.goTo(momentIndex)\n\t\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$el = jQuery(document.createElement('span'))\n\t\t\t\t\t.addClass('link-disabled');\n\t\t\t}\n\n\t\t\t$el\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.append($image || document.createTextNode(text || L10n.get(`macro${this.name.toUpperFirst()}Text`)))\n\t\t\t\t.appendTo(this.output);\n\t\t}\n\t});\n\n\t/*\n\t\t<<choice>>\n\t*/\n\tMacro.add('choice', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tconst choiceId = State.passage;\n\t\t\tlet passage;\n\t\t\tlet text;\n\t\t\tlet $image;\n\t\t\tlet setFn;\n\n\t\t\tif (this.args.length === 1) {\n\t\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[0].source);\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\tsetFn   = this.args[0].setFn;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\ttext    = this.args[0].text;\n\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\tsetFn   = this.args[0].setFn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\ttext = passage = this.args[0];\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// NOTE: The arguments here are backwards.\n\t\t\t\tpassage = this.args[0];\n\t\t\t\ttext    = this.args[1];\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t   State.variables.hasOwnProperty('#choice')\n\t\t\t\t&& State.variables['#choice'].hasOwnProperty(choiceId)\n\t\t\t\t&& State.variables['#choice'][choiceId]\n\t\t\t) {\n\t\t\t\tjQuery(document.createElement('span'))\n\t\t\t\t\t.addClass(`link-disabled macro-${this.name}`)\n\t\t\t\t\t.attr('tabindex', -1)\n\t\t\t\t\t.append($image || document.createTextNode(text))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tjQuery(Wikifier.createInternalLink(this.output, passage, null, () => {\n\t\t\t\tif (!State.variables.hasOwnProperty('#choice')) {\n\t\t\t\t\tState.variables['#choice'] = {};\n\t\t\t\t}\n\n\t\t\t\tState.variables['#choice'][choiceId] = true;\n\n\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\tsetFn();\n\t\t\t\t}\n\t\t\t}))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.append($image || document.createTextNode(text));\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tDOM Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<addclass>> & <<toggleclass>>\n\t*/\n\tMacro.add(['addclass', 'toggleclass'], {\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('selector'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('class names'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tswitch (this.name) {\n\t\t\tcase 'addclass':\n\t\t\t\t$targets.addClass(this.args[1].trim());\n\t\t\t\tbreak;\n\n\t\t\tcase 'toggleclass':\n\t\t\t\t$targets.toggleClass(this.args[1].trim());\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<removeclass>>\n\t*/\n\tMacro.add('removeclass', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tif (this.args.length > 1) {\n\t\t\t\t$targets.removeClass(this.args[1].trim());\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$targets.removeClass();\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<copy>>\n\t*/\n\tMacro.add('copy', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tjQuery(this.output).append($targets.html());\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<append>>, <<prepend>>, & <<replace>>\n\t*/\n\tMacro.add(['append', 'prepend', 'replace'], {\n\t\ttags : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tif (this.payload[0].contents !== '') {\n\t\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\t\tlet $insert;\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$insert = jQuery(document.createElement('span'));\n\t\t\t\t\t$insert.addClass(`macro-${this.name}-insert macro-${this.name}-in`);\n\t\t\t\t\tsetTimeout(() => $insert.removeClass(`macro-${this.name}-in`), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$insert = jQuery(document.createDocumentFragment());\n\t\t\t\t}\n\n\t\t\t\t$insert.wiki(this.payload[0].contents);\n\n\t\t\t\tswitch (this.name) {\n\t\t\t\tcase 'replace':\n\t\t\t\t\t$targets.empty();\n\t\t\t\t\t/* falls through */\n\n\t\t\t\tcase 'append':\n\t\t\t\t\t$targets.append($insert);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'prepend':\n\t\t\t\t\t$targets.prepend($insert);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (this.name === 'replace') {\n\t\t\t\t$targets.empty();\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<remove>>\n\t*/\n\tMacro.add('remove', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\t$targets.remove();\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAudio Macros.\n\t*******************************************************************************************************************/\n\tif (Has.audio) {\n\t\tconst errorOnePlaybackAction = (cur, prev) => `only one playback action allowed per invocation, \"${cur}\" cannot be combined with \"${prev}\"`;\n\n\t\t/*\n\t\t\t<<audio>>\n\t\t*/\n\t\tMacro.add('audio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\tconst errors = [];\n\t\t\t\t\tif (this.args.length < 1) { errors.push('track and/or group IDs'); }\n\t\t\t\t\tif (this.args.length < 2) { errors.push('actions'); }\n\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t}\n\n\t\t\t\tlet selected;\n\n\t\t\t\t// Process the track and/or group IDs.\n\t\t\t\ttry {\n\t\t\t\t\tselected = SimpleAudio.select(this.args[0]);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\tconst args = this.args.slice(1);\n\t\t\t\tlet action;\n\t\t\t\tlet fadeOver = 5;\n\t\t\t\tlet fadeTo;\n\t\t\t\tlet loop;\n\t\t\t\tlet mute;\n\t\t\t\tlet passage;\n\t\t\t\tlet time;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\tcase 'play':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadein':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 1;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeout':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 0;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('fadeto missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeoverto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length < 2) {\n\t\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\t\tif (args.length < 1) { errors.push('seconds'); }\n\t\t\t\t\t\t\tif (args.length < 2) { errors.push('level'); }\n\t\t\t\t\t\t\treturn this.error(`fadeoverto missing required ${errors.join(' and ')} value${errors.length > 1 ? 's' : ''}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeOver = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeOver) || !Number.isFinite(fadeOver)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'time':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('time missing required seconds value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\ttime = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(time) || !Number.isFinite(time)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse time: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'loop':\n\t\t\t\t\tcase 'unloop':\n\t\t\t\t\t\tloop = arg === 'loop';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'goto':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('goto missing required passage title');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\n\t\t\t\t\t\tif (typeof raw === 'object') {\n\t\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\t\tpassage = raw.link;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\t\t\tpassage = raw;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!Story.has(passage)) {\n\t\t\t\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tselected.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (time != null) { // lazy equality for null\n\t\t\t\t\t\tselected.time(time);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tselected.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (loop != null) { // lazy equality for null\n\t\t\t\t\t\tselected.loop(loop);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t\t\tconst nsEnded = `ended.macros.macro-${this.name}_goto`;\n\t\t\t\t\t\tselected\n\t\t\t\t\t\t\t.off(nsEnded)\n\t\t\t\t\t\t\t.one(nsEnded, () => {\n\t\t\t\t\t\t\t\tselected.off(nsEnded);\n\t\t\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'fade':\n\t\t\t\t\t\tselected.fade(fadeOver, fadeTo);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tselected.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\t\tselected.pause();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'play':\n\t\t\t\t\t\tselected.playWhenAllowed();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tselected.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tselected.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<cacheaudio track_id source_list>>\n\t\t*/\n\t\tMacro.add('cacheaudio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\tconst errors = [];\n\t\t\t\t\tif (this.args.length < 1) { errors.push('track ID'); }\n\t\t\t\t\tif (this.args.length < 2) { errors.push('sources'); }\n\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t}\n\n\t\t\t\tconst id       = String(this.args[0]).trim();\n\t\t\t\tconst oldFmtRe = /^format:\\s*([\\w-]+)\\s*;\\s*/i;\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.tracks.add(id, this.args.slice(1).map(source => {\n\t\t\t\t\t\t/* legacy */\n\t\t\t\t\t\t// Transform an old format specifier into the new style.\n\t\t\t\t\t\tif (oldFmtRe.test(source)) {\n\t\t\t\t\t\t\t// If in Test Mode, return an error.\n\t\t\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\t\t\treturn this.error(`track ID \"${id}\": format specifier migration required, \"format:formatId;\" \\u2192 \"formatId|\"`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tsource = source.replace(oldFmtRe, '$1|'); // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn source;\n\t\t\t\t\t\t/* /legacy */\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// If in Test Mode and no supported sources were specified, return an error.\n\t\t\t\tif (Config.debug && !SimpleAudio.tracks.get(id).hasSource()) {\n\t\t\t\t\treturn this.error(`track ID \"${id}\": no supported audio sources found`);\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<createaudiogroup group_id>>\n\t\t\t\t<<track track_id>>\n\t\t\t\t…\n\t\t\t<</createaudiogroup>>\n\t\t*/\n\t\tMacro.add('createaudiogroup', {\n\t\t\ttags : ['track'],\n\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no group ID specified');\n\t\t\t\t}\n\n\t\t\t\tif (this.payload.length === 1) {\n\t\t\t\t\treturn this.error('no tracks defined via <<track>>');\n\t\t\t\t}\n\n\t\t\t\t// Initial debug view setup for `<<createaudiogroup>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst groupId  = String(this.args[0]).trim();\n\t\t\t\tconst trackIds = [];\n\n\t\t\t\tfor (let i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\tif (this.payload[i].args.length < 1) {\n\t\t\t\t\t\treturn this.error('no track ID specified');\n\t\t\t\t\t}\n\n\t\t\t\t\ttrackIds.push(String(this.payload[i].args[0]).trim());\n\n\t\t\t\t\t// Custom debug view setup for the current `<<track>>`.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.groups.add(groupId, trackIds);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Custom fake debug view setup for `<</createaudiogroup>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<createplaylist list_id>>\n\t\t\t\t<<track track_id action_list>>\n\t\t\t\t…\n\t\t\t<</createplaylist>>\n\t\t*/\n\t\tMacro.add('createplaylist', {\n\t\t\ttags : ['track'],\n\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no list ID specified');\n\t\t\t\t}\n\n\t\t\t\tif (this.payload.length === 1) {\n\t\t\t\t\treturn this.error('no tracks defined via <<track>>');\n\t\t\t\t}\n\n\t\t\t\tconst playlist = Macro.get('playlist');\n\n\t\t\t\tif (playlist.from !== null && playlist.from !== 'createplaylist') {\n\t\t\t\t\treturn this.error('a playlist has already been defined with <<setplaylist>>');\n\t\t\t\t}\n\n\t\t\t\t// Initial debug view setup for `<<createplaylist>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst listId    = String(this.args[0]).trim();\n\t\t\t\tconst trackObjs = [];\n\n\t\t\t\tfor (let i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\tif (this.payload[i].args.length === 0) {\n\t\t\t\t\t\treturn this.error('no track ID specified');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst trackObj = { id : String(this.payload[i].args[0]).trim() };\n\t\t\t\t\tconst args     = this.payload[i].args.slice(1);\n\n\t\t\t\t\t// Process arguments.\n\t\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\t\tlet raw;\n\t\t\t\t\t\tlet parsed;\n\n\t\t\t\t\t\tswitch (arg) {\n\t\t\t\t\t\tcase 'copy': // [DEPRECATED]\n\t\t\t\t\t\tcase 'own':\n\t\t\t\t\t\t\ttrackObj.own = true;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'rate':\n\t\t\t\t\t\t\t// if (args.length === 0) {\n\t\t\t\t\t\t\t// \treturn this.error('rate missing required speed value');\n\t\t\t\t\t\t\t// }\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// raw = args.shift();\n\t\t\t\t\t\t\t// parsed = Number.parseFloat(raw);\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// if (Number.isNaN(parsed) || !Number.isFinite(parsed)) {\n\t\t\t\t\t\t\t// \treturn this.error(`cannot parse rate: ${raw}`);\n\t\t\t\t\t\t\t// }\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// trackObj.rate = parsed;\n\t\t\t\t\t\t\tif (args.length > 0) {\n\t\t\t\t\t\t\t\targs.shift();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\t\tparsed = Number.parseFloat(raw);\n\n\t\t\t\t\t\t\tif (Number.isNaN(parsed) || !Number.isFinite(parsed)) {\n\t\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ttrackObj.volume = parsed;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\ttrackObjs.push(trackObj);\n\n\t\t\t\t\t// Custom debug view setup for the current `<<track>>`.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.lists.add(listId, trackObjs);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Lock `<<playlist>>` into our syntax.\n\t\t\t\tif (playlist.from === null) {\n\t\t\t\t\tplaylist.from = 'createplaylist';\n\t\t\t\t}\n\n\t\t\t\t// Custom fake debug view setup for `<</createplaylist>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<masteraudio action_list>>\n\t\t*/\n\t\tMacro.add('masteraudio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no actions specified');\n\t\t\t\t}\n\n\t\t\t\tconst args = this.args.slice(0);\n\t\t\t\tlet action;\n\t\t\t\tlet mute;\n\t\t\t\tlet muteOnHide;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'muteonhide':\n\t\t\t\t\tcase 'nomuteonhide':\n\t\t\t\t\t\tmuteOnHide = arg === 'muteonhide';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (muteOnHide != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.muteOnHidden(muteOnHide);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tSimpleAudio.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tSimpleAudio.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tSimpleAudio.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<playlist list_id action_list>>  ← <<createplaylist>> syntax\n\t\t\t<<playlist action_list>>          ← <<setplaylist>> syntax\n\t\t*/\n\t\tMacro.add('playlist', {\n\t\t\tfrom : null,\n\n\t\t\thandler() {\n\t\t\t\tconst from = this.self.from;\n\n\t\t\t\tif (from === null) {\n\t\t\t\t\treturn this.error('no playlists have been created');\n\t\t\t\t}\n\n\t\t\t\tlet list;\n\t\t\t\tlet args;\n\n\t\t\t\tif (from === 'createplaylist') {\n\t\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\tif (this.args.length < 1) { errors.push('list ID'); }\n\t\t\t\t\t\tif (this.args.length < 2) { errors.push('actions'); }\n\t\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\t\tif (!SimpleAudio.lists.has(id)) {\n\t\t\t\t\t\treturn this.error(`playlist \"${id}\" does not exist`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlist = SimpleAudio.lists.get(id);\n\t\t\t\t\targs = this.args.slice(1);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\t\treturn this.error('no actions specified');\n\t\t\t\t\t}\n\n\t\t\t\t\tlist = SimpleAudio.lists.get('setplaylist');\n\t\t\t\t\targs = this.args.slice(0);\n\t\t\t\t}\n\n\t\t\t\tlet action;\n\t\t\t\tlet fadeOver = 5;\n\t\t\t\tlet fadeTo;\n\t\t\t\tlet loop;\n\t\t\t\tlet mute;\n\t\t\t\tlet shuffle;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\tcase 'play':\n\t\t\t\t\tcase 'skip':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadein':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 1;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeout':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 0;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('fadeto missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeoverto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length < 2) {\n\t\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\t\tif (args.length < 1) { errors.push('seconds'); }\n\t\t\t\t\t\t\tif (args.length < 2) { errors.push('level'); }\n\t\t\t\t\t\t\treturn this.error(`fadeoverto missing required ${errors.join(' and ')} value${errors.length > 1 ? 's' : ''}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeOver = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeOver) || !Number.isFinite(fadeOver)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'loop':\n\t\t\t\t\tcase 'unloop':\n\t\t\t\t\t\tloop = arg === 'loop';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'shuffle':\n\t\t\t\t\tcase 'unshuffle':\n\t\t\t\t\t\tshuffle = arg === 'shuffle';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tlist.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tlist.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (loop != null) { // lazy equality for null\n\t\t\t\t\t\tlist.loop(loop);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (shuffle != null) { // lazy equality for null\n\t\t\t\t\t\tlist.shuffle(shuffle);\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'fade':\n\t\t\t\t\t\tlist.fade(fadeOver, fadeTo);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tlist.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\t\tlist.pause();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'play':\n\t\t\t\t\t\tlist.playWhenAllowed();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'skip':\n\t\t\t\t\t\tlist.skip();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tlist.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tlist.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<removeaudiogroup group_id>>\n\t\t*/\n\t\tMacro.add('removeaudiogroup', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no group ID specified');\n\t\t\t\t}\n\n\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\tif (!SimpleAudio.groups.has(id)) {\n\t\t\t\t\treturn this.error(`group \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tSimpleAudio.groups.delete(id);\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<removeplaylist list_id>>\n\t\t*/\n\t\tMacro.add('removeplaylist', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no list ID specified');\n\t\t\t\t}\n\n\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\tif (!SimpleAudio.lists.has(id)) {\n\t\t\t\t\treturn this.error(`playlist \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tSimpleAudio.lists.delete(id);\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<waitforaudio>>\n\t\t*/\n\t\tMacro.add('waitforaudio', {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\tSimpleAudio.loadWithScreen();\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t[DEPRECATED] <<setplaylist track_id_list>>\n\t\t*/\n\t\tMacro.add('setplaylist', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no track ID(s) specified');\n\t\t\t\t}\n\n\t\t\t\tconst playlist = Macro.get('playlist');\n\n\t\t\t\tif (playlist.from !== null && playlist.from !== 'setplaylist') {\n\t\t\t\t\treturn this.error('playlists have already been defined with <<createplaylist>>');\n\t\t\t\t}\n\n\t\t\t\t// Create the new playlist.\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.lists.add('setplaylist', this.args.slice(0));\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Lock `<<playlist>>` into our syntax.\n\t\t\t\tif (playlist.from === null) {\n\t\t\t\t\tplaylist.from = 'setplaylist';\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t[DEPRECATED] <<stopallaudio>>\n\t\t*/\n\t\tMacro.add('stopallaudio', {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\tSimpleAudio.select(':all').stop();\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\telse {\n\t\t/* The HTML5 <audio> API appears to be missing or disabled, set up no-op macros. */\n\t\tMacro.add([\n\t\t\t'audio',\n\t\t\t'cacheaudio',\n\t\t\t'createaudiogroup',\n\t\t\t'createplaylist',\n\t\t\t'masteraudio',\n\t\t\t'playlist',\n\t\t\t'removeaudiogroup',\n\t\t\t'removeplaylist',\n\t\t\t'waitforaudio',\n\n\t\t\t// Deprecated.\n\t\t\t'setplaylist',\n\t\t\t'stopallaudio'\n\t\t], {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\t/* no-op */\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMiscellaneous Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<goto>>\n\t*/\n\tMacro.add('goto', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = this.args[0].link;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the passage name.\n\t\t\t\tpassage = this.args[0];\n\t\t\t}\n\n\t\t\tif (!Story.has(passage)) {\n\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tCall `Engine.play()` asynchronously.\n\n\t\t\t\tNOTE: This does not terminate the current Wikifier call chain,\n\t\t\t\tthough, ideally, it should.  Doing so would not be trivial, however,\n\t\t\t\tand there's also the question of whether that behavior would be\n\t\t\t\tunwanted by users, who are used to the current behavior from\n\t\t\t\tsimilar macros and constructs.\n\t\t\t*/\n\t\t\tsetTimeout(() => Engine.play(passage), Engine.minDomActionDelay);\n\t\t}\n\t});\n\n\t/*\n\t\t<<repeat>> & <<stop>>\n\t*/\n\tMacro.add('repeat', {\n\t\tisAsync : true,\n\t\ttags    : null,\n\t\ttimers  : new Set(),\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no time value specified');\n\t\t\t}\n\n\t\t\tlet delay;\n\n\t\t\ttry {\n\t\t\t\tdelay = Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.args[0]));\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(ex.message);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\tconst $wrapper   = jQuery(document.createElement('span'))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t// Register the timer.\n\t\t\tthis.self.registerInterval(this.createShadowWrapper(() => {\n\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(frag, this.payload[0].contents);\n\n\t\t\t\tlet $output = $wrapper;\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$output = jQuery(document.createElement('span'))\n\t\t\t\t\t\t.addClass('macro-repeat-insert macro-repeat-in')\n\t\t\t\t\t\t.appendTo($output);\n\t\t\t\t}\n\n\t\t\t\t$output.append(frag);\n\n\t\t\t\tif (transition) {\n\t\t\t\t\tsetTimeout(() => $output.removeClass('macro-repeat-in'), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t}), delay);\n\t\t},\n\n\t\tregisterInterval(callback, delay) {\n\t\t\tif (typeof callback !== 'function') {\n\t\t\t\tthrow new TypeError('callback parameter must be a function');\n\t\t\t}\n\n\t\t\tconst turnId = State.turns;\n\t\t\tconst timers = this.timers;\n\t\t\tlet timerId = null;\n\n\t\t\t// Set up the interval.\n\t\t\ttimerId = setInterval(() => {\n\t\t\t\t// Terminate the timer if the turn IDs do not match.\n\t\t\t\tif (turnId !== State.turns) {\n\t\t\t\t\tclearInterval(timerId);\n\t\t\t\t\ttimers.delete(timerId);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet timerIdCache;\n\t\t\t\t/*\n\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t`Wikifier` call.\n\t\t\t\t*/\n\t\t\t\ttry {\n\t\t\t\t\tTempState.break = null;\n\n\t\t\t\t\t// Set up the `repeatTimerId` value, caching the existing value, if necessary.\n\t\t\t\t\tif (TempState.hasOwnProperty('repeatTimerId')) {\n\t\t\t\t\t\ttimerIdCache = TempState.repeatTimerId;\n\t\t\t\t\t}\n\n\t\t\t\t\tTempState.repeatTimerId = timerId;\n\n\t\t\t\t\t// Execute the callback.\n\t\t\t\t\tcallback.call(this);\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\t// Teardown the `repeatTimerId` property, restoring the cached value, if necessary.\n\t\t\t\t\tif (typeof timerIdCache !== 'undefined') {\n\t\t\t\t\t\tTempState.repeatTimerId = timerIdCache;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdelete TempState.repeatTimerId;\n\t\t\t\t\t}\n\n\t\t\t\t\tTempState.break = null;\n\t\t\t\t}\n\t\t\t}, delay);\n\t\t\ttimers.add(timerId);\n\n\t\t\t// Set up a single-use `prehistory` task to remove pending timers.\n\t\t\tif (!prehistory.hasOwnProperty('#repeat-timers-cleanup')) {\n\t\t\t\tprehistory['#repeat-timers-cleanup'] = task => {\n\t\t\t\t\tdelete prehistory[task]; // single-use task\n\t\t\t\t\ttimers.forEach(timerId => clearInterval(timerId));\n\t\t\t\t\ttimers.clear();\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\tMacro.add('stop', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (!TempState.hasOwnProperty('repeatTimerId')) {\n\t\t\t\treturn this.error('must only be used in conjunction with its parent macro <<repeat>>');\n\t\t\t}\n\n\t\t\tconst timers  = Macro.get('repeat').timers;\n\t\t\tconst timerId = TempState.repeatTimerId;\n\t\t\tclearInterval(timerId);\n\t\t\ttimers.delete(timerId);\n\t\t\tTempState.break = 2;\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<timed>> & <<next>>\n\t*/\n\tMacro.add('timed', {\n\t\tisAsync : true,\n\t\ttags    : ['next'],\n\t\ttimers  : new Set(),\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no time value specified in <<timed>>');\n\t\t\t}\n\n\t\t\tconst items = [];\n\n\t\t\ttry {\n\t\t\t\titems.push({\n\t\t\t\t\tname    : this.name,\n\t\t\t\t\tsource  : this.source,\n\t\t\t\t\tdelay   : Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.args[0])),\n\t\t\t\t\tcontent : this.payload[0].contents\n\t\t\t\t});\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`${ex.message} in <<timed>>`);\n\t\t\t}\n\n\t\t\tif (this.payload.length > 1) {\n\t\t\t\tlet i;\n\n\t\t\t\ttry {\n\t\t\t\t\tlet len;\n\n\t\t\t\t\tfor (i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\t\titems.push({\n\t\t\t\t\t\t\tname   : this.payload[i].name,\n\t\t\t\t\t\t\tsource : this.payload[i].source,\n\t\t\t\t\t\t\tdelay  : this.payload[i].args.length === 0\n\t\t\t\t\t\t\t\t? items[items.length - 1].delay\n\t\t\t\t\t\t\t\t: Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.payload[i].args[0])),\n\t\t\t\t\t\t\tcontent : this.payload[i].contents\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`${ex.message} in <<next>> (#${i})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\tconst $wrapper   = jQuery(document.createElement('span'))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t// Register the timer.\n\t\t\tthis.self.registerTimeout(this.createShadowWrapper(item => {\n\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(frag, item.content);\n\n\t\t\t\t// Output.\n\t\t\t\tlet $output = $wrapper;\n\n\t\t\t\t// Custom debug view setup for `<<next>>`.\n\t\t\t\tif (Config.debug && item.name === 'next') {\n\t\t\t\t\t$output = jQuery((new DebugView( // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t$output[0],\n\t\t\t\t\t\t'macro',\n\t\t\t\t\t\titem.name,\n\t\t\t\t\t\titem.source\n\t\t\t\t\t)).output);\n\t\t\t\t}\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$output = jQuery(document.createElement('span'))\n\t\t\t\t\t\t.addClass('macro-timed-insert macro-timed-in')\n\t\t\t\t\t\t.appendTo($output);\n\t\t\t\t}\n\n\t\t\t\t$output.append(frag);\n\n\t\t\t\tif (transition) {\n\t\t\t\t\tsetTimeout(() => $output.removeClass('macro-timed-in'), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t}), items);\n\t\t},\n\n\t\tregisterTimeout(callback, items) {\n\t\t\tif (typeof callback !== 'function') {\n\t\t\t\tthrow new TypeError('callback parameter must be a function');\n\t\t\t}\n\n\t\t\tconst turnId = State.turns;\n\t\t\tconst timers = this.timers;\n\t\t\tlet timerId  = null;\n\t\t\tlet nextItem = items.shift();\n\n\t\t\tconst worker = function () {\n\t\t\t\t// Bookkeeping.\n\t\t\t\ttimers.delete(timerId);\n\n\t\t\t\tif (turnId !== State.turns) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Set the current item and set up the next worker, if any.\n\t\t\t\tconst curItem = nextItem;\n\n\t\t\t\tif ((nextItem = items.shift()) != null) { // lazy equality for null\n\t\t\t\t\ttimerId = setTimeout(worker, nextItem.delay);\n\t\t\t\t\ttimers.add(timerId);\n\t\t\t\t}\n\n\t\t\t\t// Execute the callback.\n\t\t\t\tcallback.call(this, curItem);\n\t\t\t};\n\n\t\t\t// Setup the timeout.\n\t\t\ttimerId = setTimeout(worker, nextItem.delay);\n\t\t\ttimers.add(timerId);\n\n\t\t\t// Set up a single-use `prehistory` task to remove pending timers.\n\t\t\tif (!prehistory.hasOwnProperty('#timed-timers-cleanup')) {\n\t\t\t\tprehistory['#timed-timers-cleanup'] = task => {\n\t\t\t\t\tdelete prehistory[task]; // single-use task\n\t\t\t\t\ttimers.forEach(timerId => clearTimeout(timerId)); // eslint-disable-line no-shadow\n\t\t\t\t\ttimers.clear();\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<widget>>\n\t*/\n\tMacro.add('widget', {\n\t\ttags : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no widget name specified');\n\t\t\t}\n\n\t\t\tconst widgetName = this.args[0];\n\n\t\t\tif (Macro.has(widgetName)) {\n\t\t\t\tif (!Macro.get(widgetName).isWidget) {\n\t\t\t\t\treturn this.error(`cannot clobber existing macro \"${widgetName}\"`);\n\t\t\t\t}\n\n\t\t\t\t// Delete the existing widget.\n\t\t\t\tMacro.delete(widgetName);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tMacro.add(widgetName, {\n\t\t\t\t\tisWidget : true,\n\t\t\t\t\thandler  : (function (contents) {\n\t\t\t\t\t\treturn function () {\n\t\t\t\t\t\t\tlet argsCache;\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t// Cache the existing value of the `$args` variable, if necessary.\n\t\t\t\t\t\t\t\tif (State.variables.hasOwnProperty('args')) {\n\t\t\t\t\t\t\t\t\targsCache = State.variables.args;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Set up the widget `$args` variable and add a shadow.\n\t\t\t\t\t\t\t\tState.variables.args = [...this.args];\n\t\t\t\t\t\t\t\tState.variables.args.raw = this.args.raw;\n\t\t\t\t\t\t\t\tState.variables.args.full = this.args.full;\n\t\t\t\t\t\t\t\tthis.addShadow('$args');\n\n\t\t\t\t\t\t\t\t// Set up the error trapping variables.\n\t\t\t\t\t\t\t\tconst resFrag = document.createDocumentFragment();\n\t\t\t\t\t\t\t\tconst errList = [];\n\n\t\t\t\t\t\t\t\t// Wikify the widget contents.\n\t\t\t\t\t\t\t\tnew Wikifier(resFrag, contents);\n\n\t\t\t\t\t\t\t\t// Carry over the output, unless there were errors.\n\t\t\t\t\t\t\t\tArray.from(resFrag.querySelectorAll('.error')).forEach(errEl => {\n\t\t\t\t\t\t\t\t\terrList.push(errEl.textContent);\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tif (errList.length === 0) {\n\t\t\t\t\t\t\t\t\tthis.output.appendChild(resFrag);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\treturn this.error(`error${errList.length > 1 ? 's' : ''} within widget contents (${errList.join('; ')})`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\treturn this.error(`cannot execute widget: ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t// Revert the `$args` variable shadowing.\n\t\t\t\t\t\t\t\tif (typeof argsCache !== 'undefined') {\n\t\t\t\t\t\t\t\t\tState.variables.args = argsCache;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tdelete State.variables.args;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t})(this.payload[0].contents)\n\t\t\t\t});\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`cannot create widget macro \"${widgetName}\": ${ex.message}`);\n\t\t\t}\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tdialog.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Has, L10n, safeActiveElement */\n\nvar Dialog = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Dialog element caches.\n\tlet _$overlay       = null;\n\tlet _$dialog        = null;\n\tlet _$dialogTitle   = null;\n\tlet _$dialogBody    = null;\n\n\t// The last active/focused non-dialog element.\n\tlet _lastActive     = null;\n\n\t// The width of the browser's scrollbars.\n\tlet _scrollbarWidth = 0;\n\n\t// Dialog mutation resize handler.\n\tlet _dialogObserver = null;\n\n\n\t/*******************************************************************************\n\t\tDialog Functions.\n\t*******************************************************************************/\n\n\t/*\n\t\t[DEPRECATED] Adds a click hander to the target element(s) which opens the dialog modal.\n\t*/\n\tfunction dialogAddClickHandler(targets, options, startFn, doneFn, closeFn) {\n\t\treturn jQuery(targets).ariaClick(ev => {\n\t\t\tev.preventDefault();\n\n\t\t\t// Call the start function.\n\t\t\tif (typeof startFn === 'function') {\n\t\t\t\tstartFn(ev);\n\t\t\t}\n\n\t\t\t// Open the dialog.\n\t\t\tdialogOpen(options, closeFn);\n\n\t\t\t// Call the done function.\n\t\t\tif (typeof doneFn === 'function') {\n\t\t\t\tdoneFn(ev);\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction dialogBodyAppend(...args) {\n\t\t_$dialogBody.append(...args);\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogBody() {\n\t\treturn _$dialogBody.get(0);\n\t}\n\n\tfunction dialogClose(ev) {\n\t\t// Trigger a `:dialogclosing` event on the dialog body.\n\t\t_$dialogBody.trigger(':dialogclosing');\n\n\t\t// Largely reverse the actions taken in `dialogOpen()`.\n\t\tjQuery(document)\n\t\t\t.off('.dialog-close');\n\t\tif (_dialogObserver) {\n\t\t\t_dialogObserver.disconnect();\n\t\t\t_dialogObserver = null;\n\t\t}\n\t\telse {\n\t\t\t_$dialogBody\n\t\t\t\t.off('.dialog-resize');\n\t\t}\n\t\tjQuery(window)\n\t\t\t.off('.dialog-resize');\n\t\t_$dialog\n\t\t\t.removeClass('open')\n\t\t\t.css({ left : '', right : '', top : '', bottom : '' });\n\n\t\tjQuery('#ui-bar,#story')\n\t\t\t.find('[tabindex=-2]')\n\t\t\t.removeAttr('aria-hidden')\n\t\t\t.attr('tabindex', 0);\n\t\tjQuery('body>[tabindex=-3]')\n\t\t\t.removeAttr('aria-hidden')\n\t\t\t.removeAttr('tabindex');\n\n\t\t_$overlay\n\t\t\t.removeClass('open');\n\t\tjQuery(document.documentElement)\n\t\t\t.removeAttr('data-dialog');\n\n\t\t// Clear the dialog's content.\n\t\t_$dialogTitle\n\t\t\t.empty();\n\t\t_$dialogBody\n\t\t\t.empty()\n\t\t\t.removeClass();\n\n\t\t// Attempt to restore focus to whichever element had it prior to opening the dialog.\n\t\tif (_lastActive !== null) {\n\t\t\tjQuery(_lastActive).focus();\n\t\t\t_lastActive = null;\n\t\t}\n\n\t\t// Call the given \"on close\" callback function, if any.\n\t\tif (ev && ev.data && typeof ev.data.closeFn === 'function') {\n\t\t\tev.data.closeFn(ev);\n\t\t}\n\n\t\t// Trigger a `:dialogclosed` event on the dialog body.\n\t\t/* legacy */\n\t\t_$dialogBody.trigger(':dialogclose');\n\t\t/* /legacy */\n\t\t_$dialogBody.trigger(':dialogclosed');\n\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogInit() {\n\t\tif (DEBUG) { console.log('[Dialog/dialogInit()]'); }\n\n\t\tif (document.getElementById('ui-dialog')) {\n\t\t\treturn;\n\t\t}\n\n\t\t/*\n\t\t\tCalculate and cache the width of scrollbars.\n\t\t*/\n\t\t_scrollbarWidth = (() => {\n\t\t\tlet scrollbarWidth;\n\n\t\t\ttry {\n\t\t\t\tconst inner = document.createElement('p');\n\t\t\t\tconst outer = document.createElement('div');\n\n\t\t\t\tinner.style.width      = '100%';\n\t\t\t\tinner.style.height     = '200px';\n\t\t\t\touter.style.position   = 'absolute';\n\t\t\t\touter.style.left       = '0px';\n\t\t\t\touter.style.top        = '0px';\n\t\t\t\touter.style.width      = '100px';\n\t\t\t\touter.style.height     = '100px';\n\t\t\t\touter.style.visibility = 'hidden';\n\t\t\t\touter.style.overflow   = 'hidden';\n\n\t\t\t\touter.appendChild(inner);\n\t\t\t\tdocument.body.appendChild(outer);\n\n\t\t\t\tconst w1 = inner.offsetWidth;\n\t\t\t\t/*\n\t\t\t\t\tThe `overflow: scroll` style property value does not work consistently\n\t\t\t\t\twith scrollbars which are styled with `::-webkit-scrollbar`, so we use\n\t\t\t\t\t`overflow: auto` with dimensions guaranteed to force a scrollbar.\n\t\t\t\t*/\n\t\t\t\touter.style.overflow = 'auto';\n\t\t\t\tlet w2 = inner.offsetWidth;\n\n\t\t\t\tif (w1 === w2) {\n\t\t\t\t\tw2 = outer.clientWidth;\n\t\t\t\t}\n\n\t\t\t\tdocument.body.removeChild(outer);\n\n\t\t\t\tscrollbarWidth = w1 - w2;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn scrollbarWidth || 17; // 17px is a reasonable failover\n\t\t})();\n\n\t\t/*\n\t\t\tGenerate the dialog elements.\n\t\t*/\n\t\tconst $elems = jQuery(document.createDocumentFragment())\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  '<div id=\"ui-overlay\" class=\"ui-close\"></div>'\n\t\t\t\t+ '<div id=\"ui-dialog\" tabindex=\"0\" role=\"dialog\" aria-labelledby=\"ui-dialog-title\">'\n\t\t\t\t+     '<div id=\"ui-dialog-titlebar\">'\n\t\t\t\t+         '<h1 id=\"ui-dialog-title\"></h1>'\n\t\t\t\t+         `<button id=\"ui-dialog-close\" class=\"ui-close\" tabindex=\"0\" aria-label=\"${L10n.get('close')}\">\\uE804</button>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div id=\"ui-dialog-body\"></div>'\n\t\t\t\t+ '</div>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t);\n\n\t\t/*\n\t\t\tCache the dialog elements, since they're going to be used often.\n\n\t\t\tNOTE: We rewrap the elements themselves, rather than simply using\n\t\t\tthe results of `find()`, so that we cache uncluttered jQuery-wrappers\n\t\t\t(i.e. `context` refers to the elements and there is no `prevObject`).\n\t\t*/\n\t\t_$overlay     = jQuery($elems.find('#ui-overlay').get(0));\n\t\t_$dialog      = jQuery($elems.find('#ui-dialog').get(0));\n\t\t_$dialogTitle = jQuery($elems.find('#ui-dialog-title').get(0));\n\t\t_$dialogBody  = jQuery($elems.find('#ui-dialog-body').get(0));\n\n\t\t/*\n\t\t\tInsert the dialog elements into the page before the main script.\n\t\t*/\n\t\t$elems.insertBefore('body>script#script-sugarcube');\n\t}\n\n\tfunction dialogIsOpen(classNames) {\n\t\treturn _$dialog.hasClass('open')\n\t\t\t&& (classNames ? classNames.splitOrEmpty(/\\s+/).every(cn => _$dialogBody.hasClass(cn)) : true);\n\t}\n\n\tfunction dialogOpen(options, closeFn) {\n\t\t// Trigger a `:dialogopening` event on the dialog body.\n\t\t_$dialogBody.trigger(':dialogopening');\n\n\t\t// Grab the options we care about.\n\t\tconst { top } = jQuery.extend({ top : 50 }, options);\n\n\t\t// Record the last active/focused non-dialog element.\n\t\tif (!dialogIsOpen()) {\n\t\t\t_lastActive = safeActiveElement();\n\t\t}\n\n\t\t// Add the `data-dialog` attribute to <html> (mostly used to style <body>).\n\t\tjQuery(document.documentElement)\n\t\t\t.attr('data-dialog', 'open');\n\n\t\t// Display the overlay.\n\t\t_$overlay\n\t\t\t.addClass('open');\n\n\t\t/*\n\t\t\tAdd the imagesLoaded handler to the dialog body, if necessary.\n\n\t\t\tNOTE: We use `querySelector()` here as jQuery has no simple way to\n\t\t\tcheck if, and only if, at least one element of the specified type\n\t\t\texists.  The best that jQuery offers is analogous to `querySelectorAll()`,\n\t\t\twhich enumerates all elements of the specified type.\n\t\t*/\n\t\tif (_$dialogBody[0].querySelector('img') !== null) {\n\t\t\t_$dialogBody\n\t\t\t\t.imagesLoaded()\n\t\t\t\t.always(() => _resizeHandler({ data : { top } }));\n\t\t}\n\n\t\t// Add `aria-hidden=true` to all direct non-dialog-children of <body> to\n\t\t// hide the underlying page from screen readers while the dialog is open.\n\t\tjQuery('body>:not(script,#store-area,tw-storydata,#ui-bar,#ui-overlay,#ui-dialog)')\n\t\t\t.attr('tabindex', -3)\n\t\t\t.attr('aria-hidden', true);\n\t\tjQuery('#ui-bar,#story')\n\t\t\t.find('[tabindex]:not([tabindex^=-])')\n\t\t\t.attr('tabindex', -2)\n\t\t\t.attr('aria-hidden', true);\n\n\t\t// Display the dialog.\n\t\t_$dialog\n\t\t\t.css(_calcPosition(top))\n\t\t\t.addClass('open')\n\t\t\t.focus();\n\n\t\t// Add the UI resize handler.\n\t\tjQuery(window)\n\t\t\t.on('resize.dialog-resize', null, { top }, jQuery.throttle(40, _resizeHandler));\n\n\t\t// Add the dialog mutation resize handler.\n\t\tif (Has.mutationObserver) {\n\t\t\t_dialogObserver = new MutationObserver(mutations => {\n\t\t\t\tfor (let i = 0; i < mutations.length; ++i) {\n\t\t\t\t\tif (mutations[i].type === 'childList') {\n\t\t\t\t\t\t_resizeHandler({ data : { top } });\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t_dialogObserver.observe(_$dialogBody[0], {\n\t\t\t\tchildList : true,\n\t\t\t\tsubtree   : true\n\t\t\t});\n\t\t}\n\t\telse {\n\t\t\t_$dialogBody\n\t\t\t\t.on(\n\t\t\t\t\t'DOMNodeInserted.dialog-resize DOMNodeRemoved.dialog-resize',\n\t\t\t\t\tnull,\n\t\t\t\t\t{ top },\n\t\t\t\t\tjQuery.throttle(40, _resizeHandler)\n\t\t\t\t);\n\t\t}\n\n\t\t// Set up the delegated UI close handler.\n\t\tjQuery(document)\n\t\t\t.on('click.dialog-close', '.ui-close', { closeFn }, dialogClose)\n\t\t\t.on('keypress.dialog-close', '.ui-close', function (ev) {\n\t\t\t\t// 13 is Enter/Return, 32 is Space.\n\t\t\t\tif (ev.which === 13 || ev.which === 32) {\n\t\t\t\t\tjQuery(this).trigger('click');\n\t\t\t\t}\n\t\t\t});\n\n\t\t// Trigger a `:dialogopened` event on the dialog body.\n\t\t/* legacy */\n\t\t_$dialogBody.trigger(':dialogopen');\n\t\t/* /legacy */\n\t\t_$dialogBody.trigger(':dialogopened');\n\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogResize(data) {\n\t\treturn _resizeHandler(typeof data === 'object' ? { data } : undefined);\n\t}\n\n\tfunction dialogSetup(title, classNames) {\n\t\t_$dialogBody\n\t\t\t.empty()\n\t\t\t.removeClass();\n\n\t\tif (classNames != null) { // lazy equality for null\n\t\t\t_$dialogBody.addClass(classNames);\n\t\t}\n\n\t\t_$dialogTitle\n\t\t\t.empty()\n\t\t\t.append((title != null ? String(title) : '') || '\\u00A0'); // lazy equality for null\n\n\t\t// TODO: In v3 this should return `Dialog` for chaining.\n\t\treturn _$dialogBody.get(0);\n\t}\n\n\tfunction dialogBodyWiki(...args) {\n\t\t_$dialogBody.wiki(...args);\n\t\treturn Dialog;\n\t}\n\n\n\t/*******************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************/\n\n\tfunction _calcPosition(topPos) {\n\t\tconst top       = topPos != null ? topPos : 50; // lazy equality for null\n\t\tconst $parent   = jQuery(window);\n\t\tconst dialogPos = { left : '', right : '', top : '', bottom : '' };\n\n\t\t// Unset the dialog's positional properties before checking its dimensions.\n\t\t_$dialog.css(dialogPos);\n\n\t\tlet horzSpace = $parent.width() - _$dialog.outerWidth(true) - 1;   // -1 to address a Firefox issue\n\t\tlet vertSpace = $parent.height() - _$dialog.outerHeight(true) - 1; // -1 to address a Firefox issue\n\n\t\tif (horzSpace <= 32 + _scrollbarWidth) {\n\t\t\tvertSpace -= _scrollbarWidth;\n\t\t}\n\n\t\tif (vertSpace <= 32 + _scrollbarWidth) {\n\t\t\thorzSpace -= _scrollbarWidth;\n\t\t}\n\n\t\tif (horzSpace <= 32) {\n\t\t\tdialogPos.left = dialogPos.right = 16;\n\t\t}\n\t\telse {\n\t\t\tdialogPos.left = dialogPos.right = horzSpace / 2 >> 0;\n\t\t}\n\n\t\tif (vertSpace <= 32) {\n\t\t\tdialogPos.top = dialogPos.bottom = 16;\n\t\t}\n\t\telse {\n\t\t\tif (vertSpace / 2 > top) {\n\t\t\t\tdialogPos.top = top;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdialogPos.top = dialogPos.bottom = vertSpace / 2 >> 0;\n\t\t\t}\n\t\t}\n\n\t\tObject.keys(dialogPos).forEach(key => {\n\t\t\tif (dialogPos[key] !== '') {\n\t\t\t\tdialogPos[key] += 'px';\n\t\t\t}\n\t\t});\n\n\t\treturn dialogPos;\n\t}\n\n\tfunction _resizeHandler(ev) {\n\t\tconst top = ev && ev.data && typeof ev.data.top !== 'undefined' ? ev.data.top : 50;\n\n\t\tif (_$dialog.css('display') === 'block') {\n\t\t\t// Stow the dialog.\n\t\t\t_$dialog.css({ display : 'none' });\n\n\t\t\t// Restore the dialog with its new positional properties.\n\t\t\t_$dialog.css(jQuery.extend({ display : '' }, _calcPosition(top)));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tappend : { value : dialogBodyAppend },\n\t\tbody   : { value : dialogBody },\n\t\tclose  : { value : dialogClose },\n\t\tinit   : { value : dialogInit },\n\t\tisOpen : { value : dialogIsOpen },\n\t\topen   : { value : dialogOpen },\n\t\tresize : { value : dialogResize },\n\t\tsetup  : { value : dialogSetup },\n\t\twiki   : { value : dialogBodyWiki },\n\n\t\t// Legacy Functions.\n\t\taddClickHandler : { value : dialogAddClickHandler }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tengine.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Config, DebugView, Dialog, Has, LoadScreen, Save, State, Story, StyleWrapper, UI, UIBar, Util,\n\t       Wikifier, postdisplay, postrender, predisplay, prehistory, prerender, setDisplayTitle\n*/\n\nvar Engine = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Engine state types object (pseudo-enumeration).\n\tconst States = Util.toEnum({\n\t\tIdle      : 'idle',\n\t\tPlaying   : 'playing',\n\t\tRendering : 'rendering'\n\t});\n\n\t// Minimum delay for DOM actions (in milliseconds).\n\tconst minDomActionDelay = 40;\n\n\t// Current state of the engine (default: `Engine.States.Idle`).\n\tlet _state = States.Idle;\n\n\t// Last time `enginePlay()` was called (in milliseconds).\n\tlet _lastPlay = null;\n\n\t// Cache of the debug view for the StoryInit special passage.\n\tlet _storyInitDebugView = null;\n\n\t// Cache of the outline patching <style> element (`StyleWrapper`-wrapped).\n\tlet _outlinePatch = null;\n\n\t// List of objects describing `StoryInterface` elements to update via passages during navigation.\n\tlet _updating = null;\n\n\n\t/*******************************************************************************************************************\n\t\tEngine Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tInitialize the core story elements and perform some bookkeeping.\n\t*/\n\tfunction engineInit() {\n\t\tif (DEBUG) { console.log('[Engine/engineInit()]'); }\n\n\t\t/*\n\t\t\tRemove #init-no-js & #init-lacking from #init-screen.\n\t\t*/\n\t\tjQuery('#init-no-js,#init-lacking').remove();\n\n\t\t/*\n\t\t\tGenerate the core story elements and insert them into the page before the store area.\n\t\t*/\n\t\t(() => {\n\t\t\tconst $elems = jQuery(document.createDocumentFragment());\n\t\t\tconst markup = Story.has('StoryInterface') && Story.get('StoryInterface').text.trim();\n\n\t\t\tif (markup) {\n\t\t\t\t// Remove the UI bar, its styles, and events.\n\t\t\t\tUIBar.destroy();\n\n\t\t\t\t// Remove the core display area styles.\n\t\t\t\tjQuery(document.head).find('#style-core-display').remove();\n\n\t\t\t\t$elems.append(markup);\n\n\t\t\t\tif ($elems.find('#passages').length === 0) {\n\t\t\t\t\tthrow new Error('no element with ID \"passages\" found within \"StoryInterface\" special passage');\n\t\t\t\t}\n\n\t\t\t\tconst updating = [];\n\n\t\t\t\t$elems.find('[data-passage]').each((i, el) => {\n\t\t\t\t\tif (el.id === 'passages') {\n\t\t\t\t\t\tthrow new Error(`\"StoryInterface\" element <${el.nodeName.toLowerCase()} id=\"passages\"> must not contain a \"data-passage\" content attribute`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst passage = el.getAttribute('data-passage').trim();\n\n\t\t\t\t\tif (el.firstElementChild !== null) {\n\t\t\t\t\t\tthrow new Error(`\"StoryInterface\" element <${el.nodeName.toLowerCase()} data-passage=\"${passage}\"> contains child elements`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tupdating.push({\n\t\t\t\t\t\t\tpassage,\n\t\t\t\t\t\t\telement : el\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (updating.length > 0) {\n\t\t\t\t\t_updating = updating;\n\t\t\t\t}\n\n\t\t\t\tConfig.ui.updateStoryElements = false;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$elems.append('<div id=\"story\" role=\"main\"><div id=\"passages\"></div></div>');\n\t\t\t}\n\n\t\t\t// Insert the core UI elements into the page before the main script.\n\t\t\t$elems.insertBefore('body>script#script-sugarcube');\n\t\t})();\n\n\t\t/*\n\t\t\tGenerate and cache the ARIA outlines <style> element (`StyleWrapper`-wrapped)\n\t\t\tand set up the handler to manipulate the outlines.\n\n\t\t\tIDEA: http://www.paciellogroup.com/blog/2012/04/how-to-remove-css-outlines-in-an-accessible-manner/\n\t\t*/\n\t\t_outlinePatch = new StyleWrapper((\n\t\t\t() => jQuery(document.createElement('style'))\n\t\t\t\t.attr({\n\t\t\t\t\tid   : 'style-aria-outlines',\n\t\t\t\t\ttype : 'text/css'\n\t\t\t\t})\n\t\t\t\t.appendTo(document.head)\n\t\t\t\t.get(0) // return the <style> element itself\n\t\t)());\n\t\tlet _lastOutlineEvent;\n\t\tjQuery(document).on(\n\t\t\t'mousedown.aria-outlines keydown.aria-outlines',\n\t\t\tev => {\n\t\t\t\tif (ev.type !== _lastOutlineEvent) {\n\t\t\t\t\t_lastOutlineEvent = ev.type;\n\n\t\t\t\t\tif (ev.type === 'keydown') {\n\t\t\t\t\t\t_showOutlines();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t_hideOutlines();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\t/*\n\t\tStarts the story.\n\t*/\n\tfunction engineStart() {\n\t\tif (DEBUG) { console.log('[Engine/engineStart()]'); }\n\n\t\t/*\n\t\t\tExecute the StoryInit special passage.\n\t\t*/\n\t\tif (Story.has('StoryInit')) {\n\t\t\ttry {\n\t\t\t\tconst debugBuffer = Wikifier.wikifyEval(Story.get('StoryInit').text);\n\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tconst debugView = new DebugView(\n\t\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t\t'special',\n\t\t\t\t\t\t'StoryInit',\n\t\t\t\t\t\t'StoryInit'\n\t\t\t\t\t);\n\t\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\t\tdebugView.append(debugBuffer);\n\t\t\t\t\t_storyInitDebugView = debugView.output;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('StoryInit', ex.message);\n\t\t\t}\n\t\t}\n\n\t\t// Sanity checks.\n\t\tif (Config.passages.start == null) { // lazy equality for null\n\t\t\tthrow new Error('starting passage not selected');\n\t\t}\n\t\tif (!Story.has(Config.passages.start)) {\n\t\t\tthrow new Error(`starting passage (\"${Config.passages.start}\") not found`);\n\t\t}\n\n\t\t// Focus the document element initially.\n\t\tjQuery(document.documentElement).focus();\n\n\t\t/*\n\t\t\tAttempt to restore an active session.  Failing that, attempt to autoload the autosave,\n\t\t\tif requested.  Failing that, display the starting passage.\n\t\t*/\n\t\tif (State.restore()) {\n\t\t\tengineShow();\n\t\t}\n\t\telse {\n\t\t\tlet loadStart = true;\n\n\t\t\tswitch (typeof Config.saves.autoload) {\n\t\t\tcase 'boolean':\n\t\t\t\tif (Config.saves.autoload && Save.autosave.ok() && Save.autosave.has()) {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\t\tloadStart = !Save.autosave.load();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'string':\n\t\t\t\tif (Config.saves.autoload === 'prompt' && Save.autosave.ok() && Save.autosave.has()) {\n\t\t\t\t\tloadStart = false;\n\t\t\t\t\tUI.buildAutoload();\n\t\t\t\t\tDialog.open();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'function':\n\t\t\t\tif (Save.autosave.ok() && Save.autosave.has() && !!Config.saves.autoload()) {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\t\tloadStart = !Save.autosave.load();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (loadStart) {\n\t\t\t\tif (DEBUG) { console.log(`\\tstarting passage: \"${Config.passages.start}\"`); }\n\n\t\t\t\tenginePlay(Config.passages.start);\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t\tRestarts the story.\n\t*/\n\tfunction engineRestart() {\n\t\tif (DEBUG) { console.log('[Engine/engineRestart()]'); }\n\n\t\t/*\n\t\t\tShow the loading screen to hide any unsightly rendering shenanigans during the\n\t\t\tpage reload.\n\t\t*/\n\t\tLoadScreen.show();\n\n\t\t/*\n\t\t\tScroll the window to the top.\n\n\t\t\tThis is required by most browsers for the starting passage or it will remain at\n\t\t\twhatever its current scroll position is after the page reload.  We do it generally,\n\t\t\trather than only for the currently set starting passage, since the starting passage\n\t\t\tmay be dynamically manipulated.\n\t\t*/\n\t\twindow.scroll(0, 0);\n\n\t\t/*\n\t\t\tDelete the active session.\n\t\t*/\n\t\tState.reset();\n\n\t\t/*\n\t\t\tTrigger an ':enginerestart' event.\n\t\t*/\n\t\tjQuery.event.trigger(':enginerestart');\n\n\t\t/*\n\t\t\tReload the page.\n\t\t*/\n\t\twindow.location.reload();\n\t}\n\n\t/*\n\t\tReturns the current state of the engine.\n\t*/\n\tfunction engineState() {\n\t\treturn _state;\n\t}\n\n\t/*\n\t\tReturns whether the engine is idle.\n\t*/\n\tfunction engineIsIdle() {\n\t\treturn _state === States.Idle;\n\t}\n\n\t/*\n\t\tReturns whether the engine is playing.\n\t*/\n\tfunction engineIsPlaying() {\n\t\treturn _state !== States.Idle;\n\t}\n\n\t/*\n\t\tReturns whether the engine is rendering.\n\t*/\n\tfunction engineIsRendering() {\n\t\treturn _state === States.Rendering;\n\t}\n\n\t/*\n\t\tReturns a timestamp representing the last time `Engine.play()` was called.\n\t*/\n\tfunction engineLastPlay() {\n\t\treturn _lastPlay;\n\t}\n\n\t/*\n\t\tActivate the moment at the given index within the state history and show it.\n\t*/\n\tfunction engineGoTo(idx) {\n\t\tconst succeded = State.goTo(idx);\n\n\t\tif (succeded) {\n\t\t\tengineShow();\n\t\t}\n\n\t\treturn succeded;\n\t}\n\n\t/*\n\t\tActivate the moment at the given offset from the active moment within the state history\n\t\tand show it.\n\t*/\n\tfunction engineGo(offset) {\n\t\tconst succeded = State.go(offset);\n\n\t\tif (succeded) {\n\t\t\tengineShow();\n\t\t}\n\n\t\treturn succeded;\n\t}\n\n\t/*\n\t\tGo to the moment which directly precedes the active moment and show it.\n\t*/\n\tfunction engineBackward() {\n\t\treturn engineGo(-1);\n\t}\n\n\t/*\n\t\tGo to the moment which directly follows the active moment and show it.\n\t*/\n\tfunction engineForward() {\n\t\treturn engineGo(1);\n\t}\n\n\t/*\n\t\tRenders and displays the active (present) moment's associated passage without adding\n\t\ta new moment to the history.\n\t*/\n\tfunction engineShow() {\n\t\treturn enginePlay(State.passage, true);\n\t}\n\n\t/*\n\t\tRenders and displays the passage referenced by the given title, optionally without\n\t\tadding a new moment to the history.\n\t*/\n\tfunction enginePlay(title, noHistory) {\n\t\tif (DEBUG) { console.log(`[Engine/enginePlay(title: \"${title}\", noHistory: ${noHistory})]`); }\n\n\t\tlet passageTitle = title;\n\n\t\t// Update the engine state.\n\t\t_state = States.Playing;\n\n\t\t// Reset the temporary state and variables objects.\n\t\tTempState = {}; // eslint-disable-line no-undef\n\t\tState.clearTemporary();\n\n\t\t// Debug view setup.\n\t\tlet passageReadyOutput;\n\t\tlet passageDoneOutput;\n\n\t\t// Execute the navigation override callback.\n\t\tif (typeof Config.navigation.override === 'function') {\n\t\t\ttry {\n\t\t\t\tconst overrideTitle = Config.navigation.override(passageTitle);\n\n\t\t\t\tif (overrideTitle) {\n\t\t\t\t\tpassageTitle = overrideTitle;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\t\t}\n\n\t\t// Retrieve the passage by the given title.\n\t\t//\n\t\t// NOTE: The values of the `title` parameter and `passageTitle` variable\n\t\t// may be empty, strings, or numbers (though using a number as reference\n\t\t// to a numeric title should be discouraged), so after loading the passage,\n\t\t// always refer to `passage.title` and never to the others.\n\t\tconst passage = Story.get(passageTitle);\n\n\t\t// Execute the pre-history events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype : ':passageinit',\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(prehistory).forEach(task => {\n\t\t\tif (typeof prehistory[task] === 'function') {\n\t\t\t\tprehistory[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\t// Create a new entry in the history.\n\t\tif (!noHistory) {\n\t\t\tState.create(passage.title);\n\t\t}\n\n\t\t// Clear the document body's classes.\n\t\tif (document.body.className) {\n\t\t\tdocument.body.className = '';\n\t\t}\n\n\t\t// Update the last play time.\n\t\t//\n\t\t// NOTE: This is mostly for event, task, and special passage code,\n\t\t// though the likelihood of it being needed this early is low.  This\n\t\t// will be updated again later at the end.\n\t\t_lastPlay = Util.now();\n\n\t\t// Execute pre-display tasks and the `PassageReady` special passage.\n\t\tObject.keys(predisplay).forEach(task => {\n\t\t\tif (typeof predisplay[task] === 'function') {\n\t\t\t\tpredisplay[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\tif (Story.has('PassageReady')) {\n\t\t\ttry {\n\t\t\t\tpassageReadyOutput = Wikifier.wikifyEval(Story.get('PassageReady').text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('PassageReady', ex.message);\n\t\t\t}\n\t\t}\n\n\t\t// Update the engine state.\n\t\t_state = States.Rendering;\n\n\t\t// Get the passage's tags as a string, or `null` if there aren't any.\n\t\tconst dataTags = passage.tags.length > 0 ? passage.tags.join(' ') : null;\n\n\t\t// Create and set up the incoming passage element.\n\t\tconst passageEl = document.createElement('div');\n\t\tjQuery(passageEl)\n\t\t\t.attr({\n\t\t\t\tid             : passage.domId,\n\t\t\t\t'data-passage' : passage.title,\n\t\t\t\t'data-tags'    : dataTags\n\t\t\t})\n\t\t\t.addClass(`passage ${passage.className}`);\n\n\t\t// Add the passage's classes and tags to the document body.\n\t\tjQuery(document.body)\n\t\t\t.attr('data-tags', dataTags)\n\t\t\t.addClass(passage.className);\n\n\t\t// Add the passage's tags to the document element.\n\t\tjQuery(document.documentElement)\n\t\t\t.attr('data-tags', dataTags);\n\n\t\t// Execute pre-render events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagestart',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(prerender).forEach(task => {\n\t\t\tif (typeof prerender[task] === 'function') {\n\t\t\t\tprerender[task].call(passage, passageEl, task);\n\t\t\t}\n\t\t});\n\n\t\t// Render the `PassageHeader` passage, if it exists, into the passage element.\n\t\tif (Story.has('PassageHeader')) {\n\t\t\tnew Wikifier(passageEl, Story.get('PassageHeader').processText());\n\t\t}\n\n\t\t// Render the passage into its element.\n\t\tpassageEl.appendChild(passage.render());\n\n\t\t// Render the `PassageFooter` passage, if it exists, into the passage element.\n\t\tif (Story.has('PassageFooter')) {\n\t\t\tnew Wikifier(passageEl, Story.get('PassageFooter').processText());\n\t\t}\n\n\t\t// Execute post-render events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagerender',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(postrender).forEach(task => {\n\t\t\tif (typeof postrender[task] === 'function') {\n\t\t\t\tpostrender[task].call(passage, passageEl, task);\n\t\t\t}\n\t\t});\n\n\t\t// Cache the passage container.\n\t\tconst containerEl = document.getElementById('passages');\n\n\t\t// Empty the passage container.\n\t\tif (containerEl.hasChildNodes()) {\n\t\t\tif (\n\t\t\t\t   typeof Config.passages.transitionOut === 'number'\n\t\t\t\t|| typeof Config.passages.transitionOut === 'string'\n\t\t\t\t&& Config.passages.transitionOut !== ''\n\t\t\t\t&& Has.transitionEndEvent\n\t\t\t) {\n\t\t\t\t[...containerEl.childNodes].forEach(outgoing => {\n\t\t\t\t\tconst $outgoing = jQuery(outgoing);\n\n\t\t\t\t\tif (outgoing.nodeType === Node.ELEMENT_NODE && $outgoing.hasClass('passage')) {\n\t\t\t\t\t\tif ($outgoing.hasClass('passage-out')) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$outgoing\n\t\t\t\t\t\t\t.attr('id', `out-${$outgoing.attr('id')}`)\n\t\t\t\t\t\t\t.addClass('passage-out');\n\n\t\t\t\t\t\tif (typeof Config.passages.transitionOut === 'string') {\n\t\t\t\t\t\t\t$outgoing.on(Has.transitionEndEvent, ev => {\n\t\t\t\t\t\t\t\tif (ev.originalEvent.propertyName === Config.passages.transitionOut) {\n\t\t\t\t\t\t\t\t\t$outgoing.remove();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tsetTimeout(\n\t\t\t\t\t\t\t\t() => $outgoing.remove(),\n\t\t\t\t\t\t\t\tMath.max(minDomActionDelay, Config.passages.transitionOut)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t$outgoing.remove();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery(containerEl).empty();\n\t\t\t}\n\t\t}\n\n\t\t// Append the passage element to the passage container and set up its transition.\n\t\tjQuery(passageEl)\n\t\t\t.addClass('passage-in')\n\t\t\t.appendTo(containerEl);\n\t\tsetTimeout(() => jQuery(passageEl).removeClass('passage-in'), minDomActionDelay);\n\n\t\t// Update the story display title, if necessary.\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\t// NOTE: We don't have an `else` here because that case will be handled later (below).\n\t\t\tif (_updating !== null || !Config.ui.updateStoryElements) {\n\t\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t\t}\n\t\t}\n\t\telse if (Config.passages.displayTitles && passage.title !== Config.passages.start) {\n\t\t\tdocument.title = `${passage.title} | ${Story.title}`;\n\t\t}\n\n\t\t// Scroll the window to the top.\n\t\twindow.scroll(0, 0);\n\n\t\t// Update the engine state.\n\t\t_state = States.Playing;\n\n\t\t// Execute post-display events, tasks, and the `PassageDone` special passage.\n\t\tif (Story.has('PassageDone')) {\n\t\t\ttry {\n\t\t\t\tpassageDoneOutput = Wikifier.wikifyEval(Story.get('PassageDone').text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('PassageDone', ex.message);\n\t\t\t}\n\t\t}\n\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagedisplay',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(postdisplay).forEach(task => {\n\t\t\tif (typeof postdisplay[task] === 'function') {\n\t\t\t\tpostdisplay[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\t// Update the other interface elements, if necessary.\n\t\tif (_updating !== null) {\n\t\t\t_updating.forEach(pair => {\n\t\t\t\tjQuery(pair.element).empty();\n\t\t\t\tnew Wikifier(pair.element, Story.get(pair.passage).processText().trim());\n\t\t\t});\n\t\t}\n\t\telse if (Config.ui.updateStoryElements) {\n\t\t\tUIBar.update();\n\t\t}\n\n\t\t// Add the completed debug views for `StoryInit`, `PassageReady`, and `PassageDone`\n\t\t// to the incoming passage element.\n\t\tif (Config.debug) {\n\t\t\tlet debugView;\n\n\t\t\t// Prepend the `PassageReady` debug view.\n\t\t\tif (passageReadyOutput != null) { // lazy equality for null\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t'special',\n\t\t\t\t\t'PassageReady',\n\t\t\t\t\t'PassageReady'\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\tdebugView.append(passageReadyOutput);\n\t\t\t\tjQuery(passageEl).prepend(debugView.output);\n\t\t\t}\n\n\t\t\t// Append the `PassageDone` debug view.\n\t\t\tif (passageDoneOutput != null) { // lazy equality for null\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t'special',\n\t\t\t\t\t'PassageDone',\n\t\t\t\t\t'PassageDone'\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\tdebugView.append(passageDoneOutput);\n\t\t\t\tjQuery(passageEl).append(debugView.output);\n\t\t\t}\n\n\t\t\t// Prepend the cached `StoryInit` debug view, if we're showing the first moment/turn.\n\t\t\tif (State.turns === 1 && _storyInitDebugView != null) { // lazy equality for null\n\t\t\t\tjQuery(passageEl).prepend(_storyInitDebugView);\n\t\t\t}\n\t\t}\n\n\t\t// Last second post-processing for accessibility and other things.\n\t\t_hideOutlines(); // initially hide outlines\n\t\tjQuery('#story')\n\t\t\t// Add `link-external` to all `href` bearing `<a>` elements which don't have it.\n\t\t\t.find('a[href]:not(.link-external)')\n\t\t\t.addClass('link-external')\n\t\t\t.end()\n\t\t\t// Add `tabindex=0` to all interactive elements which don't have it.\n\t\t\t.find('a,link,button,input,select,textarea')\n\t\t\t.not('[tabindex]')\n\t\t\t.attr('tabindex', 0);\n\n\t\t// Handle autosaves.\n\t\tswitch (typeof Config.saves.autosave) {\n\t\tcase 'boolean':\n\t\t\tif (Config.saves.autosave) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'object':\n\t\t\tif (passage.tags.some(tag => Config.saves.autosave.includes(tag))) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'function':\n\t\t\tif (Config.saves.autosave()) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// Execute post-play events.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passageend',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\n\t\t// Reset the engine state.\n\t\t_state = States.Idle;\n\n\t\t// Update the last play time.\n\t\t_lastPlay = Util.now();\n\n\t\treturn passageEl;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tLegacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Play the given passage, optionally without altering the history.\n\t*/\n\tfunction engineDisplay(title, link, option) {\n\t\tif (DEBUG) { console.log('[Engine/engineDisplay()]'); }\n\n\t\tlet noHistory = false;\n\n\t\t// Process the option parameter.\n\t\tswitch (option) {\n\t\tcase undefined:\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'replace':\n\t\tcase 'back':\n\t\t\tnoHistory = true;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new Error(`Engine.display option parameter called with obsolete value \"${option}\"; please notify the developer`);\n\t\t}\n\n\t\tenginePlay(title, noHistory);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _hideOutlines() {\n\t\t_outlinePatch.set('*:focus{outline:none;}');\n\t}\n\n\tfunction _showOutlines() {\n\t\t_outlinePatch.clear();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tConstants.\n\t\t*/\n\t\tStates            : { value : States },\n\t\tminDomActionDelay : { value : minDomActionDelay },\n\n\t\t/*\n\t\t\tCore Functions.\n\t\t*/\n\t\tinit        : { value : engineInit },\n\t\tstart       : { value : engineStart },\n\t\trestart     : { value : engineRestart },\n\t\tstate       : { get : engineState },\n\t\tisIdle      : { value : engineIsIdle },\n\t\tisPlaying   : { value : engineIsPlaying },\n\t\tisRendering : { value : engineIsRendering },\n\t\tlastPlay    : { get : engineLastPlay },\n\t\tgoTo        : { value : engineGoTo },\n\t\tgo          : { value : engineGo },\n\t\tbackward    : { value : engineBackward },\n\t\tforward     : { value : engineForward },\n\t\tshow        : { value : engineShow },\n\t\tplay        : { value : enginePlay },\n\n\t\t/*\n\t\t\tLegacy Functions.\n\t\t*/\n\t\tdisplay : { value : engineDisplay }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tpassage.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, L10n, Util, Wikifier */\n\nvar Passage = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tlet _tagsToSkip;\n\tlet _twine1Unescape;\n\n\t/*\n\t\tTags which should not be transformed into classes:\n\t\t\tdebug      → special tag\n\t\t\tnobr       → special tag\n\t\t\tpassage    → the default class\n\t\t\tscript     → special tag (only in Twine 1)\n\t\t\tstylesheet → special tag (only in Twine 1)\n\t\t\ttwine.*    → special tag\n\t\t\twidget     → special tag\n\t*/\n\t// For Twine 1\n\tif (TWINE1) {\n\t\t_tagsToSkip = /^(?:debug|nobr|passage|script|stylesheet|widget|twine\\..*)$/i;\n\t}\n\t// For Twine 2\n\telse {\n\t\t_tagsToSkip = /^(?:debug|nobr|passage|widget|twine\\..*)$/i;\n\t}\n\n\t// For Twine 1\n\tif (TWINE1) {\n\t\t/*\n\t\t\tReturns a decoded version of the passed Twine 1 passage store encoded string.\n\t\t*/\n\t\tconst _twine1EscapesRe    = /(?:\\\\n|\\\\t|\\\\s|\\\\|\\r)/g;\n\t\tconst _hasTwine1EscapesRe = new RegExp(_twine1EscapesRe.source); // to drop the global flag\n\t\tconst _twine1EscapesMap   = Object.freeze({\n\t\t\t'\\\\n' : '\\n',\n\t\t\t'\\\\t' : '\\t',\n\t\t\t'\\\\s' : '\\\\',\n\t\t\t'\\\\'  : '\\\\',\n\t\t\t'\\r'  : ''\n\t\t});\n\n\t\t_twine1Unescape = function (str) {\n\t\t\tif (str == null) { // lazy equality for null\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tconst val = String(str);\n\t\t\treturn val && _hasTwine1EscapesRe.test(val)\n\t\t\t\t? val.replace(_twine1EscapesRe, esc => _twine1EscapesMap[esc])\n\t\t\t\t: val;\n\t\t};\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPassage Class.\n\t*******************************************************************************************************************/\n\tclass Passage {\n\t\tconstructor(title, el) {\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// Passage title/ID.\n\t\t\t\ttitle : {\n\t\t\t\t\tvalue : Util.unescape(title)\n\t\t\t\t},\n\n\t\t\t\t// Passage data element (within the story data element; i.e. T1: '[tiddler]', T2: 'tw-passagedata').\n\t\t\t\telement : {\n\t\t\t\t\tvalue : el || null\n\t\t\t\t},\n\n\t\t\t\t// Passage tags array (sorted and unique).\n\t\t\t\ttags : {\n\t\t\t\t\tvalue : Object.freeze(el && el.hasAttribute('tags')\n\t\t\t\t\t\t? el.getAttribute('tags')\n\t\t\t\t\t\t\t.trim()\n\t\t\t\t\t\t\t.splitOrEmpty(/\\s+/)\n\t\t\t\t\t\t\t.sort()\n\t\t\t\t\t\t\t.filter((tag, i, aref) => i === 0 || aref[i - 1] !== tag)\n\t\t\t\t\t\t: [])\n\t\t\t\t},\n\n\t\t\t\t// Passage excerpt.  Used by the `description()` method.\n\t\t\t\t_excerpt : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Properties dependant upon the above set.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// Passage DOM-compatible ID.\n\t\t\t\tdomId : {\n\t\t\t\t\tvalue : `passage-${Util.slugify(this.title)}`\n\t\t\t\t},\n\n\t\t\t\t// Passage classes array (sorted and unique).\n\t\t\t\tclasses : {\n\t\t\t\t\tvalue : Object.freeze(this.tags.length === 0 ? [] : (() =>\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tReturn the sorted list of unique classes.\n\n\t\t\t\t\t\t\tNOTE: The `this.tags` array is already sorted and unique,\n\t\t\t\t\t\t\tso we only need to filter and map here.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tthis.tags\n\t\t\t\t\t\t\t.filter(tag => !_tagsToSkip.test(tag))\n\t\t\t\t\t\t\t.map(tag => Util.slugify(tag))\n\t\t\t\t\t)())\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// Getters.\n\t\tget className() {\n\t\t\treturn this.classes.join(' ');\n\t\t}\n\n\t\t// TODO: (v3) This should be → `get source`.\n\t\tget text() {\n\t\t\tif (this.element == null) { // lazy equality for null\n\t\t\t\tconst passage = Util.escape(this.title);\n\t\t\t\tconst mesg    = `${L10n.get('errorTitle')}: ${L10n.get('errorNonexistentPassage', { passage })}`;\n\t\t\t\treturn `<div class=\"error-view\"><span class=\"error\">${mesg}</span></div>`;\n\t\t\t}\n\n\t\t\t// For Twine 1\n\t\t\tif (TWINE1) {\n\t\t\t\treturn _twine1Unescape(this.element.textContent);\n\t\t\t}\n\t\t\t// For Twine 2\n\t\t\telse { // eslint-disable-line no-else-return\n\t\t\t\treturn this.element.textContent.replace(/\\r/g, '');\n\t\t\t}\n\t\t}\n\n\t\tdescription() {\n\t\t\tconst descriptions = Config.passages.descriptions;\n\n\t\t\tif (descriptions != null) { // lazy equality for null\n\t\t\t\tswitch (typeof descriptions) {\n\t\t\t\tcase 'boolean':\n\t\t\t\t\tif (descriptions) {\n\t\t\t\t\t\treturn this.title;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\tif (descriptions instanceof Map && descriptions.has(this.title)) {\n\t\t\t\t\t\treturn descriptions.get(this.title);\n\t\t\t\t\t}\n\t\t\t\t\telse if (descriptions.hasOwnProperty(this.title)) {\n\t\t\t\t\t\treturn descriptions[this.title];\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'function':\n\t\t\t\t\t{\n\t\t\t\t\t\tconst result = descriptions.call(this);\n\n\t\t\t\t\t\tif (result) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new TypeError('Config.passages.descriptions must be a boolean, object, or function');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Initialize the excerpt cache from the raw passage text, if necessary.\n\t\t\tif (this._excerpt === null) {\n\t\t\t\tthis._excerpt = Passage.getExcerptFromText(this.text);\n\t\t\t}\n\n\t\t\treturn this._excerpt;\n\t\t}\n\n\t\t// TODO: (v3) This should be → `get text`.\n\t\tprocessText() {\n\t\t\tif (this.element == null) { // lazy equality for null\n\t\t\t\treturn this.text;\n\t\t\t}\n\n\t\t\t// Handle image passage transclusion.\n\t\t\tif (this.tags.includes('Twine.image')) {\n\t\t\t\treturn `[img[${this.text}]]`;\n\t\t\t}\n\n\t\t\tlet processed = this.text;\n\n\t\t\t// Handle `Config.passages.onProcess`.\n\t\t\tif (Config.passages.onProcess) {\n\t\t\t\tprocessed = Config.passages.onProcess.call(null, {\n\t\t\t\t\ttitle : this.title,\n\t\t\t\t\ttags  : this.tags,\n\t\t\t\t\ttext  : processed\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Handle `Config.passages.nobr` and the `nobr` tag.\n\t\t\tif (Config.passages.nobr || this.tags.includes('nobr')) {\n\t\t\t\t// Remove all leading & trailing newlines and compact all internal sequences\n\t\t\t\t// of newlines into single spaces.\n\t\t\t\tprocessed = processed.replace(/^\\n+|\\n+$/g, '').replace(/\\n+/g, ' ');\n\t\t\t}\n\n\t\t\treturn processed;\n\t\t}\n\n\t\trender(options) {\n\t\t\t// Wikify the passage into a document fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, this.processText(), options);\n\n\t\t\t// Update the excerpt cache to reflect the rendered text, if we need it for the passage description\n\t\t\tif (Config.passages.descriptions == null) {\n\t\t\t\tthis._excerpt = Passage.getExcerptFromNode(frag);\n\t\t\t}\n\n\t\t\treturn frag;\n\t\t}\n\n\t\tstatic getExcerptFromNode(node, count) {\n\t\t\tif (!node.hasChildNodes()) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tlet excerpt = node.textContent.trim();\n\n\t\t\tif (excerpt !== '') {\n\t\t\t\tconst excerptRe = new RegExp(`(\\\\S+(?:\\\\s+\\\\S+){0,${count > 0 ? count - 1 : 7}})`);\n\t\t\t\texcerpt = excerpt\n\t\t\t\t\t// Compact whitespace.\n\t\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t\t// Attempt to match the excerpt regexp.\n\t\t\t\t\t.match(excerptRe);\n\t\t\t}\n\n\t\t\treturn excerpt ? `${excerpt[1]}\\u2026` : '\\u2026'; // horizontal ellipsis\n\t\t}\n\n\t\tstatic getExcerptFromText(text, count) {\n\t\t\tif (text === '') {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tconst excerptRe = new RegExp(`(\\\\S+(?:\\\\s+\\\\S+){0,${count > 0 ? count - 1 : 7}})`);\n\t\t\tconst excerpt   = text\n\t\t\t\t// Strip macro tags (replace with a space).\n\t\t\t\t.replace(/<<.*?>>/g, ' ')\n\t\t\t\t// Strip html tags (replace with a space).\n\t\t\t\t.replace(/<.*?>/g, ' ')\n\t\t\t\t// The above might have left problematic whitespace, so trim.\n\t\t\t\t.trim()\n\t\t\t\t// Strip table markup.\n\t\t\t\t.replace(/^\\s*\\|.*\\|.*?$/gm, '')\n\t\t\t\t// Strip image markup.\n\t\t\t\t.replace(/\\[[<>]?img\\[[^\\]]*\\]\\]/g, '')\n\t\t\t\t// Clean link markup (remove all but the link text).\n\t\t\t\t.replace(/\\[\\[([^|\\]]*?)(?:(?:\\||->|<-)[^\\]]*)?\\]\\]/g, '$1')\n\t\t\t\t// Clean heading markup.\n\t\t\t\t.replace(/^\\s*!+(.*?)$/gm, '$1')\n\t\t\t\t// Clean bold/italic/underline/highlight styles.\n\t\t\t\t.replace(/'{2}|\\/{2}|_{2}|@{2}/g, '')\n\t\t\t\t// A final trim.\n\t\t\t\t.trim()\n\t\t\t\t// Compact whitespace.\n\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t// Attempt to match the excerpt regexp.\n\t\t\t\t.match(excerptRe);\n\t\t\treturn excerpt ? `${excerpt[1]}\\u2026` : '\\u2026'; // horizontal ellipsis\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Passage;\n})();\n\n/***********************************************************************************************************************\n\n\tsave.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Dialog, Engine, L10n, State, Story, UI, storage */\n\nvar Save = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// The upper bound of the saves slots.\n\tlet _slotsUBound = -1;\n\n\n\t/*******************************************************************************************************************\n\t\tSaves Functions.\n\t*******************************************************************************************************************/\n\tfunction savesInit() {\n\t\tif (DEBUG) { console.log('[Save/savesInit()]'); }\n\n\t\t// Disable save slots and the autosave when Web Storage is unavailable.\n\t\tif (storage.name === 'cookie') {\n\t\t\tsavesObjClear();\n\t\t\tConfig.saves.autoload = undefined;\n\t\t\tConfig.saves.autosave = undefined;\n\t\t\tConfig.saves.slots = 0;\n\t\t\treturn false;\n\t\t}\n\n\t\tlet saves   = savesObjGet();\n\t\tlet updated = false;\n\n\t\t/* legacy */\n\t\t// Convert an ancient saves array into a new saves object.\n\t\tif (Array.isArray(saves)) {\n\t\t\tsaves = {\n\t\t\t\tautosave : null,\n\t\t\t\tslots    : saves\n\t\t\t};\n\t\t\tupdated = true;\n\t\t}\n\t\t/* /legacy */\n\n\t\t// Handle the author changing the number of save slots.\n\t\tif (Config.saves.slots !== saves.slots.length) {\n\t\t\tif (Config.saves.slots < saves.slots.length) {\n\t\t\t\t// Attempt to decrease the number of slots; this will only compact\n\t\t\t\t// the slots array, by removing empty slots, no saves will be deleted.\n\t\t\t\tsaves.slots.reverse();\n\n\t\t\t\tsaves.slots = saves.slots.filter(function (val) {\n\t\t\t\t\tif (val === null && this.count > 0) {\n\t\t\t\t\t\t--this.count;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\t\t\t\t}, { count : saves.slots.length - Config.saves.slots });\n\n\t\t\t\tsaves.slots.reverse();\n\t\t\t}\n\t\t\telse if (Config.saves.slots > saves.slots.length) {\n\t\t\t\t// Attempt to increase the number of slots.\n\t\t\t\t_appendSlots(saves.slots, Config.saves.slots - saves.slots.length);\n\t\t\t}\n\n\t\t\tupdated = true;\n\t\t}\n\n\t\t/* legacy */\n\t\t// Update saves with old/obsolete properties.\n\t\tif (_savesObjUpdate(saves.autosave)) {\n\t\t\tupdated = true;\n\t\t}\n\n\t\tfor (let i = 0; i < saves.slots.length; ++i) {\n\t\t\tif (_savesObjUpdate(saves.slots[i])) {\n\t\t\t\tupdated = true;\n\t\t\t}\n\t\t}\n\n\t\t// Remove save stores which are empty.\n\t\tif (_savesObjIsEmpty(saves)) {\n\t\t\tstorage.delete('saves');\n\t\t\tupdated = false;\n\t\t}\n\t\t/* /legacy */\n\n\t\t// If the saves object was updated, then update the store.\n\t\tif (updated) {\n\t\t\t_savesObjSave(saves);\n\t\t}\n\n\t\t_slotsUBound = saves.slots.length - 1;\n\n\t\treturn true;\n\t}\n\n\tfunction savesObjCreate() {\n\t\treturn {\n\t\t\tautosave : null,\n\t\t\tslots    : _appendSlots([], Config.saves.slots)\n\t\t};\n\t}\n\n\tfunction savesObjGet() {\n\t\tconst saves = storage.get('saves');\n\t\treturn saves === null ? savesObjCreate() : saves;\n\t}\n\n\tfunction savesObjClear() {\n\t\tstorage.delete('saves');\n\t\treturn true;\n\t}\n\n\tfunction savesOk() {\n\t\treturn autosaveOk() || slotsOk();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAutosave Functions.\n\t*******************************************************************************************************************/\n\tfunction autosaveOk() {\n\t\treturn storage.name !== 'cookie' && typeof Config.saves.autosave !== 'undefined';\n\t}\n\n\tfunction autosaveHas() {\n\t\tconst saves = savesObjGet();\n\n\t\tif (saves.autosave === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction autosaveGet() {\n\t\tconst saves = savesObjGet();\n\t\treturn saves.autosave;\n\t}\n\n\tfunction autosaveLoad() {\n\t\tconst saves = savesObjGet();\n\n\t\tif (saves.autosave === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn _unmarshal(saves.autosave);\n\t}\n\n\tfunction autosaveSave(title, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves        = savesObjGet();\n\t\tconst supplemental = {\n\t\t\ttitle : title || Story.get(State.passage).description(),\n\t\t\tdate  : Date.now()\n\t\t};\n\n\t\tif (metadata != null) { // lazy equality for null\n\t\t\tsupplemental.metadata = metadata;\n\t\t}\n\n\t\tsaves.autosave = _marshal(supplemental);\n\n\t\treturn _savesObjSave(saves);\n\t}\n\n\tfunction autosaveDelete() {\n\t\tconst saves = savesObjGet();\n\t\tsaves.autosave = null;\n\t\treturn _savesObjSave(saves);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSlots Functions.\n\t*******************************************************************************************************************/\n\tfunction slotsOk() {\n\t\treturn storage.name !== 'cookie' && _slotsUBound !== -1;\n\t}\n\n\tfunction slotsLength() {\n\t\treturn _slotsUBound + 1;\n\t}\n\n\tfunction slotsCount() {\n\t\tif (!slotsOk()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\t\tlet count = 0;\n\n\t\tfor (let i = 0, iend = saves.slots.length; i < iend; ++i) {\n\t\t\tif (saves.slots[i] !== null) {\n\t\t\t\t++count;\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n\n\tfunction slotsIsEmpty() {\n\t\treturn slotsCount() === 0;\n\t}\n\n\tfunction slotsHas(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length || saves.slots[slot] === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction slotsGet(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn saves.slots[slot];\n\t}\n\n\tfunction slotsLoad(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length || saves.slots[slot] === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn _unmarshal(saves.slots[slot]);\n\t}\n\n\tfunction slotsSave(slot, title, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst supplemental = {\n\t\t\ttitle : title || Story.get(State.passage).description(),\n\t\t\tdate  : Date.now()\n\t\t};\n\n\t\tif (metadata != null) { // lazy equality for null\n\t\t\tsupplemental.metadata = metadata;\n\t\t}\n\n\t\tsaves.slots[slot] = _marshal(supplemental);\n\n\t\treturn _savesObjSave(saves);\n\t}\n\n\tfunction slotsDelete(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tsaves.slots[slot] = null;\n\t\treturn _savesObjSave(saves);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tDisk Import/Export Functions.\n\t*******************************************************************************************************************/\n\tfunction exportToDisk(filename, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tfunction datestamp() {\n\t\t\tconst now = new Date();\n\t\t\tlet MM = now.getMonth() + 1;\n\t\t\tlet DD = now.getDate();\n\t\t\tlet hh = now.getHours();\n\t\t\tlet mm = now.getMinutes();\n\t\t\tlet ss = now.getSeconds();\n\n\t\t\tif (MM < 10) { MM = `0${MM}`; }\n\t\t\tif (DD < 10) { DD = `0${DD}`; }\n\t\t\tif (hh < 10) { hh = `0${hh}`; }\n\t\t\tif (mm < 10) { mm = `0${mm}`; }\n\t\t\tif (ss < 10) { ss = `0${ss}`; }\n\n\t\t\treturn `${now.getFullYear()}${MM}${DD}-${hh}${mm}${ss}`;\n\t\t}\n\n\t\tfunction legalizeName(str) {\n\t\t\t/*\n\t\t\t\tNOTE: The range of illegal characters consists of: C0 controls, double quote,\n\t\t\t\tnumber, dollar, percent, ampersand, single quote, asterisk, plus, comma,\n\t\t\t\tforward slash, colon, semi-colon, less-than, equals, greater-than, question,\n\t\t\t\tbackslash, caret, backquote/grave, pipe/vertical-bar, delete, C1 controls.\n\t\t\t*/\n\t\t\treturn String(str).trim()\n\t\t\t\t.replace(/[\\x00-\\x1f\"#$%&'*+,/:;<=>?\\\\^`|\\x7f-\\x9f]+/g, '') // eslint-disable-line no-control-regex\n\t\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-'); // legacy\n\t\t}\n\n\t\tconst baseName     = filename == null ? Story.domId : legalizeName(filename); // lazy equality for null\n\t\tconst saveName     = `${baseName}-${datestamp()}.save`;\n\t\tconst supplemental = metadata == null ? {} : { metadata }; // lazy equality for null\n\t\tconst saveObj      = LZString.compressToBase64(JSON.stringify(_marshal(supplemental)));\n\t\tsaveAs(new Blob([saveObj], { type : 'text/plain;charset=UTF-8' }), saveName);\n\t}\n\n\tfunction importFromDisk(event) {\n\t\tconst file   = event.target.files[0];\n\t\tconst reader = new FileReader();\n\n\t\t// Add the handler that will capture the file information once the load is finished.\n\t\tjQuery(reader).on('load', ev => {\n\t\t\tconst target = ev.currentTarget;\n\n\t\t\tif (!target.result) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet saveObj;\n\n\t\t\ttry {\n\t\t\t\tsaveObj = JSON.parse(\n\t\t\t\t\t/* legacy */ /\\.json$/i.test(file.name) || /^\\{/.test(target.result)\n\t\t\t\t\t\t? target.result\n\t\t\t\t\t\t: /* /legacy */ LZString.decompressFromBase64(target.result)\n\t\t\t\t);\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op; `_unmarshal()` will handle the error */ }\n\n\t\t\t_unmarshal(saveObj);\n\t\t});\n\n\t\t// Initiate the file load.\n\t\treader.readAsText(file);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSerialization Functions.\n\t*******************************************************************************************************************/\n\tfunction serialize(metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tconst supplemental = metadata == null ? {} : { metadata }; // lazy equality for null\n\t\treturn LZString.compressToBase64(JSON.stringify(_marshal(supplemental)));\n\t}\n\n\tfunction deserialize(base64Str) {\n\t\t/*\n\t\t\tNOTE: We purposefully do not attempt to catch parameter shenanigans\n\t\t\there, instead relying on `_unmarshal()` to do the heavy lifting.\n\t\t*/\n\n\t\tlet saveObj;\n\n\t\ttry {\n\t\t\tsaveObj = JSON.parse(LZString.decompressFromBase64(base64Str));\n\t\t}\n\t\tcatch (ex) { /* no-op; `_unmarshal()` will handle the error */ }\n\n\t\tif (!_unmarshal(saveObj)) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn saveObj.metadata;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _appendSlots(array, num) {\n\t\tfor (let i = 0; i < num; ++i) {\n\t\t\tarray.push(null);\n\t\t}\n\n\t\treturn array;\n\t}\n\n\tfunction _savesObjIsEmpty(saves) {\n\t\tconst slots = saves.slots;\n\t\tlet isSlotsEmpty = true;\n\n\t\tfor (let i = 0, iend = slots.length; i < iend; ++i) {\n\t\t\tif (slots[i] !== null) {\n\t\t\t\tisSlotsEmpty = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn saves.autosave === null && isSlotsEmpty;\n\t}\n\n\tfunction _savesObjSave(saves) {\n\t\tif (_savesObjIsEmpty(saves)) {\n\t\t\tstorage.delete('saves');\n\t\t\treturn true;\n\t\t}\n\n\t\treturn storage.set('saves', saves);\n\t}\n\n\tfunction _savesObjUpdate(saveObj) {\n\t\tif (saveObj == null || typeof saveObj !== 'object') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tlet updated = false;\n\n\t\t/* eslint-disable no-param-reassign */\n\t\tif (\n\t\t\t   !saveObj.hasOwnProperty('state')\n\t\t\t|| !saveObj.state.hasOwnProperty('delta')\n\t\t\t|| !saveObj.state.hasOwnProperty('index')\n\t\t) {\n\t\t\tif (saveObj.hasOwnProperty('data')) {\n\t\t\t\tdelete saveObj.mode;\n\t\t\t\tsaveObj.state = {\n\t\t\t\t\tdelta : State.deltaEncode(saveObj.data)\n\t\t\t\t};\n\t\t\t\tdelete saveObj.data;\n\t\t\t}\n\t\t\telse if (!saveObj.state.hasOwnProperty('delta')) {\n\t\t\t\tdelete saveObj.state.mode;\n\t\t\t\tsaveObj.state.delta = State.deltaEncode(saveObj.state.history);\n\t\t\t\tdelete saveObj.state.history;\n\t\t\t}\n\t\t\telse if (!saveObj.state.hasOwnProperty('index')) {\n\t\t\t\tdelete saveObj.state.mode;\n\t\t\t}\n\n\t\t\tsaveObj.state.index = saveObj.state.delta.length - 1;\n\t\t\tupdated = true;\n\t\t}\n\n\t\tif (saveObj.state.hasOwnProperty('rseed')) {\n\t\t\tsaveObj.state.seed = saveObj.state.rseed;\n\t\t\tdelete saveObj.state.rseed;\n\n\t\t\tsaveObj.state.delta.forEach((_, i, delta) => {\n\t\t\t\tif (delta[i].hasOwnProperty('rcount')) {\n\t\t\t\t\tdelta[i].pull = delta[i].rcount;\n\t\t\t\t\tdelete delta[i].rcount;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tupdated = true;\n\t\t}\n\n\t\tif (\n\t\t\t   saveObj.state.hasOwnProperty('expired') && typeof saveObj.state.expired === 'number'\n\t\t\t||  saveObj.state.hasOwnProperty('unique')\n\t\t\t||  saveObj.state.hasOwnProperty('last')\n\t\t) {\n\t\t\tif (saveObj.state.hasOwnProperty('expired') && typeof saveObj.state.expired === 'number') {\n\t\t\t\tdelete saveObj.state.expired;\n\t\t\t}\n\n\t\t\tif (saveObj.state.hasOwnProperty('unique') || saveObj.state.hasOwnProperty('last')) {\n\t\t\t\tsaveObj.state.expired = [];\n\n\t\t\t\tif (saveObj.state.hasOwnProperty('unique')) {\n\t\t\t\t\tsaveObj.state.expired.push(saveObj.state.unique);\n\t\t\t\t\tdelete saveObj.state.unique;\n\t\t\t\t}\n\n\t\t\t\tif (saveObj.state.hasOwnProperty('last')) {\n\t\t\t\t\tsaveObj.state.expired.push(saveObj.state.last);\n\t\t\t\t\tdelete saveObj.state.last;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tupdated = true;\n\t\t}\n\t\t/* eslint-enable no-param-reassign */\n\n\t\treturn updated;\n\t}\n\n\tfunction _marshal(supplemental) {\n\t\tif (DEBUG) { console.log('[Save/_marshal()]'); }\n\n\t\tif (supplemental != null && typeof supplemental !== 'object') { // lazy equality for null\n\t\t\tthrow new Error('supplemental parameter must be an object');\n\t\t}\n\n\t\tconst saveObj = Object.assign({}, supplemental, {\n\t\t\tid    : Config.saves.id,\n\t\t\tstate : State.marshalForSave()\n\t\t});\n\n\t\tif (Config.saves.version) {\n\t\t\tsaveObj.version = Config.saves.version;\n\t\t}\n\n\t\tif (typeof Config.saves.onSave === 'function') {\n\t\t\tConfig.saves.onSave(saveObj);\n\t\t}\n\n\t\t// Delta encode the state history and delete the non-encoded property.\n\t\tsaveObj.state.delta = State.deltaEncode(saveObj.state.history);\n\t\tdelete saveObj.state.history;\n\n\t\treturn saveObj;\n\t}\n\n\tfunction _unmarshal(saveObj) {\n\t\tif (DEBUG) { console.log('[Save/_unmarshal()]'); }\n\n\t\ttry {\n\t\t\t/* eslint-disable no-param-reassign */\n\t\t\t/* legacy */\n\t\t\t// Update saves with old/obsolete properties.\n\t\t\t_savesObjUpdate(saveObj);\n\t\t\t/* /legacy */\n\n\t\t\tif (!saveObj || !saveObj.hasOwnProperty('id') || !saveObj.hasOwnProperty('state')) {\n\t\t\t\tthrow new Error(L10n.get('errorSaveMissingData'));\n\t\t\t}\n\n\t\t\t// Delta decode the state history and delete the encoded property.\n\t\t\tsaveObj.state.history = State.deltaDecode(saveObj.state.delta);\n\t\t\tdelete saveObj.state.delta;\n\n\t\t\tif (typeof Config.saves.onLoad === 'function') {\n\t\t\t\tConfig.saves.onLoad(saveObj);\n\t\t\t}\n\n\t\t\tif (saveObj.id !== Config.saves.id) {\n\t\t\t\tthrow new Error(L10n.get('errorSaveIdMismatch'));\n\t\t\t}\n\n\t\t\t// Restore the state.\n\t\t\tState.unmarshalForSave(saveObj.state); // may also throw exceptions\n\n\t\t\t// Show the active moment.\n\t\t\tEngine.show();\n\t\t\t/* eslint-enable no-param-reassign */\n\t\t}\n\t\tcatch (ex) {\n\t\t\tUI.alert(`${ex.message.toUpperFirst()}.</p><p>${L10n.get('aborting')}.`);\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tSave Functions.\n\t\t*/\n\t\tinit  : { value : savesInit },\n\t\tget   : { value : savesObjGet },\n\t\tclear : { value : savesObjClear },\n\t\tok    : { value : savesOk },\n\n\t\t/*\n\t\t\tAutosave Functions.\n\t\t*/\n\t\tautosave : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tok     : { value : autosaveOk },\n\t\t\t\thas    : { value : autosaveHas },\n\t\t\t\tget    : { value : autosaveGet },\n\t\t\t\tload   : { value : autosaveLoad },\n\t\t\t\tsave   : { value : autosaveSave },\n\t\t\t\tdelete : { value : autosaveDelete }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tSlots Functions.\n\t\t*/\n\t\tslots : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tok      : { value : slotsOk },\n\t\t\t\tlength  : { get : slotsLength },\n\t\t\t\tisEmpty : { value : slotsIsEmpty },\n\t\t\t\tcount   : { value : slotsCount },\n\t\t\t\thas     : { value : slotsHas },\n\t\t\t\tget     : { value : slotsGet },\n\t\t\t\tload    : { value : slotsLoad },\n\t\t\t\tsave    : { value : slotsSave },\n\t\t\t\tdelete  : { value : slotsDelete }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tDisk Import/Export Functions.\n\t\t*/\n\t\texport : { value : exportToDisk },\n\t\timport : { value : importFromDisk },\n\n\t\t/*\n\t\t\tSerialization Functions.\n\t\t*/\n\t\tserialize   : { value : serialize },\n\t\tdeserialize : { value : deserialize }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tsetting.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util, settings:true, storage */\n\nvar Setting = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Setting control types object (pseudo-enumeration).\n\tconst Types = Util.toEnum({\n\t\tHeader : 0,\n\t\tToggle : 1,\n\t\tList   : 2,\n\t\tRange  : 3\n\t});\n\n\t// Setting definition array.\n\tconst _definitions = [];\n\n\n\t/*******************************************************************************************************************\n\t\tSettings Functions.\n\t*******************************************************************************************************************/\n\tfunction settingsInit() {\n\t\tif (DEBUG) { console.log('[Setting/settingsInit()]'); }\n\n\t\t/* legacy */\n\t\t// Attempt to migrate an existing `options` store to `settings`.\n\t\tif (storage.has('options')) {\n\t\t\tconst old = storage.get('options');\n\n\t\t\tif (old !== null) {\n\t\t\t\twindow.SugarCube.settings = settings = Object.assign(settingsCreate(), old);\n\t\t\t}\n\n\t\t\tsettingsSave();\n\t\t\tstorage.delete('options');\n\t\t}\n\t\t/* /legacy */\n\n\t\t// Load existing settings.\n\t\tsettingsLoad();\n\n\t\t// Execute `onInit` callbacks.\n\t\t_definitions.forEach(def => {\n\t\t\tif (def.hasOwnProperty('onInit')) {\n\t\t\t\tconst thisArg = {\n\t\t\t\t\tname    : def.name,\n\t\t\t\t\tvalue   : settings[def.name],\n\t\t\t\t\tdefault : def.default\n\t\t\t\t};\n\n\t\t\t\tif (def.hasOwnProperty('list')) {\n\t\t\t\t\tthisArg.list = def.list;\n\t\t\t\t}\n\n\t\t\t\tdef.onInit.call(thisArg);\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction settingsCreate() {\n\t\treturn Object.create(null);\n\t}\n\n\tfunction settingsSave() {\n\t\tconst savedSettings = settingsCreate();\n\n\t\tif (Object.keys(settings).length > 0) {\n\t\t\t_definitions\n\t\t\t\t.filter(def => def.type !== Types.Header && settings[def.name] !== def.default)\n\t\t\t\t.forEach(def => savedSettings[def.name] = settings[def.name]);\n\t\t}\n\n\t\tif (Object.keys(savedSettings).length === 0) {\n\t\t\tstorage.delete('settings');\n\t\t\treturn true;\n\t\t}\n\n\t\treturn storage.set('settings', savedSettings);\n\t}\n\n\tfunction settingsLoad() {\n\t\tconst defaultSettings = settingsCreate();\n\t\tconst loadedSettings  = storage.get('settings') || settingsCreate();\n\n\t\t// Load the defaults.\n\t\t_definitions\n\t\t\t.filter(def => def.type !== Types.Header)\n\t\t\t.forEach(def => defaultSettings[def.name] = def.default);\n\n\t\t// Assign to the `settings` object while overwriting the defaults with the loaded settings.\n\t\twindow.SugarCube.settings = settings = Object.assign(defaultSettings, loadedSettings);\n\t}\n\n\tfunction settingsClear() {\n\t\twindow.SugarCube.settings = settings = settingsCreate();\n\t\tstorage.delete('settings');\n\t\treturn true;\n\t}\n\n\tfunction settingsReset(name) {\n\t\tif (arguments.length === 0) {\n\t\t\tsettingsClear();\n\t\t\tsettingsLoad();\n\t\t}\n\t\telse {\n\t\t\tif (name == null || !definitionsHas(name)) { // lazy equality for null\n\t\t\t\tthrow new Error(`nonexistent setting \"${name}\"`);\n\t\t\t}\n\n\t\t\tconst def = definitionsGet(name);\n\n\t\t\tif (def.type !== Types.Header) {\n\t\t\t\tsettings[name] = def.default;\n\t\t\t}\n\t\t}\n\n\t\treturn settingsSave();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tDefinitions Functions.\n\t*******************************************************************************************************************/\n\tfunction definitionsForEach(callback, thisArg) {\n\t\t_definitions.forEach(callback, thisArg);\n\t}\n\n\tfunction definitionsAdd(type, name, def) {\n\t\tif (arguments.length < 3) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('type'); }\n\t\t\tif (arguments.length < 2) { errors.push('name'); }\n\t\t\tif (arguments.length < 3) { errors.push('definition'); }\n\t\t\tthrow new Error(`missing parameters, no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tif (typeof def !== 'object') {\n\t\t\tthrow new TypeError('definition parameter must be an object');\n\t\t}\n\n\t\tif (definitionsHas(name)) {\n\t\t\tthrow new Error(`cannot clobber existing setting \"${name}\"`);\n\t\t}\n\n\t\t/*\n\t\t\tDefinition object properties and types:\n\t\t\t\ttype      →  (all)   → Setting.Types\n\t\t\t\tname      →  (all)   → string\n\t\t\t\tlabel     →  (all)   → string\n\t\t\t\tdesc      →  (all)   → string\n\t\t\t\tdefault\n\t\t\t\t\t(if defined)\n \t\t\t\t\t\t  →  Toggle  → boolean\n\t\t\t\t\t\t  →  List    → Array\n\t\t\t\t\t\t  →  Range   → number\n\t\t\t\t\t(if undefined)\n\t\t\t\t\t\t  →  Toggle  → false\n\t\t\t\t\t\t  →  List    → list[0]\n\t\t\t\t\t\t  →  Range   → max\n\t\t\t\tlist      →  List    → Array\n\t\t\t\tmin       →  Range   → number\n\t\t\t\tmax       →  Range   → number\n\t\t\t\tstep      →  Range   → number\n\t\t\t\tonInit    →  (all)   → function\n\t\t\t\tonChange  →  (all)   → function\n\t\t*/\n\t\tconst definition = {\n\t\t\ttype,\n\t\t\tname,\n\t\t\tlabel : typeof def.label === 'string' ? def.label.trim() : ''\n\t\t};\n\n\t\tif (typeof def.desc === 'string') {\n\t\t\tconst desc = def.desc.trim();\n\n\t\t\tif (desc !== '') {\n\t\t\t\tdefinition.desc = desc;\n\t\t\t}\n\t\t}\n\n\t\tswitch (type) {\n\t\tcase Types.Header:\n\t\t\tbreak;\n\n\t\tcase Types.Toggle:\n\t\t\tdefinition.default = !!def.default;\n\t\t\tbreak;\n\n\t\tcase Types.List:\n\t\t\tif (!def.hasOwnProperty('list')) {\n\t\t\t\tthrow new Error('no list specified');\n\t\t\t}\n\t\t\telse if (!Array.isArray(def.list)) {\n\t\t\t\tthrow new TypeError('list must be an array');\n\t\t\t}\n\t\t\telse if (def.list.length === 0) {\n\t\t\t\tthrow new Error('list must not be empty');\n\t\t\t}\n\n\t\t\tdefinition.list = Object.freeze(def.list);\n\n\t\t\tif (def.default == null) { // lazy equality for null\n\t\t\t\tdefinition.default = def.list[0];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst defaultIndex = def.list.indexOf(def.default);\n\n\t\t\t\tif (defaultIndex === -1) {\n\t\t\t\t\tthrow new Error('list does not contain default');\n\t\t\t\t}\n\n\t\t\t\tdefinition.default = def.list[defaultIndex];\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase Types.Range:\n\t\t\tif (!def.hasOwnProperty('min')) {\n\t\t\t\tthrow new Error('no min specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.min !== 'number'\n\t\t\t\t|| Number.isNaN(def.min)\n\t\t\t\t|| !Number.isFinite(def.min)\n\t\t\t) {\n\t\t\t\tthrow new TypeError('min must be a finite number');\n\t\t\t}\n\n\t\t\tif (!def.hasOwnProperty('max')) {\n\t\t\t\tthrow new Error('no max specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.max !== 'number'\n\t\t\t\t|| Number.isNaN(def.max)\n\t\t\t\t|| !Number.isFinite(def.max)\n\t\t\t) {\n\t\t\t\tthrow new TypeError('max must be a finite number');\n\t\t\t}\n\n\t\t\tif (!def.hasOwnProperty('step')) {\n\t\t\t\tthrow new Error('no step specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.step !== 'number'\n\t\t\t\t|| Number.isNaN(def.step)\n\t\t\t\t|| !Number.isFinite(def.step)\n\t\t\t\t|| def.step <= 0\n\t\t\t) {\n\t\t\t\tthrow new TypeError('step must be a finite number greater than zero');\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Determine how many fractional digits we need to be concerned with based on the step value.\n\t\t\t\tconst fracDigits = (() => {\n\t\t\t\t\tconst str = String(def.step);\n\t\t\t\t\tconst pos = str.lastIndexOf('.');\n\t\t\t\t\treturn pos === -1 ? 0 : str.length - pos - 1;\n\t\t\t\t})();\n\n\t\t\t\t// Set up a function to validate a given value against the step value.\n\t\t\t\tfunction stepValidate(value) {\n\t\t\t\t\tif (fracDigits > 0) {\n\t\t\t\t\t\tconst ma = Number(`${def.min}e${fracDigits}`);\n\t\t\t\t\t\tconst sa = Number(`${def.step}e${fracDigits}`);\n\t\t\t\t\t\tconst va = Number(`${value}e${fracDigits}`) - ma;\n\t\t\t\t\t\treturn Number(`${va - va % sa + ma}e-${fracDigits}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst va = value - def.min;\n\t\t\t\t\treturn va - va % def.step + def.min;\n\t\t\t\t}\n\n\t\t\t\t// Sanity check the max value against the step value.\n\t\t\t\tif (stepValidate(def.max) !== def.max) {\n\t\t\t\t\tthrow new RangeError(`max (${def.max}) is not a multiple of the step (${def.step}) plus the min (${def.min})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdefinition.max = def.max;\n\t\t\tdefinition.min = def.min;\n\t\t\tdefinition.step = def.step;\n\n\t\t\tif (def.default == null) { // lazy equality for null\n\t\t\t\tdefinition.default = def.max;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (\n\t\t\t\t\t   typeof def.default !== 'number'\n\t\t\t\t\t|| Number.isNaN(def.default)\n\t\t\t\t\t|| !Number.isFinite(def.default)\n\t\t\t\t) {\n\t\t\t\t\tthrow new TypeError('default must be a finite number');\n\t\t\t\t}\n\t\t\t\telse if (def.default < def.min) {\n\t\t\t\t\tthrow new RangeError(`default (${def.default}) is less than min (${def.min})`);\n\t\t\t\t}\n\t\t\t\telse if (def.default > def.max) {\n\t\t\t\t\tthrow new RangeError(`default (${def.default}) is greater than max (${def.max})`);\n\t\t\t\t}\n\n\t\t\t\tdefinition.default = def.default;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new Error(`unknown Setting type: ${type}`);\n\t\t}\n\n\t\tif (typeof def.onInit === 'function') {\n\t\t\tdefinition.onInit = Object.freeze(def.onInit);\n\t\t}\n\n\t\tif (typeof def.onChange === 'function') {\n\t\t\tdefinition.onChange = Object.freeze(def.onChange);\n\t\t}\n\n\t\t_definitions.push(Object.freeze(definition));\n\t}\n\n\tfunction definitionsAddHeader(name, desc) {\n\t\tdefinitionsAdd(Types.Header, name, { desc });\n\t}\n\n\tfunction definitionsAddToggle(...args) {\n\t\tdefinitionsAdd(Types.Toggle, ...args);\n\t}\n\n\tfunction definitionsAddList(...args) {\n\t\tdefinitionsAdd(Types.List, ...args);\n\t}\n\n\tfunction definitionsAddRange(...args) {\n\t\tdefinitionsAdd(Types.Range, ...args);\n\t}\n\n\tfunction definitionsIsEmpty() {\n\t\treturn _definitions.length === 0;\n\t}\n\n\tfunction definitionsHas(name) {\n\t\treturn _definitions.some(definition => definition.name === name);\n\t}\n\n\tfunction definitionsGet(name) {\n\t\treturn _definitions.find(definition => definition.name === name);\n\t}\n\n\tfunction definitionsDelete(name) {\n\t\tif (definitionsHas(name)) {\n\t\t\tdelete settings[name];\n\t\t}\n\n\t\tfor (let i = 0; i < _definitions.length; ++i) {\n\t\t\tif (_definitions[i].name === name) {\n\t\t\t\t_definitions.splice(i, 1);\n\t\t\t\tdefinitionsDelete(name);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tEnumerations.\n\t\t*/\n\t\tTypes : { value : Types },\n\n\t\t/*\n\t\t\tSettings Functions.\n\t\t*/\n\t\tinit   : { value : settingsInit },\n\t\tcreate : { value : settingsCreate },\n\t\tsave   : { value : settingsSave },\n\t\tload   : { value : settingsLoad },\n\t\tclear  : { value : settingsClear },\n\t\treset  : { value : settingsReset },\n\n\t\t/*\n\t\t\tDefinitions Functions.\n\t\t*/\n\t\tforEach   : { value : definitionsForEach },\n\t\tadd       : { value : definitionsAdd },\n\t\taddHeader : { value : definitionsAddHeader },\n\t\taddToggle : { value : definitionsAddToggle },\n\t\taddList   : { value : definitionsAddList },\n\t\taddRange  : { value : definitionsAddRange },\n\t\tisEmpty   : { value : definitionsIsEmpty },\n\t\thas       : { value : definitionsHas },\n\t\tget       : { value : definitionsGet },\n\t\tdelete    : { value : definitionsDelete }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tstory.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Alert, Config, Passage, Scripting, StyleWrapper, Util, Wikifier */\n\nvar Story = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Map of normal passages.\n\tconst _passages = {};\n\n\t// List of script passages.\n\tconst _scripts = [];\n\n\t// List of style passages.\n\tconst _styles = [];\n\n\t// List of widget passages.\n\tconst _widgets = [];\n\n\t// Story title.\n\tlet _title = '';\n\n\t// Story IFID.\n\tlet _ifId = '';\n\n\t// DOM-compatible ID.\n\tlet _domId = '';\n\n\n\t/*******************************************************************************************************************\n\t\tStory Functions.\n\t*******************************************************************************************************************/\n\tfunction storyLoad() {\n\t\tif (DEBUG) { console.log('[Story/storyLoad()]'); }\n\n\t\tconst validationCodeTags = [\n\t\t\t'widget'\n\t\t];\n\t\tconst validationNoCodeTagPassages = [\n\t\t\t'PassageDone',\n\t\t\t'PassageFooter',\n\t\t\t'PassageHeader',\n\t\t\t'PassageReady',\n\t\t\t'StoryAuthor',\n\t\t\t'StoryBanner',\n\t\t\t'StoryCaption',\n\t\t\t'StoryInit',\n\t\t\t'StoryMenu',\n\t\t\t'StoryShare',\n\t\t\t'StorySubtitle'\n\t\t];\n\n\t\tfunction validateStartingPassage(passage) {\n\t\t\tif (passage.tags.includesAny(validationCodeTags)) {\n\t\t\t\tthrow new Error(`starting passage \"${passage.title}\" contains illegal tags; invalid: \"${passage.tags.filter(tag => validationCodeTags.includes(tag)).sort().join('\", \"')}\"`);\n\t\t\t}\n\t\t}\n\n\t\tfunction validateSpecialPassages(passage) {\n\t\t\tif (validationNoCodeTagPassages.includes(passage.title) && passage.tags.includesAny(validationCodeTags)) {\n\t\t\t\tthrow new Error(`special passage \"${passage.title}\" contains illegal tags; invalid: \"${passage.tags.filter(tag => validationCodeTags.includes(tag)).sort().join('\", \"')}\"`);\n\t\t\t}\n\t\t}\n\n\t\t// For Twine 1.\n\t\tif (TWINE1) {\n\t\t\t/*\n\t\t\t\tAdditional Twine 1 validation setup.\n\t\t\t*/\n\t\t\tvalidationCodeTags.unshift('script', 'stylesheet');\n\t\t\tvalidationNoCodeTagPassages.push('StoryTitle');\n\n\t\t\tfunction validateTwine1CodePassages(passage) {\n\t\t\t\tconst codeTags  = [...validationCodeTags];\n\t\t\t\tconst foundTags = [];\n\n\t\t\t\tpassage.tags.forEach(tag => {\n\t\t\t\t\tif (codeTags.includes(tag)) {\n\t\t\t\t\t\tfoundTags.push(...codeTags.delete(tag));\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (foundTags.length > 1) {\n\t\t\t\t\tthrow new Error(`code passage \"${passage.title}\" contains multiple code tags; invalid: \"${foundTags.sort().join('\", \"')}\"`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet the default starting passage.\n\t\t\t*/\n\t\t\tConfig.passages.start = (() => {\n\t\t\t\t/*\n\t\t\t\t\tHandle the Twine 1.4+ Test Play From Here feature.\n\n\t\t\t\t\tWARNING: Do not remove the `String()` wrapper from or change the quote\n\t\t\t\t\tstyle of the `\"START_AT\"` replacement target.  The former is there to\n\t\t\t\t\tkeep UglifyJS from pruning the code into oblivion—i.e. minifying the\n\t\t\t\t\tcode into something broken.  The latter is there because the Twine 1\n\t\t\t\t\tpattern that matches it depends upon the double quotes.\n\n\t\t\t\t*/\n\t\t\t\tconst testPlay = String(\"START_AT\"); // eslint-disable-line quotes\n\n\t\t\t\tif (testPlay !== '') {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tTest play; starting passage: \"${testPlay}\"`); }\n\n\t\t\t\t\tConfig.debug = true;\n\t\t\t\t\treturn testPlay;\n\t\t\t\t}\n\n\t\t\t\t// In the absence of a `testPlay` value, return 'Start'.\n\t\t\t\treturn 'Start';\n\t\t\t})();\n\n\t\t\t/*\n\t\t\t\tProcess the passages, excluding any tagged 'Twine.private' or 'annotation'.\n\t\t\t*/\n\t\t\tjQuery('#store-area')\n\t\t\t\t.children(':not([tags~=\"Twine.private\"],[tags~=\"annotation\"])')\n\t\t\t\t.each(function () {\n\t\t\t\t\tconst $this   = jQuery(this);\n\t\t\t\t\tconst passage = new Passage($this.attr('tiddler'), this);\n\n\t\t\t\t\t// Special cases.\n\t\t\t\t\tif (passage.title === Config.passages.start) {\n\t\t\t\t\t\tvalidateStartingPassage(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('stylesheet')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_styles.push(passage);\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('script')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_scripts.push(passage);\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('widget')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_widgets.push(passage);\n\t\t\t\t\t}\n\n\t\t\t\t\t// All other passages.\n\t\t\t\t\telse {\n\t\t\t\t\t\tvalidateSpecialPassages(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tSet the story title or throw an exception.\n\t\t\t*/\n\t\t\tif (_passages.hasOwnProperty('StoryTitle')) {\n\t\t\t\tconst buf = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(buf, _passages.StoryTitle.processText().trim());\n\t\t\t\t_storySetTitle(buf.textContent);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('cannot find the \"StoryTitle\" special passage');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet the default saves ID (must be done after the call to `_storySetTitle()`).\n\t\t\t*/\n\t\t\tConfig.saves.id = Story.domId;\n\t\t}\n\n\t\t// For Twine 2.\n\t\telse {\n\t\t\tconst $storydata = jQuery('tw-storydata');\n\t\t\tconst startNode  = $storydata.attr('startnode') || '';\n\n\t\t\t/*\n\t\t\t\tSet the default starting passage.\n\t\t\t*/\n\t\t\tConfig.passages.start = null; // no default in Twine 2\n\n\t\t\t/*\n\t\t\t\tProcess story options.\n\n\t\t\t\tNOTE: Currently, the only option of interest is 'debug', so we\n\t\t\t\tsimply use a regular expression to check for it.\n\t\t\t*/\n\t\t\tConfig.debug = /\\bdebug\\b/.test($storydata.attr('options'));\n\n\t\t\t/*\n\t\t\t\tProcess stylesheet passages.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('style') // alternatively: '[type=\"text/twine-css\"]' or '#twine-user-stylesheet'\n\t\t\t\t.each(function (i) {\n\t\t\t\t\t_styles.push(new Passage(`tw-user-style-${i}`, this));\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tProcess script passages.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('script') // alternatively: '[type=\"text/twine-javascript\"]' or '#twine-user-script'\n\t\t\t\t.each(function (i) {\n\t\t\t\t\t_scripts.push(new Passage(`tw-user-script-${i}`, this));\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tProcess normal passages, excluding any tagged 'Twine.private' or 'annotation'.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('tw-passagedata:not([tags~=\"Twine.private\"],[tags~=\"annotation\"])')\n\t\t\t\t.each(function () {\n\t\t\t\t\tconst $this   = jQuery(this);\n\t\t\t\t\tconst pid     = $this.attr('pid') || '';\n\t\t\t\t\tconst passage = new Passage($this.attr('name'), this);\n\n\t\t\t\t\t// Special cases.\n\t\t\t\t\tif (pid === startNode && startNode !== '') {\n\t\t\t\t\t\tConfig.passages.start = passage.title;\n\t\t\t\t\t\tvalidateStartingPassage(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('widget')) {\n\t\t\t\t\t\t_widgets.push(passage);\n\t\t\t\t\t}\n\n\t\t\t\t\t// All other passages.\n\t\t\t\t\telse {\n\t\t\t\t\t\tvalidateSpecialPassages(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tGet the story IFID.\n\t\t\t*/\n\t\t\t_ifId = $storydata.attr('ifid');\n\n\t\t\t/*\n\t\t\t\tSet the story title.\n\n\t\t\t\tFIXME: Maybe `$storydata.attr('name')` should be used instead of `'{{STORY_NAME}}'`?\n\t\t\t*/\n\t\t\t// _storySetTitle($storydata.attr('name'));\n\t\t\t_storySetTitle('{{STORY_NAME}}');\n\n\t\t\t/*\n\t\t\t\tSet the default saves ID (must be done after the call to `_storySetTitle()`).\n\t\t\t*/\n\t\t\tConfig.saves.id = Story.domId;\n\t\t}\n\t}\n\n\tfunction storyInit() {\n\t\tif (DEBUG) { console.log('[Story/storyInit()]'); }\n\n\t\t/*\n\t\t\tAdd the story styles.\n\t\t*/\n\t\t(() => {\n\t\t\tconst storyStyle = document.createElement('style');\n\n\t\t\t(new StyleWrapper(storyStyle))\n\t\t\t\t.add(_styles.map(style => style.text.trim()).join('\\n'));\n\n\t\t\tjQuery(storyStyle)\n\t\t\t\t.appendTo(document.head)\n\t\t\t\t.attr({\n\t\t\t\t\tid   : 'style-story',\n\t\t\t\t\ttype : 'text/css'\n\t\t\t\t});\n\t\t})();\n\n\t\t/*\n\t\t\tEvaluate the story scripts.\n\t\t*/\n\t\tfor (let i = 0; i < _scripts.length; ++i) {\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(_scripts[i].text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error(_scripts[i].title, typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t\tProcess the story widgets.\n\t\t*/\n\t\tfor (let i = 0; i < _widgets.length; ++i) {\n\t\t\ttry {\n\t\t\t\tWikifier.wikifyEval(_widgets[i].processText());\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error(_widgets[i].title, typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction _storySetTitle(rawTitle) {\n\t\tif (rawTitle == null) { // lazy equality for null\n\t\t\tthrow new Error('story title must not be null or undefined');\n\t\t}\n\n\t\tconst title = Util.unescape(String(rawTitle)).trim();\n\n\t\tif (title === '') { // lazy equality for null\n\t\t\tthrow new Error('story title must not be empty or consist solely of whitespace');\n\t\t}\n\n\t\tdocument.title = _title = title;\n\n\t\t// TODO: In v3 the `_domId` should be created from a combination of the\n\t\t// `_title` slug and the IFID, if available, to avoid collisions between\n\t\t// stories whose titles generate identical slugs.\n\t\t_domId = Util.slugify(_title);\n\n\t\t// [v2] Protect the `_domId` against being an empty string.\n\t\t//\n\t\t// If `_domId` is empty, attempt a failover.\n\t\tif (_domId === '') {\n\t\t\t// If `_ifId` is not empty, then use it.\n\t\t\tif (_ifId !== '') {\n\t\t\t\t_domId = _ifId;\n\t\t\t}\n\n\t\t\t// Elsewise generate a string from the `_title`'s code points (in hexadecimal).\n\t\t\telse {\n\t\t\t\tfor (let i = 0, len = _title.length; i < len; ++i) {\n\t\t\t\t\tconst { char, start, end } = Util.charAndPosAt(_title, i);\n\t\t\t\t\t_domId += char.codePointAt(0).toString(16);\n\t\t\t\t\ti += end - start;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction storyTitle() {\n\t\treturn _title;\n\t}\n\n\tfunction storyDomId() {\n\t\treturn _domId;\n\t}\n\n\tfunction storyIfId() {\n\t\treturn _ifId;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPassage Functions.\n\t*******************************************************************************************************************/\n\tfunction passagesAdd(passage) {\n\t\tif (!(passage instanceof Passage)) {\n\t\t\tthrow new TypeError('Story.add passage parameter must be an instance of Passage');\n\t\t}\n\n\t\tconst title = passage.title;\n\n\t\tif (!_passages.hasOwnProperty(title)) {\n\t\t\t_passages[title] = passage;\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tfunction passagesHas(title) {\n\t\tlet type = typeof title;\n\n\t\tswitch (type) {\n\t\t// Valid types.\n\t\tcase 'number':\n\t\tcase 'string':\n\t\t\treturn _passages.hasOwnProperty(String(title));\n\n\t\t// Invalid types.  We do the extra processing just to make a nicer error.\n\t\tcase 'undefined':\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\ttype = title === null ? 'null' : 'an object';\n\t\t\tbreak;\n\n\t\tdefault: // 'bigint', 'boolean', 'function', 'symbol'\n\t\t\ttype = `a ${type}`;\n\t\t\tbreak;\n\t\t}\n\n\t\tthrow new TypeError(`Story.has title parameter cannot be ${type}`);\n\t}\n\n\tfunction passagesGet(title) {\n\t\tlet type = typeof title;\n\n\t\tswitch (type) {\n\t\t// Valid types.\n\t\tcase 'number':\n\t\tcase 'string':\n\t\t/* eslint-disable indent */\n\t\t\t{\n\t\t\t\tconst id = String(title);\n\t\t\t\treturn _passages.hasOwnProperty(id) ? _passages[id] : new Passage(id || '(unknown)');\n\t\t\t}\n\t\t/* eslint-enable indent */\n\n\t\t// Invalid types.  We do the extra processing just to make a nicer error.\n\t\tcase 'undefined':\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\ttype = title === null ? 'null' : 'an object';\n\t\t\tbreak;\n\n\t\tdefault: // 'bigint', 'boolean', 'function', 'symbol'\n\t\t\ttype = `a ${type}`;\n\t\t\tbreak;\n\t\t}\n\n\t\tthrow new TypeError(`Story.get title parameter cannot be ${type}`);\n\t}\n\n\tfunction passagesGetAllRegular() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Object.assign({}, _passages));\n\t}\n\n\tfunction passagesGetAllScript() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_scripts));\n\t}\n\n\tfunction passagesGetAllStylesheet() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_styles));\n\t}\n\n\tfunction passagesGetAllWidget() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_widgets));\n\t}\n\n\tfunction passagesLookup(key, value  /* legacy */, sortKey = 'title'/* /legacy */) {\n\t\tconst results = [];\n\n\t\tObject.keys(_passages).forEach(name => {\n\t\t\tconst passage = _passages[name];\n\n\t\t\t// Objects (sans `null`).\n\t\t\tif (typeof passage[key] === 'object' && passage[key] !== null) {\n\t\t\t\t// The only object type currently supported is `Array`, since the\n\t\t\t\t// non-method `Passage` object properties currently yield only either\n\t\t\t\t// primitives or arrays.\n\t\t\t\tif (passage[key] instanceof Array && passage[key].some(m => Util.sameValueZero(m, value))) {\n\t\t\t\t\tresults.push(passage);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// All other types (incl. `null`).\n\t\t\telse if (Util.sameValueZero(passage[key], value)) {\n\t\t\t\tresults.push(passage);\n\t\t\t}\n\t\t});\n\n\t\t// For v3.\n\t\t// /* eslint-disable no-nested-ternary */\n\t\t// // QUESTION: Do we really need to sort the list?\n\t\t// results.sort((a, b) => a.title === b.title ? 0 : a.title < b.title ? -1 : +1);\n\t\t// /* eslint-enable no-nested-ternary */\n\n\t\t/* legacy */\n\t\t/* eslint-disable eqeqeq, no-nested-ternary, max-len */\n\t\tresults.sort((a, b) => a[sortKey] == b[sortKey] ? 0 : a[sortKey] < b[sortKey] ? -1 : +1); // lazy equality for null\n\t\t/* eslint-enable eqeqeq, no-nested-ternary, max-len */\n\t\t/* /legacy */\n\n\t\treturn results;\n\t}\n\n\tfunction passagesLookupWith(predicate /* legacy */, sortKey = 'title'/* /legacy */) {\n\t\tif (typeof predicate !== 'function') {\n\t\t\tthrow new TypeError('Story.lookupWith predicate parameter must be a function');\n\t\t}\n\n\t\tconst results = [];\n\n\t\tObject.keys(_passages).forEach(name => {\n\t\t\tconst passage = _passages[name];\n\n\t\t\tif (predicate(passage)) {\n\t\t\t\tresults.push(passage);\n\t\t\t}\n\t\t});\n\n\t\t// For v3.\n\t\t// /* eslint-disable no-nested-ternary */\n\t\t// // QUESTION: Do we really need to sort the list?\n\t\t// results.sort((a, b) => a.title === b.title ? 0 : a.title < b.title ? -1 : +1);\n\t\t// /* eslint-enable no-nested-ternary */\n\n\t\t/* legacy */\n\t\t/* eslint-disable eqeqeq, no-nested-ternary, max-len */\n\t\tresults.sort((a, b) => a[sortKey] == b[sortKey] ? 0 : a[sortKey] < b[sortKey] ? -1 : +1); // lazy equality for null\n\t\t/* eslint-enable eqeqeq, no-nested-ternary, max-len */\n\t\t/* /legacy */\n\n\t\treturn results;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Story Functions.\n\t\tload  : { value : storyLoad },\n\t\tinit  : { value : storyInit },\n\t\ttitle : { get : storyTitle },\n\t\tdomId : { get : storyDomId },\n\t\tifId  : { get : storyIfId },\n\n\t\t// Passage Functions.\n\t\tadd              : { value : passagesAdd },\n\t\thas              : { value : passagesHas },\n\t\tget              : { value : passagesGet },\n\t\tgetAllRegular    : { value : passagesGetAllRegular },\n\t\tgetAllScript     : { value : passagesGetAllScript },\n\t\tgetAllStylesheet : { value : passagesGetAllStylesheet },\n\t\tgetAllWidget     : { value : passagesGetAllWidget },\n\t\tlookup           : { value : passagesLookup },\n\t\tlookupWith       : { value : passagesLookupWith }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tui.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Dialog, Engine, Has, L10n, Save, Setting, State, Story, Util, Wikifier, Config, errorPrologRegExp,\n\t       settings\n*/\n\nvar UI = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUI Functions, Core.\n\t*******************************************************************************************************************/\n\tfunction uiAssembleLinkList(passage, listEl) {\n\t\tlet list = listEl;\n\n\t\t// Cache the values of `Config.debug` and `Config.cleanupWikifierOutput`,\n\t\t// then disable them during this method's run.\n\t\tconst debugState = Config.debug;\n\t\tconst cleanState = Config.cleanupWikifierOutput;\n\t\tConfig.debug = false;\n\t\tConfig.cleanupWikifierOutput = false;\n\n\t\ttry {\n\t\t\tif (list == null) { // lazy equality for null\n\t\t\t\tlist = document.createElement('ul');\n\t\t\t}\n\n\t\t\t// Wikify the content of the given source passage into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, Story.get(passage).processText().trim());\n\n\t\t\t// Gather the text of any error elements within the fragment…\n\t\t\tconst errors = [...frag.querySelectorAll('.error')]\n\t\t\t\t.map(errEl => errEl.textContent.replace(errorPrologRegExp, ''));\n\n\t\t\t// …and throw an exception, if there were any errors.\n\t\t\tif (errors.length > 0) {\n\t\t\t\tthrow new Error(errors.join('; '));\n\t\t\t}\n\n\t\t\twhile (frag.hasChildNodes()) {\n\t\t\t\tconst node = frag.firstChild;\n\n\t\t\t\t// Create list items for <a>-element nodes.\n\t\t\t\tif (node.nodeType === Node.ELEMENT_NODE && node.nodeName.toUpperCase() === 'A') {\n\t\t\t\t\tconst li = document.createElement('li');\n\t\t\t\t\tlist.appendChild(li);\n\t\t\t\t\tli.appendChild(node);\n\t\t\t\t}\n\n\t\t\t\t// Discard non-<a>-element nodes.\n\t\t\t\telse {\n\t\t\t\t\tfrag.removeChild(node);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\t// Restore the `Config` settings to their original values.\n\t\t\tConfig.cleanupWikifierOutput = cleanState;\n\t\t\tConfig.debug = debugState;\n\t\t}\n\n\t\treturn list;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUI Functions, Built-ins.\n\t*******************************************************************************************************************/\n\tfunction uiOpenAlert(message, /* options, closeFn */ ...args) {\n\t\tjQuery(Dialog.setup('Alert', 'alert'))\n\t\t\t.append(\n\t\t\t\t  `<p>${message}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"alert-ok\" class=\"ui-close\">${L10n.get(['alertOk', 'ok'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t);\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenJumpto(/* options, closeFn */ ...args) {\n\t\tuiBuildJumpto();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenRestart(/* options, closeFn */ ...args) {\n\t\tuiBuildRestart();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenSaves(/* options, closeFn */ ...args) {\n\t\tuiBuildSaves();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenSettings(/* options, closeFn */ ...args) {\n\t\tuiBuildSettings();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenShare(/* options, closeFn */ ...args) {\n\t\tuiBuildShare();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiBuildAutoload() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildAutoload()]'); }\n\n\t\tjQuery(Dialog.setup(L10n.get('autoloadTitle'), 'autoload'))\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  `<p>${L10n.get('autoloadPrompt')}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"autoload-ok\" class=\"ui-close\">${L10n.get(['autoloadOk', 'ok'])}</button></li>`\n\t\t\t\t+ `<li><button id=\"autoload-cancel\" class=\"ui-close\">${L10n.get(['autoloadCancel', 'cancel'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t);\n\n\t\t// Add an additional delegated click handler for the `.ui-close` elements to handle autoloading.\n\t\tjQuery(document).one('click.autoload', '.ui-close', ev => {\n\t\t\tconst isAutoloadOk = ev.target.id === 'autoload-ok';\n\t\t\tjQuery(document).one(':dialogclosed', () => {\n\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\tif (!isAutoloadOk || !Save.autosave.load()) {\n\t\t\t\t\tEngine.play(Config.passages.start);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildJumpto() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildJumpto()]'); }\n\n\t\tconst list = document.createElement('ul');\n\n\t\tjQuery(Dialog.setup(L10n.get('jumptoTitle'), 'jumpto list'))\n\t\t\t.append(list);\n\n\t\tconst expired = State.expired.length;\n\n\t\tfor (let i = State.size - 1; i >= 0; --i) {\n\t\t\tif (i === State.activeIndex) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst passage = Story.get(State.history[i].title);\n\n\t\t\tif (passage && passage.tags.includes('bookmark')) {\n\t\t\t\tjQuery(document.createElement('li'))\n\t\t\t\t\t.append(\n\t\t\t\t\t\tjQuery(document.createElement('a'))\n\t\t\t\t\t\t\t.ariaClick({ one : true }, (function (idx) {\n\t\t\t\t\t\t\t\treturn () => jQuery(document).one(':dialogclosed', () => Engine.goTo(idx));\n\t\t\t\t\t\t\t})(i))\n\t\t\t\t\t\t\t.addClass('ui-close')\n\t\t\t\t\t\t\t.text(`${L10n.get('jumptoTurn')} ${expired + i + 1}: ${passage.description()}`)\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo(list);\n\t\t\t}\n\t\t}\n\n\t\tif (!list.hasChildNodes()) {\n\t\t\tjQuery(list).append(`<li><a><em>${L10n.get('jumptoUnavailable')}</em></a></li>`);\n\t\t}\n\t}\n\n\tfunction uiBuildRestart() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildRestart()]'); }\n\n\t\tjQuery(Dialog.setup(L10n.get('restartTitle'), 'restart'))\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  `<p>${L10n.get('restartPrompt')}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"restart-ok\">${L10n.get(['restartOk', 'ok'])}</button></li>`\n\t\t\t\t+ `<li><button id=\"restart-cancel\" class=\"ui-close\">${L10n.get(['restartCancel', 'cancel'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t)\n\t\t\t.find('#restart-ok')\n\t\t\t/*\n\t\t\t\tInstead of adding '.ui-close' to '#restart-ok' (to receive the use of the default\n\t\t\t\tdelegated dialog close handler), we set up a special case close handler here.  We\n\t\t\t\tdo this to ensure that the invocation of `Engine.restart()` happens after the dialog\n\t\t\t\thas fully closed.  If we did not, then a race condition could occur, causing display\n\t\t\t\tshenanigans.\n\t\t\t*/\n\t\t\t.ariaClick({ one : true }, () => {\n\t\t\t\tjQuery(document).one(':dialogclosed', () => Engine.restart());\n\t\t\t\tDialog.close();\n\t\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildSaves() {\n\t\tfunction createActionItem(bId, bClass, bText, bAction) {\n\t\t\tconst $btn = jQuery(document.createElement('button'))\n\t\t\t\t.attr('id', `saves-${bId}`)\n\t\t\t\t.html(bText);\n\n\t\t\tif (bClass) {\n\t\t\t\t$btn.addClass(bClass);\n\t\t\t}\n\n\t\t\tif (bAction) {\n\t\t\t\t$btn.ariaClick(bAction);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$btn.ariaDisabled(true);\n\t\t\t}\n\n\t\t\treturn jQuery(document.createElement('li'))\n\t\t\t\t.append($btn);\n\t\t}\n\n\t\tfunction createSaveList() {\n\t\t\tfunction createButton(bId, bClass, bText, bSlot, bAction) {\n\t\t\t\tconst $btn = jQuery(document.createElement('button'))\n\t\t\t\t\t.attr('id', `saves-${bId}-${bSlot}`)\n\t\t\t\t\t.addClass(bId)\n\t\t\t\t\t.html(bText);\n\n\t\t\t\tif (bClass) {\n\t\t\t\t\t$btn.addClass(bClass);\n\t\t\t\t}\n\n\t\t\t\tif (bAction) {\n\t\t\t\t\tif (bSlot === 'auto') {\n\t\t\t\t\t\t$btn.ariaClick({\n\t\t\t\t\t\t\tlabel : `${bText} ${L10n.get('savesLabelAuto')}`\n\t\t\t\t\t\t}, () => bAction());\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t$btn.ariaClick({\n\t\t\t\t\t\t\tlabel : `${bText} ${L10n.get('savesLabelSlot')} ${bSlot + 1}`\n\t\t\t\t\t\t}, () => bAction(bSlot));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$btn.ariaDisabled(true);\n\t\t\t\t}\n\n\t\t\t\treturn $btn;\n\t\t\t}\n\n\t\t\tconst saves  = Save.get();\n\t\t\tconst $tbody = jQuery(document.createElement('tbody'));\n\n\t\t\tif (Save.autosave.ok()) {\n\t\t\t\tconst $tdSlot = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdLoad = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDesc = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDele = jQuery(document.createElement('td'));\n\n\t\t\t\t// Add the slot ID.\n\t\t\t\tjQuery(document.createElement('b'))\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttitle        : L10n.get('savesLabelAuto'),\n\t\t\t\t\t\t'aria-label' : L10n.get('savesLabelAuto')\n\t\t\t\t\t})\n\t\t\t\t\t.text('A') // '\\u25C6' Black Diamond\n\t\t\t\t\t.appendTo($tdSlot);\n\n\t\t\t\tif (saves.autosave) {\n\t\t\t\t\t// Add the load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('load', 'ui-close', L10n.get('savesLabelLoad'), 'auto', () => {\n\t\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.autosave.load());\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description (title and datestamp).\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.text(saves.autosave.title)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.addClass('datestamp')\n\t\t\t\t\t\t.html(\n\t\t\t\t\t\t\tsaves.autosave.date\n\t\t\t\t\t\t\t\t? `${new Date(saves.autosave.date).toLocaleString()}`\n\t\t\t\t\t\t\t\t: `<em>${L10n.get('savesUnknownDate')}</em>`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\n\t\t\t\t\t// Add the delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), 'auto', () => {\n\t\t\t\t\t\t\tSave.autosave.delete();\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Add the disabled load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('load', null, L10n.get('savesLabelLoad'), 'auto')\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description.\n\t\t\t\t\t$tdDesc.addClass('empty').text('\\u2022\\u00a0\\u00a0\\u2022\\u00a0\\u00a0\\u2022');\n\n\t\t\t\t\t// Add the disabled delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), 'auto')\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t.append($tdSlot)\n\t\t\t\t\t.append($tdLoad)\n\t\t\t\t\t.append($tdDesc)\n\t\t\t\t\t.append($tdDele)\n\t\t\t\t\t.appendTo($tbody);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = saves.slots.length; i < iend; ++i) {\n\t\t\t\tconst $tdSlot = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdLoad = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDesc = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDele = jQuery(document.createElement('td'));\n\n\t\t\t\t// Add the slot ID.\n\t\t\t\t$tdSlot.append(document.createTextNode(i + 1));\n\n\t\t\t\tif (saves.slots[i]) {\n\t\t\t\t\t// Add the load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('save', 'ui-close', L10n.get('savesLabelSave'), i, Save.slots.save),\n\t\t\t\t\t\tcreateButton('load', 'ui-close', L10n.get('savesLabelLoad'), i, slot => {\n\t\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.slots.load(slot));\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description (title and datestamp).\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.text(saves.slots[i].title)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.addClass('datestamp')\n\t\t\t\t\t\t.html(\n\t\t\t\t\t\t\tsaves.slots[i].date\n\t\t\t\t\t\t\t\t? `${new Date(saves.slots[i].date).toLocaleString()}`\n\t\t\t\t\t\t\t\t: `<em>${L10n.get('savesUnknownDate')}</em>`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\n\t\t\t\t\t// Add the delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), i, slot => {\n\t\t\t\t\t\t\tSave.slots.delete(slot);\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Add the save button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('save', 'ui-close', L10n.get('savesLabelSave'), i, Save.slots.save)\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description.\n\t\t\t\t\t$tdDesc.addClass('empty').text('\\u2022\\u00a0\\u00a0\\u2022\\u00a0\\u00a0\\u2022');\n\n\t\t\t\t\t// Add the disabled delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), i)\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t.append($tdSlot)\n\t\t\t\t\t.append($tdLoad)\n\t\t\t\t\t.append($tdDesc)\n\t\t\t\t\t.append($tdDele)\n\t\t\t\t\t.appendTo($tbody);\n\t\t\t}\n\n\t\t\treturn jQuery(document.createElement('table'))\n\t\t\t\t.attr('id', 'saves-list')\n\t\t\t\t.append($tbody);\n\t\t}\n\n\t\tif (DEBUG) { console.log('[UI/uiBuildSaves()]'); }\n\n\t\tconst $dialogBody = jQuery(Dialog.setup(L10n.get('savesTitle'), 'saves'));\n\t\tconst savesOk     = Save.ok();\n\n\t\t// Add saves list.\n\t\tif (savesOk) {\n\t\t\t$dialogBody.append(createSaveList());\n\t\t}\n\n\t\t// Add button bar items (export, import, and clear).\n\t\tif (savesOk || Has.fileAPI) {\n\t\t\tconst $btnBar = jQuery(document.createElement('ul'))\n\t\t\t\t.addClass('buttons')\n\t\t\t\t.appendTo($dialogBody);\n\n\t\t\tif (Has.fileAPI) {\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'export',\n\t\t\t\t\t'ui-close',\n\t\t\t\t\tL10n.get('savesLabelExport'),\n\t\t\t\t\t() => Save.export()\n\t\t\t\t));\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'import',\n\t\t\t\t\tnull,\n\t\t\t\t\tL10n.get('savesLabelImport'),\n\t\t\t\t\t() => $dialogBody.find('#saves-import-file').trigger('click')\n\t\t\t\t));\n\n\t\t\t\t// Add the hidden `input[type=file]` element which will be triggered by the `#saves-import` button.\n\t\t\t\tjQuery(document.createElement('input'))\n\t\t\t\t\t.css({\n\t\t\t\t\t\tdisplay    : 'block',\n\t\t\t\t\t\tvisibility : 'hidden',\n\t\t\t\t\t\tposition   : 'fixed',\n\t\t\t\t\t\tleft       : '-9999px',\n\t\t\t\t\t\ttop        : '-9999px',\n\t\t\t\t\t\twidth      : '1px',\n\t\t\t\t\t\theight     : '1px'\n\t\t\t\t\t})\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttype          : 'file',\n\t\t\t\t\t\tid            : 'saves-import-file',\n\t\t\t\t\t\ttabindex      : -1,\n\t\t\t\t\t\t'aria-hidden' : true\n\t\t\t\t\t})\n\t\t\t\t\t.on('change', ev => {\n\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.import(ev));\n\t\t\t\t\t\tDialog.close();\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo($dialogBody);\n\t\t\t}\n\n\t\t\tif (savesOk) {\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'clear',\n\t\t\t\t\tnull,\n\t\t\t\t\tL10n.get('savesLabelClear'),\n\t\t\t\t\tSave.autosave.has() || !Save.slots.isEmpty()\n\t\t\t\t\t\t? () => {\n\t\t\t\t\t\t\tSave.clear();\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t: null\n\t\t\t\t));\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tuiOpenAlert(L10n.get('savesIncapable'));\n\t\treturn false;\n\t}\n\n\tfunction uiBuildSettings() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildSettings()]'); }\n\n\t\tconst $dialogBody = jQuery(Dialog.setup(L10n.get('settingsTitle'), 'settings'));\n\n\t\tSetting.forEach(control => {\n\t\t\tif (control.type === Setting.Types.Header) {\n\t\t\t\tconst name     = control.name;\n\t\t\t\tconst id       = Util.slugify(name);\n\t\t\t\tconst $header  = jQuery(document.createElement('div'));\n\t\t\t\tconst $heading = jQuery(document.createElement('h2'));\n\n\t\t\t\t$header\n\t\t\t\t\t.attr('id', `header-body-${id}`)\n\t\t\t\t\t.append($heading)\n\t\t\t\t\t.appendTo($dialogBody);\n\t\t\t\t$heading\n\t\t\t\t\t.attr('id', `header-heading-${id}`)\n\t\t\t\t\t.wiki(name);\n\n\t\t\t\t// Set up the description, if any.\n\t\t\t\tif (control.desc) {\n\t\t\t\t\tjQuery(document.createElement('p'))\n\t\t\t\t\t\t.attr('id', `header-desc-${id}`)\n\t\t\t\t\t\t.wiki(control.desc)\n\t\t\t\t\t\t.appendTo($header);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst name        = control.name;\n\t\t\tconst id          = Util.slugify(name);\n\t\t\tconst $setting    = jQuery(document.createElement('div'));\n\t\t\tconst $label      = jQuery(document.createElement('label'));\n\t\t\tconst $controlBox = jQuery(document.createElement('div'));\n\t\t\tlet $control;\n\n\t\t\t// Set up the label+control wrapper.\n\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t.append($label)\n\t\t\t\t.append($controlBox)\n\t\t\t\t.appendTo($setting);\n\n\t\t\t// Set up the description, if any.\n\t\t\tif (control.desc) {\n\t\t\t\tjQuery(document.createElement('p'))\n\t\t\t\t\t.attr('id', `setting-desc-${id}`)\n\t\t\t\t\t.wiki(control.desc)\n\t\t\t\t\t.appendTo($setting);\n\t\t\t}\n\n\t\t\t// Set up the label.\n\t\t\t$label\n\t\t\t\t.attr({\n\t\t\t\t\tid  : `setting-label-${id}`,\n\t\t\t\t\tfor : `setting-control-${id}` // must be in sync with $control's ID (see below)\n\t\t\t\t})\n\t\t\t\t.wiki(control.label);\n\n\t\t\t// Set up the control.\n\t\t\tif (settings[name] == null) { // lazy equality for null\n\t\t\t\tsettings[name] = control.default;\n\t\t\t}\n\n\t\t\tswitch (control.type) {\n\t\t\tcase Setting.Types.Toggle:\n\t\t\t\t$control = jQuery(document.createElement('button'));\n\n\t\t\t\tif (settings[name]) {\n\t\t\t\t\t$control\n\t\t\t\t\t\t.addClass('enabled')\n\t\t\t\t\t\t.text(L10n.get('settingsOn'));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$control\n\t\t\t\t\t\t.text(L10n.get('settingsOff'));\n\t\t\t\t}\n\n\t\t\t\t$control.ariaClick(function () {\n\t\t\t\t\tif (settings[name]) {\n\t\t\t\t\t\tjQuery(this)\n\t\t\t\t\t\t\t.removeClass('enabled')\n\t\t\t\t\t\t\t.text(L10n.get('settingsOff'));\n\t\t\t\t\t\tsettings[name] = false;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tjQuery(this)\n\t\t\t\t\t\t\t.addClass('enabled')\n\t\t\t\t\t\t\t.text(L10n.get('settingsOn'));\n\t\t\t\t\t\tsettings[name] = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tSetting.save();\n\n\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\tdefault : control.default\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase Setting.Types.List:\n\t\t\t\t$control = jQuery(document.createElement('select'));\n\n\t\t\t\tfor (let i = 0, iend = control.list.length; i < iend; ++i) {\n\t\t\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t\t\t.val(i)\n\t\t\t\t\t\t.text(control.list[i])\n\t\t\t\t\t\t.appendTo($control);\n\t\t\t\t}\n\n\t\t\t\t$control\n\t\t\t\t\t.val(control.list.indexOf(settings[name]))\n\t\t\t\t\t.attr('tabindex', 0)\n\t\t\t\t\t.on('change', function () {\n\t\t\t\t\t\tsettings[name] = control.list[Number(this.value)];\n\t\t\t\t\t\tSetting.save();\n\n\t\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\t\tdefault : control.default,\n\t\t\t\t\t\t\t\tlist    : control.list\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase Setting.Types.Range:\n\t\t\t\t$control = jQuery(document.createElement('input'));\n\n\t\t\t\t// NOTE: Setting the value with `<jQuery>.val()` can cause odd behavior\n\t\t\t\t// in Edge if it's called before the type is set, so we use the `value`\n\t\t\t\t// content attribute here to dodge the entire issue.\n\t\t\t\t$control\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttype     : 'range',\n\t\t\t\t\t\tmin      : control.min,\n\t\t\t\t\t\tmax      : control.max,\n\t\t\t\t\t\tstep     : control.step,\n\t\t\t\t\t\tvalue    : settings[name],\n\t\t\t\t\t\ttabindex : 0\n\t\t\t\t\t})\n\t\t\t\t\t.on('change input', function () {\n\t\t\t\t\t\tsettings[name] = Number(this.value);\n\t\t\t\t\t\tSetting.save();\n\n\t\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\t\tdefault : control.default,\n\t\t\t\t\t\t\t\tmin     : control.min,\n\t\t\t\t\t\t\t\tmax     : control.max,\n\t\t\t\t\t\t\t\tstep    : control.step\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.on('keypress', ev => {\n\t\t\t\t\t\tif (ev.which === 13) {\n\t\t\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t\t\t$control.trigger('change');\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$control\n\t\t\t\t.attr('id', `setting-control-${id}`)\n\t\t\t\t.appendTo($controlBox);\n\n\t\t\t$setting\n\t\t\t\t.attr('id', `setting-body-${id}`)\n\t\t\t\t.appendTo($dialogBody);\n\t\t});\n\n\t\t// Add the button bar.\n\t\t$dialogBody\n\t\t\t.append(\n\t\t\t\t  '<ul class=\"buttons\">'\n\t\t\t\t+     `<li><button id=\"settings-ok\" class=\"ui-close\">${L10n.get(['settingsOk', 'ok'])}</button></li>`\n\t\t\t\t+     `<li><button id=\"settings-reset\">${L10n.get('settingsReset')}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t)\n\t\t\t.find('#settings-reset')\n\t\t\t/*\n\t\t\t\tInstead of adding '.ui-close' to '#settings-reset' (to receive the use of the default\n\t\t\t\tdelegated dialog close handler), we set up a special case close handler here.  We\n\t\t\t\tdo this to ensure that the invocation of `window.location.reload()` happens after the\n\t\t\t\tdialog has fully closed.  If we did not, then a race condition could occur, causing\n\t\t\t\tdisplay shenanigans.\n\t\t\t*/\n\t\t\t.ariaClick({ one : true }, () => {\n\t\t\t\tjQuery(document).one(':dialogclosed', () => {\n\t\t\t\t\tSetting.reset();\n\t\t\t\t\twindow.location.reload();\n\t\t\t\t});\n\t\t\t\tDialog.close();\n\t\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildShare() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildShare()]'); }\n\n\t\ttry {\n\t\t\tjQuery(Dialog.setup(L10n.get('shareTitle'), 'share list'))\n\t\t\t\t.append(uiAssembleLinkList('StoryShare'));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tconsole.error(ex);\n\t\t\tAlert.error('StoryShare', ex.message);\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tUI Functions, Core.\n\t\t*/\n\t\tassembleLinkList : { value : uiAssembleLinkList },\n\n\t\t/*\n\t\t\tUI Functions, Built-ins.\n\t\t*/\n\t\talert         : { value : uiOpenAlert },\n\t\tjumpto        : { value : uiOpenJumpto },\n\t\trestart       : { value : uiOpenRestart },\n\t\tsaves         : { value : uiOpenSaves },\n\t\tsettings      : { value : uiOpenSettings },\n\t\tshare         : { value : uiOpenShare },\n\t\tbuildAutoload : { value : uiBuildAutoload },\n\t\tbuildJumpto   : { value : uiBuildJumpto },\n\t\tbuildRestart  : { value : uiBuildRestart },\n\t\tbuildSaves    : { value : uiBuildSaves },\n\t\tbuildSettings : { value : uiBuildSettings },\n\t\tbuildShare    : { value : uiBuildShare },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\t// `UIBar` methods.\n\t\t/* global UIBar */\n\t\tstow                     : { value : () => UIBar.stow() },\n\t\tunstow                   : { value : () => UIBar.unstow() },\n\t\tsetStoryElements         : { value : () => UIBar.update() },\n\t\t// `Dialog` methods.\n\t\tisOpen                   : { value : (...args) => Dialog.isOpen(...args) },\n\t\tbody                     : { value : () => Dialog.body() },\n\t\tsetup                    : { value : (...args) => Dialog.setup(...args) },\n\t\taddClickHandler          : { value : (...args) => Dialog.addClickHandler(...args) },\n\t\topen                     : { value : (...args) => Dialog.open(...args) },\n\t\tclose                    : { value : (...args) => Dialog.close(...args) },\n\t\tresize                   : { value : () => Dialog.resize() },\n\t\t// Deprecated method names.\n\t\tbuildDialogAutoload      : { value : uiBuildAutoload },\n\t\tbuildDialogJumpto        : { value : uiBuildJumpto },\n\t\tbuildDialogRestart       : { value : uiBuildRestart },\n\t\tbuildDialogSaves         : { value : uiBuildSaves },\n\t\tbuildDialogSettings      : { value : uiBuildSettings },\n\t\tbuildDialogShare         : { value : uiBuildShare },\n\t\tbuildLinkListFromPassage : { value : uiAssembleLinkList }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tuibar.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Dialog, Engine, L10n, Setting, State, Story, UI, Config, setDisplayTitle, setPageElement\n*/\n\nvar UIBar = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// UI bar element cache.\n\tlet _$uiBar = null;\n\n\n\t/*******************************************************************************\n\t\tUI Bar Functions.\n\t*******************************************************************************/\n\n\tfunction uiBarDestroy() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarDestroy()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Hide the UI bar.\n\t\t_$uiBar.hide();\n\n\t\t// Remove its namespaced events.\n\t\tjQuery(document).off('.ui-bar');\n\n\t\t// Remove its styles.\n\t\tjQuery(document.head).find('#style-ui-bar').remove();\n\n\t\t// Remove it from the DOM.\n\t\t_$uiBar.remove();\n\n\t\t// Drop the reference to the element.\n\t\t_$uiBar = null;\n\t}\n\n\tfunction uiBarHide() {\n\t\tif (_$uiBar) {\n\t\t\t_$uiBar.hide();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarInit() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarInit()]'); }\n\n\t\tif (document.getElementById('ui-bar')) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Generate the UI bar elements.\n\t\tconst $elems = (() => {\n\t\t\tconst toggleLabel   = L10n.get('uiBarToggle');\n\t\t\tconst backwardLabel = L10n.get('uiBarBackward');\n\t\t\tconst jumptoLabel   = L10n.get('uiBarJumpto');\n\t\t\tconst forwardLabel  = L10n.get('uiBarForward');\n\n\t\t\treturn jQuery(document.createDocumentFragment())\n\t\t\t\t.append(\n\t\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t\t  '<div id=\"ui-bar\">'\n\t\t\t\t\t+     '<div id=\"ui-bar-tray\">'\n\t\t\t\t\t+         `<button id=\"ui-bar-toggle\" tabindex=\"0\" title=\"${toggleLabel}\" aria-label=\"${toggleLabel}\"></button>`\n\t\t\t\t\t+         '<div id=\"ui-bar-history\">'\n\t\t\t\t\t+             `<button id=\"history-backward\" tabindex=\"0\" title=\"${backwardLabel}\" aria-label=\"${backwardLabel}\">\\uE821</button>`\n\t\t\t\t\t+             `<button id=\"history-jumpto\" tabindex=\"0\" title=\"${jumptoLabel}\" aria-label=\"${jumptoLabel}\">\\uE839</button>`\n\t\t\t\t\t+             `<button id=\"history-forward\" tabindex=\"0\" title=\"${forwardLabel}\" aria-label=\"${forwardLabel}\">\\uE822</button>`\n\t\t\t\t\t+         '</div>'\n\t\t\t\t\t+     '</div>'\n\t\t\t\t\t+     '<div id=\"ui-bar-body\">'\n\t\t\t\t\t+         '<header id=\"title\" role=\"banner\">'\n\t\t\t\t\t+             '<div id=\"story-banner\"></div>'\n\t\t\t\t\t+             '<h1 id=\"story-title\"></h1>'\n\t\t\t\t\t+             '<div id=\"story-subtitle\"></div>'\n\t\t\t\t\t+             '<div id=\"story-title-separator\"></div>'\n\t\t\t\t\t+             '<p id=\"story-author\"></p>'\n\t\t\t\t\t+         '</header>'\n\t\t\t\t\t+         '<div id=\"story-caption\"></div>'\n\t\t\t\t\t+         '<nav id=\"menu\" role=\"navigation\">'\n\t\t\t\t\t+             '<ul id=\"menu-story\"></ul>'\n\t\t\t\t\t+             '<ul id=\"menu-core\">'\n\t\t\t\t\t+                 `<li id=\"menu-item-saves\"><a tabindex=\"0\">${L10n.get('savesTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-settings\"><a tabindex=\"0\">${L10n.get('settingsTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-restart\"><a tabindex=\"0\">${L10n.get('restartTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-share\"><a tabindex=\"0\">${L10n.get('shareTitle')}</a></li>`\n\t\t\t\t\t+             '</ul>'\n\t\t\t\t\t+         '</nav>'\n\t\t\t\t\t+     '</div>'\n\t\t\t\t\t+ '</div>'\n\t\t\t\t\t/* eslint-enable max-len */\n\t\t\t\t);\n\t\t})();\n\n\t\t/*\n\t\t\tCache the UI bar element, since its going to be used often.\n\n\t\t\tNOTE: We rewrap the element itself, rather than simply using the result\n\t\t\tof `find()`, so that we cache an uncluttered jQuery-wrapper (i.e. `context`\n\t\t\trefers to the element and there is no `prevObject`).\n\t\t*/\n\t\t_$uiBar = jQuery($elems.find('#ui-bar').get(0));\n\n\t\t// Insert the UI bar elements into the page before the main script.\n\t\t$elems.insertBefore('body>script#script-sugarcube');\n\n\t\t// Set up the UI bar's global event handlers.\n\t\tjQuery(document)\n\t\t\t// Set up a handler for the history-backward/-forward buttons.\n\t\t\t.on(':historyupdate.ui-bar', (($backward, $forward) => () => {\n\t\t\t\t$backward.ariaDisabled(State.length < 2);\n\t\t\t\t$forward.ariaDisabled(State.length === State.size);\n\t\t\t})(jQuery('#history-backward'), jQuery('#history-forward')));\n\t}\n\n\tfunction uiBarIsHidden() {\n\t\treturn _$uiBar && _$uiBar.css('display') === 'none';\n\t}\n\n\tfunction uiBarIsStowed() {\n\t\treturn _$uiBar && _$uiBar.hasClass('stowed');\n\t}\n\n\tfunction uiBarShow() {\n\t\tif (_$uiBar) {\n\t\t\t_$uiBar.show();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarStart() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarStart()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Set up the #ui-bar's initial state.\n\t\tif (\n\t\t\ttypeof Config.ui.stowBarInitially === 'boolean'\n\t\t\t\t? Config.ui.stowBarInitially\n\t\t\t\t: jQuery(window).width() <= Config.ui.stowBarInitially\n\t\t) {\n\t\t\tuiBarStow(true);\n\t\t}\n\n\t\t// Set up the #ui-bar-toggle and #ui-bar-history widgets.\n\t\tjQuery('#ui-bar-toggle')\n\t\t\t.ariaClick({\n\t\t\t\tlabel : L10n.get('uiBarToggle')\n\t\t\t}, () => _$uiBar.toggleClass('stowed'));\n\n\t\tif (Config.history.controls) {\n\t\t\tjQuery('#history-backward')\n\t\t\t\t.ariaDisabled(State.length < 2)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tlabel : L10n.get('uiBarBackward')\n\t\t\t\t}, () => Engine.backward());\n\n\t\t\tif (Story.lookup('tags', 'bookmark').length > 0) {\n\t\t\t\tjQuery('#history-jumpto')\n\t\t\t\t\t.ariaClick({\n\t\t\t\t\t\tlabel : L10n.get('uiBarJumpto')\n\t\t\t\t\t}, () => UI.jumpto());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery('#history-jumpto').remove();\n\t\t\t}\n\n\t\t\tjQuery('#history-forward')\n\t\t\t\t.ariaDisabled(State.length === State.size)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tlabel : L10n.get('uiBarForward')\n\t\t\t\t}, () => Engine.forward());\n\t\t}\n\t\telse {\n\t\t\tjQuery('#ui-bar-history').remove();\n\t\t}\n\n\t\t// Set up the story display title.\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t}\n\t\telse {\n\t\t\tif (TWINE1) { // for Twine 1\n\t\t\t\tsetPageElement('story-title', 'StoryTitle', Story.title);\n\t\t\t}\n\t\t\telse { // for Twine 2\n\t\t\t\tjQuery('#story-title').text(Story.title);\n\t\t\t}\n\t\t}\n\n\t\t// Set up the dynamic page elements.\n\t\tif (!Story.has('StoryCaption')) {\n\t\t\tjQuery('#story-caption').remove();\n\t\t}\n\n\t\tif (!Story.has('StoryMenu')) {\n\t\t\tjQuery('#menu-story').remove();\n\t\t}\n\n\t\tif (!Config.ui.updateStoryElements) {\n\t\t\t// We only need to set the story elements here if `Config.ui.updateStoryElements`\n\t\t\t// is falsy, since otherwise they will be set by `Engine.play()`.\n\t\t\tuiBarUpdate();\n\t\t}\n\n\t\t// Set up the Saves menu item.\n\t\tjQuery('#menu-item-saves a')\n\t\t\t.ariaClick(ev => {\n\t\t\t\tev.preventDefault();\n\t\t\t\tUI.buildSaves();\n\t\t\t\tDialog.open();\n\t\t\t})\n\t\t\t.text(L10n.get('savesTitle'));\n\n\t\t// Set up the Settings menu item.\n\t\tif (!Setting.isEmpty()) {\n\t\t\tjQuery('#menu-item-settings a')\n\t\t\t\t.ariaClick(ev => {\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\tUI.buildSettings();\n\t\t\t\t\tDialog.open();\n\t\t\t\t})\n\t\t\t\t.text(L10n.get('settingsTitle'));\n\t\t}\n\t\telse {\n\t\t\tjQuery('#menu-item-settings').remove();\n\t\t}\n\n\t\t// Set up the Restart menu item.\n\t\tjQuery('#menu-item-restart a')\n\t\t\t.ariaClick(ev => {\n\t\t\t\tev.preventDefault();\n\t\t\t\tUI.buildRestart();\n\t\t\t\tDialog.open();\n\t\t\t})\n\t\t\t.text(L10n.get('restartTitle'));\n\n\t\t// Set up the Share menu item.\n\t\tif (Story.has('StoryShare')) {\n\t\t\tjQuery('#menu-item-share a')\n\t\t\t\t.ariaClick(ev => {\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\tUI.buildShare();\n\t\t\t\t\tDialog.open();\n\t\t\t\t})\n\t\t\t\t.text(L10n.get('shareTitle'));\n\t\t}\n\t\telse {\n\t\t\tjQuery('#menu-item-share').remove();\n\t\t}\n\t}\n\n\tfunction uiBarStow(noAnimation) {\n\t\tif (_$uiBar && !_$uiBar.hasClass('stowed')) {\n\t\t\tlet $story;\n\n\t\t\tif (noAnimation) {\n\t\t\t\t$story = jQuery('#story');\n\t\t\t\t$story.addClass('no-transition');\n\t\t\t\t_$uiBar.addClass('no-transition');\n\t\t\t}\n\n\t\t\t_$uiBar.addClass('stowed');\n\n\t\t\tif (noAnimation) {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t$story.removeClass('no-transition');\n\t\t\t\t\t_$uiBar.removeClass('no-transition');\n\t\t\t\t}, Engine.minDomActionDelay);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarUnstow(noAnimation) {\n\t\tif (_$uiBar && _$uiBar.hasClass('stowed')) {\n\t\t\tlet $story;\n\n\t\t\tif (noAnimation) {\n\t\t\t\t$story = jQuery('#story');\n\t\t\t\t$story.addClass('no-transition');\n\t\t\t\t_$uiBar.addClass('no-transition');\n\t\t\t}\n\n\t\t\t_$uiBar.removeClass('stowed');\n\n\t\t\tif (noAnimation) {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t$story.removeClass('no-transition');\n\t\t\t\t\t_$uiBar.removeClass('no-transition');\n\t\t\t\t}, Engine.minDomActionDelay);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarUpdate() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarUpdate()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Set up the (non-navigation) dynamic page elements.\n\t\tsetPageElement('story-banner', 'StoryBanner');\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t}\n\t\tsetPageElement('story-subtitle', 'StorySubtitle');\n\t\tsetPageElement('story-author', 'StoryAuthor');\n\t\tsetPageElement('story-caption', 'StoryCaption');\n\n\t\t// Set up the #menu-story items.\n\t\tconst menuStory = document.getElementById('menu-story');\n\n\t\tif (menuStory !== null) {\n\t\t\tjQuery(menuStory).empty();\n\n\t\t\tif (Story.has('StoryMenu')) {\n\t\t\t\ttry {\n\t\t\t\t\tUI.assembleLinkList('StoryMenu', menuStory);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\tconsole.error(ex);\n\t\t\t\t\tAlert.error('StoryMenu', ex.message);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tdestroy  : { value : uiBarDestroy },\n\t\thide     : { value : uiBarHide },\n\t\tinit     : { value : uiBarInit },\n\t\tisHidden : { value : uiBarIsHidden },\n\t\tisStowed : { value : uiBarIsStowed },\n\t\tshow     : { value : uiBarShow },\n\t\tstart    : { value : uiBarStart },\n\t\tstow     : { value : uiBarStow },\n\t\tunstow   : { value : uiBarUnstow },\n\t\tupdate   : { value : uiBarUpdate },\n\n\t\t// Legacy Functions.\n\t\tsetStoryElements : { value : uiBarUpdate }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tdebugbar.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal DebugView, Engine, L10n, Patterns, State, Util, session\n*/\n\nvar DebugBar = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tconst _variableRe   = new RegExp(`^${Patterns.variable}$`);\n\tconst _numericKeyRe = /^\\d+$/;\n\tconst _watchList    = [];\n\tlet _$debugBar   = null;\n\tlet _$watchBody  = null;\n\tlet _$watchList  = null;\n\tlet _$turnSelect = null;\n\tlet _stowed      = true;\n\n\n\t/*******************************************************************************************************************\n\t\tDebug Bar Functions.\n\t*******************************************************************************************************************/\n\tfunction debugBarInit() {\n\t\tif (DEBUG) { console.log('[DebugBar/debugBarInit()]'); }\n\n\t\t/*\n\t\t\tGenerate the debug bar elements and append them to the `<body>`.\n\t\t*/\n\t\tconst barToggleLabel   = L10n.get('debugBarToggle');\n\t\tconst watchAddLabel    = L10n.get('debugBarAddWatch');\n\t\tconst watchAllLabel    = L10n.get('debugBarWatchAll');\n\t\tconst watchNoneLabel   = L10n.get('debugBarWatchNone');\n\t\tconst watchToggleLabel = L10n.get('debugBarWatchToggle');\n\t\tconst viewsToggleLabel = L10n.get('debugBarViewsToggle');\n\n\t\tjQuery(document.createDocumentFragment())\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  '<div id=\"debug-bar\">'\n\t\t\t\t+     '<div id=\"debug-bar-watch\">'\n\t\t\t\t+         `<div>${L10n.get('debugBarNoWatches')}</div>>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div>'\n\t\t\t\t+         `<button id=\"debug-bar-watch-toggle\" tabindex=\"0\" title=\"${watchToggleLabel}\" aria-label=\"${watchToggleLabel}\">${L10n.get('debugBarLabelWatch')}</button>`\n\t\t\t\t+         `<label id=\"debug-bar-watch-label\" for=\"debug-bar-watch-input\">${L10n.get('debugBarLabelAdd')}</label>`\n\t\t\t\t+         '<input id=\"debug-bar-watch-input\" name=\"debug-bar-watch-input\" type=\"text\" list=\"debug-bar-watch-list\" tabindex=\"0\">'\n\t\t\t\t+         '<datalist id=\"debug-bar-watch-list\" aria-hidden=\"true\" hidden=\"hidden\"></datalist>'\n\t\t\t\t+         `<button id=\"debug-bar-watch-add\" tabindex=\"0\" title=\"${watchAddLabel}\" aria-label=\"${watchAddLabel}\"></button>`\n\t\t\t\t+         `<button id=\"debug-bar-watch-all\" tabindex=\"0\" title=\"${watchAllLabel}\" aria-label=\"${watchAllLabel}\"></button>`\n\t\t\t\t+         `<button id=\"debug-bar-watch-none\" tabindex=\"0\" title=\"${watchNoneLabel}\" aria-label=\"${watchNoneLabel}\"></button>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div>'\n\t\t\t\t+         `<button id=\"debug-bar-views-toggle\" tabindex=\"0\" title=\"${viewsToggleLabel}\" aria-label=\"${viewsToggleLabel}\">${L10n.get('debugBarLabelViews')}</button>`\n\t\t\t\t+         `<label id=\"debug-bar-turn-label\" for=\"debug-bar-turn-select\">${L10n.get('debugBarLabelTurn')}</label>`\n\t\t\t\t+         '<select id=\"debug-bar-turn-select\" tabindex=\"0\"></select>'\n\t\t\t\t+     '</div>'\n\t\t\t\t+     `<button id=\"debug-bar-toggle\" tabindex=\"0\" title=\"${barToggleLabel}\" aria-label=\"${barToggleLabel}\"></button>`\n\t\t\t\t+ '</div>'\n\t\t\t\t+ '<div id=\"debug-bar-hint\"></div>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t)\n\t\t\t.appendTo('body');\n\n\t\t/*\n\t\t\tCache various oft used elements.\n\n\t\t\tNOTE: We rewrap the elements themselves, rather than simply using\n\t\t\tthe results of `find()`, so that we cache uncluttered jQuery-wrappers\n\t\t\t(i.e. `context` refers to the elements and there is no `prevObject`).\n\t\t*/\n\t\t_$debugBar   = jQuery('#debug-bar');\n\t\t_$watchBody  = jQuery(_$debugBar.find('#debug-bar-watch').get(0));\n\t\t_$watchList  = jQuery(_$debugBar.find('#debug-bar-watch-list').get(0));\n\t\t_$turnSelect = jQuery(_$debugBar.find('#debug-bar-turn-select').get(0));\n\n\t\tconst $barToggle   = jQuery(_$debugBar.find('#debug-bar-toggle').get(0));\n\t\tconst $watchToggle = jQuery(_$debugBar.find('#debug-bar-watch-toggle').get(0));\n\t\tconst $watchInput  = jQuery(_$debugBar.find('#debug-bar-watch-input').get(0));\n\t\tconst $watchAdd    = jQuery(_$debugBar.find('#debug-bar-watch-add').get(0));\n\t\tconst $watchAll    = jQuery(_$debugBar.find('#debug-bar-watch-all').get(0));\n\t\tconst $watchNone   = jQuery(_$debugBar.find('#debug-bar-watch-none').get(0));\n\t\tconst $viewsToggle = jQuery(_$debugBar.find('#debug-bar-views-toggle').get(0));\n\n\t\t/*\n\t\t\tSet up the debug bar's local event handlers.\n\t\t*/\n\t\t$barToggle\n\t\t\t.ariaClick(debugBarToggle);\n\t\t$watchToggle\n\t\t\t.ariaClick(debugBarWatchToggle);\n\t\t$watchInput\n\t\t\t.on(':addwatch', function () {\n\t\t\t\tdebugBarWatchAdd(this.value.trim());\n\t\t\t\tthis.value = '';\n\t\t\t})\n\t\t\t.on('keypress', ev => {\n\t\t\t\tif (ev.which === 13) { // 13 is Return/Enter\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t$watchInput.trigger(':addwatch');\n\t\t\t\t}\n\t\t\t});\n\t\t$watchAdd\n\t\t\t.ariaClick(() => $watchInput.trigger(':addwatch'));\n\t\t$watchAll\n\t\t\t.ariaClick(debugBarWatchAddAll);\n\t\t$watchNone\n\t\t\t.ariaClick(debugBarWatchClear);\n\t\t_$turnSelect\n\t\t\t.on('change', function () {\n\t\t\t\tEngine.goTo(Number(this.value));\n\t\t\t});\n\t\t$viewsToggle\n\t\t\t.ariaClick(() => {\n\t\t\t\tDebugView.toggle();\n\t\t\t\t_updateSession();\n\t\t\t});\n\n\t\t/*\n\t\t\tSet up the debug bar's global event handlers.\n\t\t*/\n\t\tjQuery(document)\n\t\t\t// Set up a handler for the history select.\n\t\t\t.on(':historyupdate.debug-bar', _updateTurnSelect)\n\t\t\t// Set up a handler for the variables watch.\n\t\t\t.on(':passageend.debug-bar', () => {\n\t\t\t\t_updateWatchBody();\n\t\t\t\t_updateWatchList();\n\t\t\t})\n\t\t\t// Set up a handler for engine resets to clear the active debug session.\n\t\t\t.on(':enginerestart.debug-bar', _clearSession);\n\n\t\t/*\n\t\t\tInitially enable debug views if there's no active debug session.\n\t\t*/\n\t\tif (!_hasSession()) {\n\t\t\tDebugView.enable();\n\t\t}\n\t}\n\n\tfunction debugBarStart() {\n\t\tif (DEBUG) { console.log('[DebugBar/debugBarStart()]'); }\n\n\t\t// Attempt to restore an existing session.\n\t\t_restoreSession();\n\n\t\t// Update the UI.\n\t\t_updateBar();\n\t\t_updateTurnSelect();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t}\n\n\tfunction debugBarIsStowed() {\n\t\treturn _stowed;\n\t}\n\n\tfunction debugBarStow() {\n\t\t_debugBarStowNoUpdate();\n\t\t_stowed = true;\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarUnstow() {\n\t\t_debugBarUnstowNoUpdate();\n\t\t_stowed = false;\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarToggle() {\n\t\tif (_stowed) {\n\t\t\tdebugBarUnstow();\n\t\t}\n\t\telse {\n\t\t\tdebugBarStow();\n\t\t}\n\t}\n\n\tfunction debugBarWatchAdd(varName) {\n\t\tif (!_variableRe.test(varName)) {\n\t\t\treturn;\n\t\t}\n\n\t\t_watchList.pushUnique(varName);\n\t\t_watchList.sort();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchAddAll() {\n\t\tObject.keys(State.variables).map(name => _watchList.pushUnique(`$${name}`));\n\t\tObject.keys(State.temporary).map(name => _watchList.pushUnique(`_${name}`));\n\n\t\t_watchList.sort();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchClear() {\n\t\tfor (let i = _watchList.length - 1; i >= 0; --i) {\n\t\t\t_watchList.pop();\n\t\t}\n\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchDelete(varName) {\n\t\t_watchList.delete(varName);\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchDisable() {\n\t\t_debugBarWatchDisableNoUpdate();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchEnable() {\n\t\t_debugBarWatchEnableNoUpdate();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchIsEnabled() {\n\t\treturn !_$watchBody.attr('hidden');\n\t}\n\n\tfunction debugBarWatchToggle() {\n\t\tif (_$watchBody.attr('hidden')) {\n\t\t\tdebugBarWatchEnable();\n\t\t}\n\t\telse {\n\t\t\tdebugBarWatchDisable();\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _debugBarStowNoUpdate() {\n\t\t_$debugBar.css('right', `-${_$debugBar.outerWidth()}px`);\n\t}\n\n\tfunction _debugBarUnstowNoUpdate() {\n\t\t_$debugBar.css('right', 0);\n\t}\n\n\tfunction _debugBarWatchDisableNoUpdate() {\n\t\t_$watchBody.attr({\n\t\t\t'aria-hidden' : true,\n\t\t\thidden        : 'hidden'\n\t\t});\n\t}\n\n\tfunction _debugBarWatchEnableNoUpdate() {\n\t\t_$watchBody.removeAttr('aria-hidden hidden');\n\t}\n\n\tfunction _clearSession() {\n\t\tsession.delete('debugState');\n\t}\n\n\tfunction _hasSession() {\n\t\treturn session.has('debugState');\n\t}\n\n\tfunction _restoreSession() {\n\t\tif (!_hasSession()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst debugState = session.get('debugState');\n\n\t\t_stowed = debugState.stowed;\n\n\t\t_watchList.push(...debugState.watchList);\n\n\t\tif (debugState.watchEnabled) {\n\t\t\t_debugBarWatchEnableNoUpdate();\n\t\t}\n\t\telse {\n\t\t\t_debugBarWatchDisableNoUpdate();\n\t\t}\n\n\t\tif (debugState.viewsEnabled) {\n\t\t\tDebugView.enable();\n\t\t}\n\t\telse {\n\t\t\tDebugView.disable();\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction _updateSession() {\n\t\tsession.set('debugState', {\n\t\t\tstowed       : _stowed,\n\t\t\twatchList    : _watchList,\n\t\t\twatchEnabled : debugBarWatchIsEnabled(),\n\t\t\tviewsEnabled : DebugView.isEnabled()\n\t\t});\n\t}\n\n\tfunction _updateBar() {\n\t\tif (_stowed) {\n\t\t\tdebugBarStow();\n\t\t}\n\t\telse {\n\t\t\tdebugBarUnstow();\n\t\t}\n\t}\n\n\tfunction _updateWatchBody() {\n\t\tif (_watchList.length === 0) {\n\t\t\t_$watchBody\n\t\t\t\t.empty()\n\t\t\t\t.append(`<div>${L10n.get('debugBarNoWatches')}</div>`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst delLabel = L10n.get('debugBarDeleteWatch');\n\t\tconst $table   = jQuery(document.createElement('table'));\n\t\tconst $tbody   = jQuery(document.createElement('tbody'));\n\n\t\tfor (let i = 0, len = _watchList.length; i < len; ++i) {\n\t\t\tconst varName = _watchList[i];\n\t\t\tconst varKey  = varName.slice(1);\n\t\t\tconst store   = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\tconst $row    = jQuery(document.createElement('tr'));\n\t\t\tconst $delBtn = jQuery(document.createElement('button'));\n\t\t\tconst $code   = jQuery(document.createElement('code'));\n\n\t\t\t$delBtn\n\t\t\t\t.addClass('watch-delete')\n\t\t\t\t.attr('data-name', varName)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tone   : true,\n\t\t\t\t\tlabel : delLabel\n\t\t\t\t}, () => debugBarWatchDelete(varName));\n\t\t\t$code\n\t\t\t\t.text(_toWatchString(store[varKey]));\n\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.append($delBtn)\n\t\t\t\t.appendTo($row);\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.text(varName)\n\t\t\t\t.appendTo($row);\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.append($code)\n\t\t\t\t.appendTo($row);\n\t\t\t$row\n\t\t\t\t.appendTo($tbody);\n\t\t}\n\n\t\t$table\n\t\t\t.append($tbody);\n\t\t_$watchBody\n\t\t\t.empty()\n\t\t\t.append($table);\n\t}\n\n\tfunction _updateWatchList() {\n\t\tconst svn = Object.keys(State.variables);\n\t\tconst tvn = Object.keys(State.temporary);\n\n\t\tif (svn.length === 0 && tvn.length === 0) {\n\t\t\t_$watchList.empty();\n\t\t\treturn;\n\t\t}\n\n\t\tconst names   = [...svn.map(name => `$${name}`), ...tvn.map(name => `_${name}`)].sort();\n\t\tconst options = document.createDocumentFragment();\n\n\t\tnames.delete(_watchList);\n\n\t\tfor (let i = 0, len = names.length; i < len; ++i) {\n\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t.val(names[i])\n\t\t\t\t.appendTo(options);\n\t\t}\n\n\t\t_$watchList\n\t\t\t.empty()\n\t\t\t.append(options);\n\t}\n\n\tfunction _updateTurnSelect() {\n\t\tconst histLen = State.size;\n\t\tconst expLen  = State.expired.length;\n\t\tconst options = document.createDocumentFragment();\n\n\t\tfor (let i = 0; i < histLen; ++i) {\n\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t.val(i)\n\t\t\t\t.text(`${expLen + i + 1}. ${Util.escape(State.history[i].title)}`)\n\t\t\t\t.appendTo(options);\n\t\t}\n\n\t\t_$turnSelect\n\t\t\t.empty()\n\t\t\t.ariaDisabled(histLen < 2)\n\t\t\t.append(options)\n\t\t\t.val(State.activeIndex);\n\t}\n\n\tfunction _toWatchString(value) {\n\t\t/*\n\t\t\tHandle the `null` primitive.\n\t\t*/\n\t\tif (value === null) {\n\t\t\treturn 'null';\n\t\t}\n\n\t\t/*\n\t\t\tHandle the rest of the primitives and functions.\n\t\t*/\n\t\tswitch (typeof value) {\n\t\tcase 'number':\n\t\t\tif (Number.isNaN(value)) {\n\t\t\t\treturn 'NaN';\n\t\t\t}\n\t\t\telse if (!Number.isFinite(value)) {\n\t\t\t\treturn 'Infinity';\n\t\t\t}\n\t\t\t/* falls through */\n\t\tcase 'boolean':\n\t\tcase 'symbol':\n\t\tcase 'undefined':\n\t\t\treturn String(value);\n\n\t\tcase 'string':\n\t\t\treturn JSON.stringify(value);\n\n\t\t// case 'symbol':\n\t\t// \treturn `Symbol\\u202F\"${String(value).slice(7, -1)}\"`;\n\n\t\tcase 'function':\n\t\t\t// return JSON.stringify(value.toString());\n\t\t\treturn 'Function';\n\t\t}\n\n\t\tconst objType = Util.toStringTag(value);\n\n\t\t// /*\n\t\t// \tHandle instances of the primitive exemplar objects (`Boolean`, `Number`, `String`).\n\t\t// */\n\t\t// if (objType === 'Boolean') {\n\t\t// \treturn `Boolean\\u202F{${String(value)}}`;\n\t\t// }\n\t\t// if (objType === 'Number') {\n\t\t// \treturn `Number\\u202F{${String(value)}}`;\n\t\t// }\n\t\t// if (objType === 'String') {\n\t\t// \treturn `String\\u202F{\"${String(value)}\"}`;\n\t\t// }\n\n\t\t/*\n\t\t\tHandle `Date` objects.\n\t\t*/\n\t\tif (objType === 'Date') {\n\t\t\t// return `Date\\u202F${value.toISOString()}`;\n\t\t\treturn `Date\\u202F{${value.toLocaleString()}}`;\n\t\t}\n\n\t\t/*\n\t\t\tHandle `RegExp` objects.\n\t\t*/\n\t\tif (objType === 'RegExp') {\n\t\t\treturn `RegExp\\u202F${value.toString()}`;\n\t\t}\n\n\t\tconst result = [];\n\n\t\t/*\n\t\t\tHandle `Array` & `Set` objects.\n\t\t*/\n\t\tif (value instanceof Array || value instanceof Set) {\n\t\t\tconst list = value instanceof Array ? value : Array.from(value);\n\n\t\t\t// own numeric properties\n\t\t\t// NOTE: Do not use `<Array>.forEach()` here as it skips undefined members.\n\t\t\tfor (let i = 0, len = list.length; i < len; ++i) {\n\t\t\t\tresult.push(list.hasOwnProperty(i) ? _toWatchString(list[i]) : '<empty>');\n\t\t\t}\n\n\t\t\t// own enumerable non-numeric expando properties\n\t\t\tObject.keys(list)\n\t\t\t\t.filter(key => !_numericKeyRe.test(key))\n\t\t\t\t.forEach(key => result.push(`${_toWatchString(key)}: ${_toWatchString(list[key])}`));\n\n\t\t\treturn `${objType}(${list.length})\\u202F[${result.join(', ')}]`;\n\t\t}\n\n\t\t/*\n\t\t\tHandle `Map` objects.\n\t\t*/\n\t\tif (value instanceof Map) {\n\t\t\tvalue.forEach((val, key) => result.push(`${_toWatchString(key)} \\u2192 ${_toWatchString(val)}`));\n\n\t\t\treturn `${objType}(${value.size})\\u202F{${result.join(', ')}}`;\n\t\t}\n\n\t\t/*\n\t\t\tGeneral object handling.\n\t\t*/\n\t\t// own enumerable properties\n\t\tObject.keys(value)\n\t\t\t.forEach(key => result.push(`${_toWatchString(key)}: ${_toWatchString(value[key])}`));\n\n\t\treturn `${objType}\\u202F{${result.join(', ')}}`;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tDebug Bar Functions.\n\t\t*/\n\t\tinit     : { value : debugBarInit },\n\t\tisStowed : { value : debugBarIsStowed },\n\t\tstart    : { value : debugBarStart },\n\t\tstow     : { value : debugBarStow },\n\t\ttoggle   : { value : debugBarToggle },\n\t\tunstow   : { value : debugBarUnstow },\n\n\t\t/*\n\t\t\tWatch Functions.\n\t\t*/\n\t\twatch : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd       : { value : debugBarWatchAdd },\n\t\t\t\tall       : { value : debugBarWatchAddAll },\n\t\t\t\tclear     : { value : debugBarWatchClear },\n\t\t\t\tdelete    : { value : debugBarWatchDelete },\n\t\t\t\tdisable   : { value : debugBarWatchDisable },\n\t\t\t\tenable    : { value : debugBarWatchEnable },\n\t\t\t\tisEnabled : { value : debugBarWatchIsEnabled },\n\t\t\t\ttoggle    : { value : debugBarWatchToggle }\n\t\t\t}))\n\t\t}\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tloadscreen.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Engine */\n\nvar LoadScreen = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Locks collection.\n\tconst _locks = new Set();\n\n\t// Auto-incrementing lock ID.\n\tlet _autoId = 0;\n\n\n\t/*******************************************************************************************************************\n\t\tLoadScreen Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tInitialize management of the loading screen.\n\t*/\n\tfunction loadScreenInit() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenInit()]'); }\n\n\t\t// Add a `readystatechange` listener for hiding/showing the loading screen.\n\t\tjQuery(document).on('readystatechange.SugarCube', () => {\n\t\t\tif (DEBUG) { console.log(`[LoadScreen/<readystatechange>] document.readyState: \"${document.readyState}\"; locks(${_locks.size}):`, _locks); }\n\n\t\t\tif (_locks.size > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// The value of `document.readyState` may be: 'loading' -> 'interactive' -> 'complete'.\n\t\t\t// Though, to reach this point, it must already be in, at least, the 'interactive' state.\n\t\t\tif (document.readyState === 'complete') {\n\t\t\t\tif (jQuery(document.documentElement).attr('data-init') === 'loading') {\n\t\t\t\t\tif (Config.loadDelay > 0) {\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tif (_locks.size === 0) {\n\t\t\t\t\t\t\t\tloadScreenHide();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, Math.max(Engine.minDomActionDelay, Config.loadDelay));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tloadScreenHide();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloadScreenShow();\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\tClear the loading screen.\n\t*/\n\tfunction loadScreenClear() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenClear()]'); }\n\n\t\t// Remove the event listener.\n\t\tjQuery(document).off('readystatechange.SugarCube');\n\n\t\t// Clear all locks.\n\t\t_locks.clear();\n\n\t\t// Hide the loading screen.\n\t\tloadScreenHide();\n\t}\n\n\t/*\n\t\tHide the loading screen.\n\t*/\n\tfunction loadScreenHide() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenHide()]'); }\n\n\t\tjQuery(document.documentElement).removeAttr('data-init');\n\t}\n\n\t/*\n\t\tShow the loading screen.\n\t*/\n\tfunction loadScreenShow() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenShow()]'); }\n\n\t\tjQuery(document.documentElement).attr('data-init', 'loading');\n\t}\n\n\t/*\n\t\tReturns a new lock ID after locking and showing the loading screen.\n\t*/\n\tfunction loadScreenLock() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenLock()]'); }\n\n\t\t++_autoId;\n\t\t_locks.add(_autoId);\n\n\t\tif (DEBUG) { console.log(`\\tacquired loading screen lock; id: ${_autoId}`); }\n\n\t\tloadScreenShow();\n\t\treturn _autoId;\n\t}\n\n\t/*\n\t\tRemove the lock associated with the given lock ID and, if no locks remain,\n\t\ttrigger a `readystatechange` event.\n\t*/\n\tfunction loadScreenUnlock(id) {\n\t\tif (DEBUG) { console.log(`[LoadScreen/loadScreenUnlock(id: ${id})]`); }\n\n\t\tif (id == null) { // lazy equality for null\n\t\t\tthrow new Error('LoadScreen.unlock called with a null or undefined ID');\n\t\t}\n\n\t\tif (_locks.has(id)) {\n\t\t\t_locks.delete(id);\n\n\t\t\tif (DEBUG) { console.log(`\\treleased loading screen lock; id: ${id}`); }\n\t\t}\n\n\t\tif (_locks.size === 0) {\n\t\t\tjQuery(document).trigger('readystatechange');\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : loadScreenInit },\n\t\tclear  : { value : loadScreenClear },\n\t\thide   : { value : loadScreenHide },\n\t\tshow   : { value : loadScreenShow },\n\t\tlock   : { value : loadScreenLock },\n\t\tunlock : { value : loadScreenUnlock }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tsugarcube.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Browser, Config, Dialog, Engine, Fullscreen, Has, LoadScreen, SimpleStore, L10n, Macro, Passage,\n\t       Save, Scripting, Setting, SimpleAudio, State, Story, UI, UIBar, DebugBar, Util, Visibility, Wikifier\n*/\n/* eslint-disable no-var */\n\n/*\n\tVersion object.\n*/\nvar version = Object.freeze({\n\ttitle      : 'SugarCube',\n\tmajor      : 2,\n\tminor      : 31,\n\tpatch      : 1,\n\tprerelease : null,\n\tbuild      : 22,\n\tdate       : new Date(\"2020-04-15T12:06:54.847Z\"),\n\t/* legacy */\n\textensions : {},\n\t/* /legacy */\n\n\ttoString() {\n\t\t'use strict';\n\n\t\tconst prerelease = this.prerelease ? `-${this.prerelease}` : '';\n\t\treturn `${this.major}.${this.minor}.${this.patch}${prerelease}+${this.build}`;\n\t},\n\n\tshort() {\n\t\t'use strict';\n\n\t\tconst prerelease = this.prerelease ? `-${this.prerelease}` : '';\n\t\treturn `${this.title} (v${this.major}.${this.minor}.${this.patch}${prerelease})`;\n\t},\n\n\tlong() {\n\t\t'use strict';\n\n\t\treturn `${this.title} v${this.toString()} (${this.date.toUTCString()})`;\n\t}\n});\n\n/* eslint-disable no-unused-vars */\n/*\n\tInternal variables.\n*/\n// Temporary state object.\nvar TempState = {};\n\n// Legacy macros object.\nvar macros = {};\n\n// Post-display task callbacks object.\nvar postdisplay = {};\n\n// Post-render task callbacks object.\nvar postrender = {};\n\n// Pre-display task callbacks object.\nvar predisplay = {};\n\n// Pre-history task callbacks object.\nvar prehistory = {};\n\n// Pre-render task callbacks object.\nvar prerender = {};\n\n// Session storage manager object.\nvar session = null;\n\n// Settings object.\nvar settings = {};\n\n// Setup object.\nvar setup = {};\n\n// Persistant storage manager object.\nvar storage = null;\n\n/*\n\tLegacy aliases.\n*/\nvar browser       = Browser;\nvar config        = Config;\nvar has           = Has;\nvar History       = State;\nvar state         = State;\nvar tale          = Story;\nvar TempVariables = State.temporary;\n/* eslint-enable no-unused-vars */\n\n/*\n\tGlobal `SugarCube` object.  Allows scripts to detect if they're running in SugarCube by\n\ttesting for the object (e.g. `\"SugarCube\" in window`) and contains exported identifiers\n\tfor debugging purposes.\n*/\nwindow.SugarCube = {};\n\n/*\n\tMain function, entry point for the story.\n*/\njQuery(() => {\n\t'use strict';\n\n\tif (DEBUG) { console.log('[SugarCube/main()] Document loaded; beginning startup.'); }\n\n\t/*\n\t\tWARNING!\n\n\t\tThe ordering of the code within this function is critically important,\n\t\tso be careful when mucking around with it.\n\t*/\n\ttry {\n\t\t// Acquire an initial lock for and initialize the loading screen.\n\t\tconst lockId = LoadScreen.lock();\n\t\tLoadScreen.init();\n\n\t\t// Normalize the document.\n\t\tif (document.normalize) {\n\t\t\tdocument.normalize();\n\t\t}\n\n\t\t// Load the story data (must be done before most anything else).\n\t\tStory.load();\n\n\t\t// Instantiate the storage and session objects.\n\t\t// NOTE: `SimpleStore.create(storageId, persistent)`\n\t\tstorage = SimpleStore.create(Story.domId, true);\n\t\tsession = SimpleStore.create(Story.domId, false);\n\n\t\t// Initialize the user interface (must be done before story initialization, specifically before scripts).\n\t\tDialog.init();\n\t\tUIBar.init();\n\t\tEngine.init();\n\n\t\t// Initialize the story (largely load the user styles, scripts, and widgets).\n\t\tStory.init();\n\n\t\t// Initialize the localization (must be done after story initialization).\n\t\tL10n.init();\n\n\t\t// Alert when the browser is degrading required capabilities (must be done after localization initialization).\n\t\tif (!session.has('rcWarn') && storage.name === 'cookie') {\n\t\t\t/* eslint-disable no-alert */\n\t\t\tsession.set('rcWarn', 1);\n\t\t\twindow.alert(L10n.get('warningNoWebStorage'));\n\t\t\t/* eslint-enable no-alert */\n\t\t}\n\n\t\t// Initialize the saves (must be done after story initialization, but before engine start).\n\t\tSave.init();\n\n\t\t// Initialize the settings.\n\t\tSetting.init();\n\n\t\t// Initialize the macros.\n\t\tMacro.init();\n\n\t\t// Start the engine (should be done as late as possible, but before interface startup).\n\t\tEngine.start();\n\n\t\t// Initialize the debug bar interface (should be done as late as possible, but before interface startup).\n\t\tif (Config.debug) {\n\t\t\tDebugBar.init();\n\t\t}\n\n\t\t// Set a recurring timer to start the interfaces (necessary due to DOM readiness issues in some browsers).\n\t\tconst $window    = $(window);\n\t\tconst vprCheckId = setInterval(() => {\n\t\t\t// If `$window.width()` returns a zero value, bail out and wait.\n\t\t\tif (!$window.width()) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Clear the recurring timer.\n\t\t\tclearInterval(vprCheckId);\n\n\t\t\t// Start the UI bar interface.\n\t\t\tUIBar.start();\n\n\t\t\t// Start the debug bar interface.\n\t\t\tif (Config.debug) {\n\t\t\t\tDebugBar.start();\n\t\t\t}\n\n\t\t\t// Trigger the `:storyready` global synthetic event.\n\t\t\tjQuery.event.trigger({ type : ':storyready' });\n\n\t\t\t// Release the loading screen lock after a short delay.\n\t\t\tsetTimeout(() => LoadScreen.unlock(lockId), Engine.minDomActionDelay * 2);\n\t\t}, Engine.minDomActionDelay);\n\n\t\t// Finally, export identifiers for debugging purposes.\n\t\tObject.defineProperty(window, 'SugarCube', {\n\t\t\t// WARNING: We need to assign new values at points, so seal it, do not freeze it.\n\t\t\tvalue : Object.seal(Object.assign(Object.create(null), {\n\t\t\t\tBrowser,\n\t\t\t\tConfig,\n\t\t\t\tDialog,\n\t\t\t\tEngine,\n\t\t\t\tFullscreen,\n\t\t\t\tHas,\n\t\t\t\tL10n,\n\t\t\t\tMacro,\n\t\t\t\tPassage,\n\t\t\t\tSave,\n\t\t\t\tScripting,\n\t\t\t\tSetting,\n\t\t\t\tSimpleAudio,\n\t\t\t\tState,\n\t\t\t\tStory,\n\t\t\t\tUI,\n\t\t\t\tUIBar,\n\t\t\t\tDebugBar,\n\t\t\t\tUtil,\n\t\t\t\tVisibility,\n\t\t\t\tWikifier,\n\t\t\t\tsession,\n\t\t\t\tsettings,\n\t\t\t\tsetup,\n\t\t\t\tstorage,\n\t\t\t\tversion\n\t\t\t}))\n\t\t});\n\n\t\tif (DEBUG) { console.log('[SugarCube/main()] Startup complete; story ready.'); }\n\t}\n\tcatch (ex) {\n\t\tconsole.error(ex);\n\t\tLoadScreen.clear();\n\t\treturn Alert.fatal(null, ex.message, ex);\n\t}\n});\n\n})(window, window.document, jQuery);\n}\n\t</script>\n</body>\n</html>\n"});
\ No newline at end of file
+window.storyFormat({"name":"SugarCube","version":"2.31.1","description":"A full featured, highly customizable story format.  See its <a href=\"http://www.motoslave.net/sugarcube/2/#documentation\" target=\"_blank\">documentation</a>.","author":"Thomas Michael Edwards","image":"icon.svg","url":"http://www.motoslave.net/sugarcube/","license":"BSD-2-Clause","proofing":false,"source":"<!DOCTYPE html>\n<html data-init=\"no-js\">\n<head>\n<meta charset=\"UTF-8\" />\n<title>{{STORY_NAME}}</title>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n<!--\n\nSugarCube (v2.31.1): A free (gratis and libre) story format.\n\nCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n-->\n<script id=\"script-libraries\" type=\"text/javascript\">\nif(document.head&&document.addEventListener&&document.querySelector&&Object.create&&Object.freeze&&JSON){document.documentElement.setAttribute(\"data-init\", \"loading\");\n/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js */\nif(\"document\" in self){if(!(\"classList\" in document.createElement(\"_\"))){(function(j){\"use strict\";if(!(\"Element\" in j)){return}var a=\"classList\",f=\"prototype\",m=j.Element[f],b=Object,k=String[f].trim||function(){return this.replace(/^\\s+|\\s+$/g,\"\")},c=Array[f].indexOf||function(q){var p=0,o=this.length;for(;p<o;p++){if(p in this&&this[p]===q){return p}}return -1},n=function(o,p){this.name=o;this.code=DOMException[o];this.message=p},g=function(p,o){if(o===\"\"){throw new n(\"SYNTAX_ERR\",\"An invalid or illegal string was specified\")}if(/\\s/.test(o)){throw new n(\"INVALID_CHARACTER_ERR\",\"String contains an invalid character\")}return c.call(p,o)},d=function(s){var r=k.call(s.getAttribute(\"class\")||\"\"),q=r?r.split(/\\s+/):[],p=0,o=q.length;for(;p<o;p++){this.push(q[p])}this._updateClassName=function(){s.setAttribute(\"class\",this.toString())}},e=d[f]=[],i=function(){return new d(this)};n[f]=Error[f];e.item=function(o){return this[o]||null};e.contains=function(o){o+=\"\";return g(this,o)!==-1};e.add=function(){var s=arguments,r=0,p=s.length,q,o=false;do{q=s[r]+\"\";if(g(this,q)===-1){this.push(q);o=true}}while(++r<p);if(o){this._updateClassName()}};e.remove=function(){var t=arguments,s=0,p=t.length,r,o=false,q;do{r=t[s]+\"\";q=g(this,r);while(q!==-1){this.splice(q,1);o=true;q=g(this,r)}}while(++s<p);if(o){this._updateClassName()}};e.toggle=function(p,q){p+=\"\";var o=this.contains(p),r=o?q!==true&&\"remove\":q!==false&&\"add\";if(r){this[r](p)}if(q===true||q===false){return q}else{return !o}};e.toString=function(){return this.join(\" \")};if(b.defineProperty){var l={get:i,enumerable:true,configurable:true};try{b.defineProperty(m,a,l)}catch(h){if(h.number===-2146823252){l.enumerable=false;b.defineProperty(m,a,l)}}}else{if(b[f].__defineGetter__){m.__defineGetter__(a,i)}}}(self))}else{(function(){var b=document.createElement(\"_\");b.classList.add(\"c1\",\"c2\");if(!b.classList.contains(\"c2\")){var c=function(e){var d=DOMTokenList.prototype[e];DOMTokenList.prototype[e]=function(h){var g,f=arguments.length;for(g=0;g<f;g++){h=arguments[g];d.call(this,h)}}};c(\"add\");c(\"remove\")}b.classList.toggle(\"c3\",false);if(b.classList.contains(\"c3\")){var a=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(d,e){if(1 in arguments&&!this.contains(d)===!e){return e}else{return a.call(this,d)}}}b=null}())}};\n/*!\n * https://github.com/es-shims/es5-shim\n * @license es5-shim Copyright 2009-2015 by contributors, MIT License\n * see https://github.com/es-shims/es5-shim/blob/v4.5.13/LICENSE\n */\n(function(t,r){\"use strict\";if(typeof define===\"function\"&&define.amd){define(r)}else if(typeof exports===\"object\"){module.exports=r()}else{t.returnExports=r()}})(this,function(){var t=Array;var r=t.prototype;var e=Object;var n=e.prototype;var i=Function;var a=i.prototype;var o=String;var f=o.prototype;var u=Number;var l=u.prototype;var s=r.slice;var c=r.splice;var v=r.push;var h=r.unshift;var p=r.concat;var y=r.join;var d=a.call;var g=a.apply;var w=Math.max;var b=Math.min;var T=n.toString;var m=typeof Symbol===\"function\"&&typeof Symbol.toStringTag===\"symbol\";var D;var S=Function.prototype.toString,x=/^\\s*class /,O=function isES6ClassFn(t){try{var r=S.call(t);var e=r.replace(/\\/\\/.*\\n/g,\"\");var n=e.replace(/\\/\\*[.\\s\\S]*\\*\\//g,\"\");var i=n.replace(/\\n/gm,\" \").replace(/ {2}/g,\" \");return x.test(i)}catch(a){return false}},E=function tryFunctionObject(t){try{if(O(t)){return false}S.call(t);return true}catch(r){return false}},j=\"[object Function]\",I=\"[object GeneratorFunction]\",D=function isCallable(t){if(!t){return false}if(typeof t!==\"function\"&&typeof t!==\"object\"){return false}if(m){return E(t)}if(O(t)){return false}var r=T.call(t);return r===j||r===I};var M;var U=RegExp.prototype.exec,$=function tryRegexExec(t){try{U.call(t);return true}catch(r){return false}},F=\"[object RegExp]\";M=function isRegex(t){if(typeof t!==\"object\"){return false}return m?$(t):T.call(t)===F};var N;var C=String.prototype.valueOf,k=function tryStringObject(t){try{C.call(t);return true}catch(r){return false}},A=\"[object String]\";N=function isString(t){if(typeof t===\"string\"){return true}if(typeof t!==\"object\"){return false}return m?k(t):T.call(t)===A};var R=e.defineProperty&&function(){try{var t={};e.defineProperty(t,\"x\",{enumerable:false,value:t});for(var r in t){return false}return t.x===t}catch(n){return false}}();var P=function(t){var r;if(R){r=function(t,r,n,i){if(!i&&r in t){return}e.defineProperty(t,r,{configurable:true,enumerable:false,writable:true,value:n})}}else{r=function(t,r,e,n){if(!n&&r in t){return}t[r]=e}}return function defineProperties(e,n,i){for(var a in n){if(t.call(n,a)){r(e,a,n[a],i)}}}}(n.hasOwnProperty);var J=function isPrimitive(t){var r=typeof t;return t===null||r!==\"object\"&&r!==\"function\"};var Y=u.isNaN||function isActualNaN(t){return t!==t};var z={ToInteger:function ToInteger(t){var r=+t;if(Y(r)){r=0}else if(r!==0&&r!==1/0&&r!==-(1/0)){r=(r>0||-1)*Math.floor(Math.abs(r))}return r},ToPrimitive:function ToPrimitive(t){var r,e,n;if(J(t)){return t}e=t.valueOf;if(D(e)){r=e.call(t);if(J(r)){return r}}n=t.toString;if(D(n)){r=n.call(t);if(J(r)){return r}}throw new TypeError},ToObject:function(t){if(t==null){throw new TypeError(\"can't convert \"+t+\" to object\")}return e(t)},ToUint32:function ToUint32(t){return t>>>0}};var Z=function Empty(){};P(a,{bind:function bind(t){var r=this;if(!D(r)){throw new TypeError(\"Function.prototype.bind called on incompatible \"+r)}var n=s.call(arguments,1);var a;var o=function(){if(this instanceof a){var i=g.call(r,this,p.call(n,s.call(arguments)));if(e(i)===i){return i}return this}else{return g.call(r,t,p.call(n,s.call(arguments)))}};var f=w(0,r.length-n.length);var u=[];for(var l=0;l<f;l++){v.call(u,\"$\"+l)}a=i(\"binder\",\"return function (\"+y.call(u,\",\")+\"){ return binder.apply(this, arguments); }\")(o);if(r.prototype){Z.prototype=r.prototype;a.prototype=new Z;Z.prototype=null}return a}});var G=d.bind(n.hasOwnProperty);var H=d.bind(n.toString);var W=d.bind(s);var B=g.bind(s);if(typeof document===\"object\"&&document&&document.documentElement){try{W(document.documentElement.childNodes)}catch(X){var L=W;var q=B;W=function arraySliceIE(t){var r=[];var e=t.length;while(e-- >0){r[e]=t[e]}return q(r,L(arguments,1))};B=function arraySliceApplyIE(t,r){return q(W(t),r)}}}var K=d.bind(f.slice);var Q=d.bind(f.split);var V=d.bind(f.indexOf);var _=d.bind(v);var tt=d.bind(n.propertyIsEnumerable);var rt=d.bind(r.sort);var et=t.isArray||function isArray(t){return H(t)===\"[object Array]\"};var nt=[].unshift(0)!==1;P(r,{unshift:function(){h.apply(this,arguments);return this.length}},nt);P(t,{isArray:et});var it=e(\"a\");var at=it[0]!==\"a\"||!(0 in it);var ot=function properlyBoxed(t){var r=true;var e=true;var n=false;if(t){try{t.call(\"foo\",function(t,e,n){if(typeof n!==\"object\"){r=false}});t.call([1],function(){\"use strict\";e=typeof this===\"string\"},\"x\")}catch(i){n=true}}return!!t&&!n&&r&&e};P(r,{forEach:function forEach(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=-1;var i=z.ToUint32(e.length);var a;if(arguments.length>1){a=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.forEach callback must be a function\")}while(++n<i){if(n in e){if(typeof a===\"undefined\"){t(e[n],n,r)}else{t.call(a,e[n],n,r)}}}}},!ot(r.forEach));P(r,{map:function map(r){var e=z.ToObject(this);var n=at&&N(this)?Q(this,\"\"):e;var i=z.ToUint32(n.length);var a=t(i);var o;if(arguments.length>1){o=arguments[1]}if(!D(r)){throw new TypeError(\"Array.prototype.map callback must be a function\")}for(var f=0;f<i;f++){if(f in n){if(typeof o===\"undefined\"){a[f]=r(n[f],f,e)}else{a[f]=r.call(o,n[f],f,e)}}}return a}},!ot(r.map));P(r,{filter:function filter(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i=[];var a;var o;if(arguments.length>1){o=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.filter callback must be a function\")}for(var f=0;f<n;f++){if(f in e){a=e[f];if(typeof o===\"undefined\"?t(a,f,r):t.call(o,a,f,r)){_(i,a)}}}return i}},!ot(r.filter));P(r,{every:function every(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i;if(arguments.length>1){i=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.every callback must be a function\")}for(var a=0;a<n;a++){if(a in e&&!(typeof i===\"undefined\"?t(e[a],a,r):t.call(i,e[a],a,r))){return false}}return true}},!ot(r.every));P(r,{some:function some(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i;if(arguments.length>1){i=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.some callback must be a function\")}for(var a=0;a<n;a++){if(a in e&&(typeof i===\"undefined\"?t(e[a],a,r):t.call(i,e[a],a,r))){return true}}return false}},!ot(r.some));var ft=false;if(r.reduce){ft=typeof r.reduce.call(\"es5\",function(t,r,e,n){return n})===\"object\"}P(r,{reduce:function reduce(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);if(!D(t)){throw new TypeError(\"Array.prototype.reduce callback must be a function\")}if(n===0&&arguments.length===1){throw new TypeError(\"reduce of empty array with no initial value\")}var i=0;var a;if(arguments.length>=2){a=arguments[1]}else{do{if(i in e){a=e[i++];break}if(++i>=n){throw new TypeError(\"reduce of empty array with no initial value\")}}while(true)}for(;i<n;i++){if(i in e){a=t(a,e[i],i,r)}}return a}},!ft);var ut=false;if(r.reduceRight){ut=typeof r.reduceRight.call(\"es5\",function(t,r,e,n){return n})===\"object\"}P(r,{reduceRight:function reduceRight(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);if(!D(t)){throw new TypeError(\"Array.prototype.reduceRight callback must be a function\")}if(n===0&&arguments.length===1){throw new TypeError(\"reduceRight of empty array with no initial value\")}var i;var a=n-1;if(arguments.length>=2){i=arguments[1]}else{do{if(a in e){i=e[a--];break}if(--a<0){throw new TypeError(\"reduceRight of empty array with no initial value\")}}while(true)}if(a<0){return i}do{if(a in e){i=t(i,e[a],a,r)}}while(a--);return i}},!ut);var lt=r.indexOf&&[0,1].indexOf(1,2)!==-1;P(r,{indexOf:function indexOf(t){var r=at&&N(this)?Q(this,\"\"):z.ToObject(this);var e=z.ToUint32(r.length);if(e===0){return-1}var n=0;if(arguments.length>1){n=z.ToInteger(arguments[1])}n=n>=0?n:w(0,e+n);for(;n<e;n++){if(n in r&&r[n]===t){return n}}return-1}},lt);var st=r.lastIndexOf&&[0,1].lastIndexOf(0,-3)!==-1;P(r,{lastIndexOf:function lastIndexOf(t){var r=at&&N(this)?Q(this,\"\"):z.ToObject(this);var e=z.ToUint32(r.length);if(e===0){return-1}var n=e-1;if(arguments.length>1){n=b(n,z.ToInteger(arguments[1]))}n=n>=0?n:e-Math.abs(n);for(;n>=0;n--){if(n in r&&t===r[n]){return n}}return-1}},st);var ct=function(){var t=[1,2];var r=t.splice();return t.length===2&&et(r)&&r.length===0}();P(r,{splice:function splice(t,r){if(arguments.length===0){return[]}else{return c.apply(this,arguments)}}},!ct);var vt=function(){var t={};r.splice.call(t,0,0,1);return t.length===1}();P(r,{splice:function splice(t,r){if(arguments.length===0){return[]}var e=arguments;this.length=w(z.ToInteger(this.length),0);if(arguments.length>0&&typeof r!==\"number\"){e=W(arguments);if(e.length<2){_(e,this.length-t)}else{e[1]=z.ToInteger(r)}}return c.apply(this,e)}},!vt);var ht=function(){var r=new t(1e5);r[8]=\"x\";r.splice(1,1);return r.indexOf(\"x\")===7}();var pt=function(){var t=256;var r=[];r[t]=\"a\";r.splice(t+1,0,\"b\");return r[t]===\"a\"}();P(r,{splice:function splice(t,r){var e=z.ToObject(this);var n=[];var i=z.ToUint32(e.length);var a=z.ToInteger(t);var f=a<0?w(i+a,0):b(a,i);var u=b(w(z.ToInteger(r),0),i-f);var l=0;var s;while(l<u){s=o(f+l);if(G(e,s)){n[l]=e[s]}l+=1}var c=W(arguments,2);var v=c.length;var h;if(v<u){l=f;var p=i-u;while(l<p){s=o(l+u);h=o(l+v);if(G(e,s)){e[h]=e[s]}else{delete e[h]}l+=1}l=i;var y=i-u+v;while(l>y){delete e[l-1];l-=1}}else if(v>u){l=i-u;while(l>f){s=o(l+u-1);h=o(l+v-1);if(G(e,s)){e[h]=e[s]}else{delete e[h]}l-=1}}l=f;for(var d=0;d<c.length;++d){e[l]=c[d];l+=1}e.length=i-u+v;return n}},!ht||!pt);var yt=r.join;var dt;try{dt=Array.prototype.join.call(\"123\",\",\")!==\"1,2,3\"}catch(X){dt=true}if(dt){P(r,{join:function join(t){var r=typeof t===\"undefined\"?\",\":t;return yt.call(N(this)?Q(this,\"\"):this,r)}},dt)}var gt=[1,2].join(undefined)!==\"1,2\";if(gt){P(r,{join:function join(t){var r=typeof t===\"undefined\"?\",\":t;return yt.call(this,r)}},gt)}var wt=function push(t){var r=z.ToObject(this);var e=z.ToUint32(r.length);var n=0;while(n<arguments.length){r[e+n]=arguments[n];n+=1}r.length=e+n;return e+n};var bt=function(){var t={};var r=Array.prototype.push.call(t,undefined);return r!==1||t.length!==1||typeof t[0]!==\"undefined\"||!G(t,0)}();P(r,{push:function push(t){if(et(this)){return v.apply(this,arguments)}return wt.apply(this,arguments)}},bt);var Tt=function(){var t=[];var r=t.push(undefined);return r!==1||t.length!==1||typeof t[0]!==\"undefined\"||!G(t,0)}();P(r,{push:wt},Tt);P(r,{slice:function(t,r){var e=N(this)?Q(this,\"\"):this;return B(e,arguments)}},at);var mt=function(){try{[1,2].sort(null)}catch(t){try{[1,2].sort({})}catch(r){return false}}return true}();var Dt=function(){try{[1,2].sort(/a/);return false}catch(t){}return true}();var St=function(){try{[1,2].sort(undefined);return true}catch(t){}return false}();P(r,{sort:function sort(t){if(typeof t===\"undefined\"){return rt(this)}if(!D(t)){throw new TypeError(\"Array.prototype.sort callback must be a function\")}return rt(this,t)}},mt||!St||!Dt);var xt=!tt({toString:null},\"toString\");var Ot=tt(function(){},\"prototype\");var Et=!G(\"x\",\"0\");var jt=function(t){var r=t.constructor;return r&&r.prototype===t};var It={$applicationCache:true,$console:true,$external:true,$frame:true,$frameElement:true,$frames:true,$innerHeight:true,$innerWidth:true,$onmozfullscreenchange:true,$onmozfullscreenerror:true,$outerHeight:true,$outerWidth:true,$pageXOffset:true,$pageYOffset:true,$parent:true,$scrollLeft:true,$scrollTop:true,$scrollX:true,$scrollY:true,$self:true,$webkitIndexedDB:true,$webkitStorageInfo:true,$window:true,$width:true,$height:true,$top:true,$localStorage:true};var Mt=function(){if(typeof window===\"undefined\"){return false}for(var t in window){try{if(!It[\"$\"+t]&&G(window,t)&&window[t]!==null&&typeof window[t]===\"object\"){jt(window[t])}}catch(r){return true}}return false}();var Ut=function(t){if(typeof window===\"undefined\"||!Mt){return jt(t)}try{return jt(t)}catch(r){return false}};var $t=[\"toString\",\"toLocaleString\",\"valueOf\",\"hasOwnProperty\",\"isPrototypeOf\",\"propertyIsEnumerable\",\"constructor\"];var Ft=$t.length;var Nt=function isArguments(t){return H(t)===\"[object Arguments]\"};var Ct=function isArguments(t){return t!==null&&typeof t===\"object\"&&typeof t.length===\"number\"&&t.length>=0&&!et(t)&&D(t.callee)};var kt=Nt(arguments)?Nt:Ct;P(e,{keys:function keys(t){var r=D(t);var e=kt(t);var n=t!==null&&typeof t===\"object\";var i=n&&N(t);if(!n&&!r&&!e){throw new TypeError(\"Object.keys called on a non-object\")}var a=[];var f=Ot&&r;if(i&&Et||e){for(var u=0;u<t.length;++u){_(a,o(u))}}if(!e){for(var l in t){if(!(f&&l===\"prototype\")&&G(t,l)){_(a,o(l))}}}if(xt){var s=Ut(t);for(var c=0;c<Ft;c++){var v=$t[c];if(!(s&&v===\"constructor\")&&G(t,v)){_(a,v)}}}return a}});var At=e.keys&&function(){return e.keys(arguments).length===2}(1,2);var Rt=e.keys&&function(){var t=e.keys(arguments);return arguments.length!==1||t.length!==1||t[0]!==1}(1);var Pt=e.keys;P(e,{keys:function keys(t){if(kt(t)){return Pt(W(t))}else{return Pt(t)}}},!At||Rt);var Jt=new Date(-0xc782b5b342b24).getUTCMonth()!==0;var Yt=new Date(-0x55d318d56a724);var zt=new Date(14496624e5);var Zt=Yt.toUTCString()!==\"Mon, 01 Jan -45875 11:59:59 GMT\";var Gt;var Ht;var Wt=Yt.getTimezoneOffset();if(Wt<-720){Gt=Yt.toDateString()!==\"Tue Jan 02 -45875\";Ht=!/^Thu Dec 10 2015 \\d\\d:\\d\\d:\\d\\d GMT[-+]\\d\\d\\d\\d(?: |$)/.test(String(zt))}else{Gt=Yt.toDateString()!==\"Mon Jan 01 -45875\";Ht=!/^Wed Dec 09 2015 \\d\\d:\\d\\d:\\d\\d GMT[-+]\\d\\d\\d\\d(?: |$)/.test(String(zt))}var Bt=d.bind(Date.prototype.getFullYear);var Xt=d.bind(Date.prototype.getMonth);var Lt=d.bind(Date.prototype.getDate);var qt=d.bind(Date.prototype.getUTCFullYear);var Kt=d.bind(Date.prototype.getUTCMonth);var Qt=d.bind(Date.prototype.getUTCDate);var Vt=d.bind(Date.prototype.getUTCDay);var _t=d.bind(Date.prototype.getUTCHours);var tr=d.bind(Date.prototype.getUTCMinutes);var rr=d.bind(Date.prototype.getUTCSeconds);var er=d.bind(Date.prototype.getUTCMilliseconds);var nr=[\"Sun\",\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\"];var ir=[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"];var ar=function daysInMonth(t,r){return Lt(new Date(r,t,0))};P(Date.prototype,{getFullYear:function getFullYear(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);if(t<0&&Xt(this)>11){return t+1}return t},getMonth:function getMonth(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);var r=Xt(this);if(t<0&&r>11){return 0}return r},getDate:function getDate(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);var r=Xt(this);var e=Lt(this);if(t<0&&r>11){if(r===12){return e}var n=ar(0,t+1);return n-e+1}return e},getUTCFullYear:function getUTCFullYear(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);if(t<0&&Kt(this)>11){return t+1}return t},getUTCMonth:function getUTCMonth(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);var r=Kt(this);if(t<0&&r>11){return 0}return r},getUTCDate:function getUTCDate(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);var r=Kt(this);var e=Qt(this);if(t<0&&r>11){if(r===12){return e}var n=ar(0,t+1);return n-e+1}return e}},Jt);P(Date.prototype,{toUTCString:function toUTCString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Vt(this);var r=Qt(this);var e=Kt(this);var n=qt(this);var i=_t(this);var a=tr(this);var o=rr(this);return nr[t]+\", \"+(r<10?\"0\"+r:r)+\" \"+ir[e]+\" \"+n+\" \"+(i<10?\"0\"+i:i)+\":\"+(a<10?\"0\"+a:a)+\":\"+(o<10?\"0\"+o:o)+\" GMT\"}},Jt||Zt);P(Date.prototype,{toDateString:function toDateString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=this.getDay();var r=this.getDate();var e=this.getMonth();var n=this.getFullYear();return nr[t]+\" \"+ir[e]+\" \"+(r<10?\"0\"+r:r)+\" \"+n}},Jt||Gt);if(Jt||Ht){Date.prototype.toString=function toString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=this.getDay();var r=this.getDate();var e=this.getMonth();var n=this.getFullYear();var i=this.getHours();var a=this.getMinutes();var o=this.getSeconds();var f=this.getTimezoneOffset();var u=Math.floor(Math.abs(f)/60);var l=Math.floor(Math.abs(f)%60);return nr[t]+\" \"+ir[e]+\" \"+(r<10?\"0\"+r:r)+\" \"+n+\" \"+(i<10?\"0\"+i:i)+\":\"+(a<10?\"0\"+a:a)+\":\"+(o<10?\"0\"+o:o)+\" GMT\"+(f>0?\"-\":\"+\")+(u<10?\"0\"+u:u)+(l<10?\"0\"+l:l)};if(R){e.defineProperty(Date.prototype,\"toString\",{configurable:true,enumerable:false,writable:true})}}var or=-621987552e5;var fr=\"-000001\";var ur=Date.prototype.toISOString&&new Date(or).toISOString().indexOf(fr)===-1;var lr=Date.prototype.toISOString&&new Date(-1).toISOString()!==\"1969-12-31T23:59:59.999Z\";var sr=d.bind(Date.prototype.getTime);P(Date.prototype,{toISOString:function toISOString(){if(!isFinite(this)||!isFinite(sr(this))){throw new RangeError(\"Date.prototype.toISOString called on non-finite value.\")}var t=qt(this);var r=Kt(this);t+=Math.floor(r/12);r=(r%12+12)%12;var e=[r+1,Qt(this),_t(this),tr(this),rr(this)];t=(t<0?\"-\":t>9999?\"+\":\"\")+K(\"00000\"+Math.abs(t),0<=t&&t<=9999?-4:-6);for(var n=0;n<e.length;++n){e[n]=K(\"00\"+e[n],-2)}return t+\"-\"+W(e,0,2).join(\"-\")+\"T\"+W(e,2).join(\":\")+\".\"+K(\"000\"+er(this),-3)+\"Z\"}},ur||lr);var cr=function(){try{return Date.prototype.toJSON&&new Date(NaN).toJSON()===null&&new Date(or).toJSON().indexOf(fr)!==-1&&Date.prototype.toJSON.call({toISOString:function(){return true}})}catch(t){return false}}();if(!cr){Date.prototype.toJSON=function toJSON(t){var r=e(this);var n=z.ToPrimitive(r);if(typeof n===\"number\"&&!isFinite(n)){return null}var i=r.toISOString;if(!D(i)){throw new TypeError(\"toISOString property is not callable\")}return i.call(r)}}var vr=Date.parse(\"+033658-09-27T01:46:40.000Z\")===1e15;var hr=!isNaN(Date.parse(\"2012-04-04T24:00:00.500Z\"))||!isNaN(Date.parse(\"2012-11-31T23:59:59.000Z\"))||!isNaN(Date.parse(\"2012-12-31T23:59:60.000Z\"));var pr=isNaN(Date.parse(\"2000-01-01T00:00:00.000Z\"));if(pr||hr||!vr){var yr=Math.pow(2,31)-1;var dr=Y(new Date(1970,0,1,0,0,0,yr+1).getTime());Date=function(t){var r=function Date(e,n,i,a,f,u,l){var s=arguments.length;var c;if(this instanceof t){var v=u;var h=l;if(dr&&s>=7&&l>yr){var p=Math.floor(l/yr)*yr;var y=Math.floor(p/1e3);v+=y;h-=y*1e3}c=s===1&&o(e)===e?new t(r.parse(e)):s>=7?new t(e,n,i,a,f,v,h):s>=6?new t(e,n,i,a,f,v):s>=5?new t(e,n,i,a,f):s>=4?new t(e,n,i,a):s>=3?new t(e,n,i):s>=2?new t(e,n):s>=1?new t(e instanceof t?+e:e):new t}else{c=t.apply(this,arguments)}if(!J(c)){P(c,{constructor:r},true)}return c};var e=new RegExp(\"^\"+\"(\\\\d{4}|[+-]\\\\d{6})\"+\"(?:-(\\\\d{2})\"+\"(?:-(\\\\d{2})\"+\"(?:\"+\"T(\\\\d{2})\"+\":(\\\\d{2})\"+\"(?:\"+\":(\\\\d{2})\"+\"(?:(\\\\.\\\\d{1,}))?\"+\")?\"+\"(\"+\"Z|\"+\"(?:\"+\"([-+])\"+\"(\\\\d{2})\"+\":(\\\\d{2})\"+\")\"+\")?)?)?)?\"+\"$\");var n=[0,31,59,90,120,151,181,212,243,273,304,334,365];var i=function dayFromMonth(t,r){var e=r>1?1:0;return n[r]+Math.floor((t-1969+e)/4)-Math.floor((t-1901+e)/100)+Math.floor((t-1601+e)/400)+365*(t-1970)};var a=function toUTC(r){var e=0;var n=r;if(dr&&n>yr){var i=Math.floor(n/yr)*yr;var a=Math.floor(i/1e3);e+=a;n-=a*1e3}return u(new t(1970,0,1,0,0,e,n))};for(var f in t){if(G(t,f)){r[f]=t[f]}}P(r,{now:t.now,UTC:t.UTC},true);r.prototype=t.prototype;P(r.prototype,{constructor:r},true);var l=function parse(r){var n=e.exec(r);if(n){var o=u(n[1]),f=u(n[2]||1)-1,l=u(n[3]||1)-1,s=u(n[4]||0),c=u(n[5]||0),v=u(n[6]||0),h=Math.floor(u(n[7]||0)*1e3),p=Boolean(n[4]&&!n[8]),y=n[9]===\"-\"?1:-1,d=u(n[10]||0),g=u(n[11]||0),w;var b=c>0||v>0||h>0;if(s<(b?24:25)&&c<60&&v<60&&h<1e3&&f>-1&&f<12&&d<24&&g<60&&l>-1&&l<i(o,f+1)-i(o,f)){w=((i(o,f)+l)*24+s+d*y)*60;w=((w+c+g*y)*60+v)*1e3+h;if(p){w=a(w)}if(-864e13<=w&&w<=864e13){return w}}return NaN}return t.parse.apply(this,arguments)};P(r,{parse:l});return r}(Date)}if(!Date.now){Date.now=function now(){return(new Date).getTime()}}var gr=l.toFixed&&(8e-5.toFixed(3)!==\"0.000\"||.9.toFixed(0)!==\"1\"||1.255.toFixed(2)!==\"1.25\"||(1000000000000000128).toFixed(0)!==\"1000000000000000128\");var wr={base:1e7,size:6,data:[0,0,0,0,0,0],multiply:function multiply(t,r){var e=-1;var n=r;while(++e<wr.size){n+=t*wr.data[e];wr.data[e]=n%wr.base;n=Math.floor(n/wr.base)}},divide:function divide(t){var r=wr.size;var e=0;while(--r>=0){e+=wr.data[r];wr.data[r]=Math.floor(e/t);e=e%t*wr.base}},numToString:function numToString(){var t=wr.size;var r=\"\";while(--t>=0){if(r!==\"\"||t===0||wr.data[t]!==0){var e=o(wr.data[t]);if(r===\"\"){r=e}else{r+=K(\"0000000\",0,7-e.length)+e}}}return r},pow:function pow(t,r,e){return r===0?e:r%2===1?pow(t,r-1,e*t):pow(t*t,r/2,e)},log:function log(t){var r=0;var e=t;while(e>=4096){r+=12;e/=4096}while(e>=2){r+=1;e/=2}return r}};var br=function toFixed(t){var r,e,n,i,a,f,l,s;r=u(t);r=Y(r)?0:Math.floor(r);if(r<0||r>20){throw new RangeError(\"Number.toFixed called with invalid number of decimals\")}e=u(this);if(Y(e)){return\"NaN\"}if(e<=-1e21||e>=1e21){return o(e)}n=\"\";if(e<0){n=\"-\";e=-e}i=\"0\";if(e>1e-21){a=wr.log(e*wr.pow(2,69,1))-69;f=a<0?e*wr.pow(2,-a,1):e/wr.pow(2,a,1);f*=4503599627370496;a=52-a;if(a>0){wr.multiply(0,f);l=r;while(l>=7){wr.multiply(1e7,0);l-=7}wr.multiply(wr.pow(10,l,1),0);l=a-1;while(l>=23){wr.divide(1<<23);l-=23}wr.divide(1<<l);wr.multiply(1,1);wr.divide(2);i=wr.numToString()}else{wr.multiply(0,f);wr.multiply(1<<-a,0);i=wr.numToString()+K(\"0.00000000000000000000\",2,2+r)}}if(r>0){s=i.length;if(s<=r){i=n+K(\"0.0000000000000000000\",0,r-s+2)+i}else{i=n+K(i,0,s-r)+\".\"+K(i,s-r)}}else{i=n+i}return i};P(l,{toFixed:br},gr);var Tr=function(){try{return 1..toPrecision(undefined)===\"1\"}catch(t){return true}}();var mr=l.toPrecision;P(l,{toPrecision:function toPrecision(t){return typeof t===\"undefined\"?mr.call(this):mr.call(this,t)}},Tr);if(\"ab\".split(/(?:ab)*/).length!==2||\".\".split(/(.?)(.?)/).length!==4||\"tesst\".split(/(s)*/)[1]===\"t\"||\"test\".split(/(?:)/,-1).length!==4||\"\".split(/.?/).length||\".\".split(/()()/).length>1){(function(){var t=typeof/()??/.exec(\"\")[1]===\"undefined\";var r=Math.pow(2,32)-1;f.split=function(e,n){var i=String(this);if(typeof e===\"undefined\"&&n===0){return[]}if(!M(e)){return Q(this,e,n)}var a=[];var o=(e.ignoreCase?\"i\":\"\")+(e.multiline?\"m\":\"\")+(e.unicode?\"u\":\"\")+(e.sticky?\"y\":\"\"),f=0,u,l,s,c;var h=new RegExp(e.source,o+\"g\");if(!t){u=new RegExp(\"^\"+h.source+\"$(?!\\\\s)\",o)}var p=typeof n===\"undefined\"?r:z.ToUint32(n);l=h.exec(i);while(l){s=l.index+l[0].length;if(s>f){_(a,K(i,f,l.index));if(!t&&l.length>1){l[0].replace(u,function(){for(var t=1;t<arguments.length-2;t++){if(typeof arguments[t]===\"undefined\"){l[t]=void 0}}})}if(l.length>1&&l.index<i.length){v.apply(a,W(l,1))}c=l[0].length;f=s;if(a.length>=p){break}}if(h.lastIndex===l.index){h.lastIndex++}l=h.exec(i)}if(f===i.length){if(c||!h.test(\"\")){_(a,\"\")}}else{_(a,K(i,f))}return a.length>p?W(a,0,p):a}})()}else if(\"0\".split(void 0,0).length){f.split=function split(t,r){if(typeof t===\"undefined\"&&r===0){return[]}return Q(this,t,r)}}var Dr=f.replace;var Sr=function(){var t=[];\"x\".replace(/x(.)?/g,function(r,e){_(t,e)});return t.length===1&&typeof t[0]===\"undefined\"}();if(!Sr){f.replace=function replace(t,r){var e=D(r);var n=M(t)&&/\\)[*?]/.test(t.source);if(!e||!n){return Dr.call(this,t,r)}else{var i=function(e){var n=arguments.length;var i=t.lastIndex;t.lastIndex=0;var a=t.exec(e)||[];t.lastIndex=i;_(a,arguments[n-2],arguments[n-1]);return r.apply(this,a)};return Dr.call(this,t,i)}}}var xr=f.substr;var Or=\"\".substr&&\"0b\".substr(-1)!==\"b\";P(f,{substr:function substr(t,r){var e=t;if(t<0){e=w(this.length+t,0)}return xr.call(this,e,r)}},Or);var Er=\"\\t\\n\\x0B\\f\\r \\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\"+\"\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\"+\"\\u2029\\ufeff\";var jr=\"\\u200b\";var Ir=\"[\"+Er+\"]\";var Mr=new RegExp(\"^\"+Ir+Ir+\"*\");var Ur=new RegExp(Ir+Ir+\"*$\");var $r=f.trim&&(Er.trim()||!jr.trim());P(f,{trim:function trim(){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}return o(this).replace(Mr,\"\").replace(Ur,\"\")}},$r);var Fr=d.bind(String.prototype.trim);var Nr=f.lastIndexOf&&\"abc\\u3042\\u3044\".lastIndexOf(\"\\u3042\\u3044\",2)!==-1;P(f,{lastIndexOf:function lastIndexOf(t){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}var r=o(this);var e=o(t);var n=arguments.length>1?u(arguments[1]):NaN;var i=Y(n)?Infinity:z.ToInteger(n);var a=b(w(i,0),r.length);var f=e.length;var l=a+f;while(l>0){l=w(0,l-f);var s=V(K(r,l,a+f),e);if(s!==-1){return l+s}}return-1}},Nr);var Cr=f.lastIndexOf;P(f,{lastIndexOf:function lastIndexOf(t){return Cr.apply(this,arguments)}},f.lastIndexOf.length!==1);if(parseInt(Er+\"08\")!==8||parseInt(Er+\"0x16\")!==22){parseInt=function(t){var r=/^[-+]?0[xX]/;return function parseInt(e,n){if(typeof e===\"symbol\"){\"\"+e}var i=Fr(String(e));var a=u(n)||(r.test(i)?16:10);return t(i,a)}}(parseInt)}if(1/parseFloat(\"-0\")!==-Infinity){parseFloat=function(t){return function parseFloat(r){var e=Fr(String(r));var n=t(e);return n===0&&K(e,0,1)===\"-\"?-0:n}}(parseFloat)}if(String(new RangeError(\"test\"))!==\"RangeError: test\"){var kr=function toString(){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}var t=this.name;if(typeof t===\"undefined\"){t=\"Error\"}else if(typeof t!==\"string\"){t=o(t)}var r=this.message;if(typeof r===\"undefined\"){r=\"\"}else if(typeof r!==\"string\"){r=o(r)}if(!t){return r}if(!r){return t}return t+\": \"+r};Error.prototype.toString=kr}if(R){var Ar=function(t,r){if(tt(t,r)){var e=Object.getOwnPropertyDescriptor(t,r);if(e.configurable){e.enumerable=false;Object.defineProperty(t,r,e)}}};Ar(Error.prototype,\"message\");if(Error.prototype.message!==\"\"){Error.prototype.message=\"\"}Ar(Error.prototype,\"name\")}if(String(/a/gim)!==\"/a/gim\"){var Rr=function toString(){var t=\"/\"+this.source+\"/\";if(this.global){t+=\"g\"}if(this.ignoreCase){t+=\"i\"}if(this.multiline){t+=\"m\"}return t};RegExp.prototype.toString=Rr}});\n//# sourceMappingURL=es5-shim.map\n/*!\n * https://github.com/paulmillr/es6-shim\n * @license es6-shim Copyright 2013-2016 by Paul Miller (http://paulmillr.com)\n *   and contributors,  MIT License\n * es6-shim: v0.35.4\n * see https://github.com/paulmillr/es6-shim/blob/0.35.4/LICENSE\n * Details and documentation:\n * https://github.com/paulmillr/es6-shim/\n */\n(function(e,t){if(typeof define===\"function\"&&define.amd){define(t)}else if(typeof exports===\"object\"){module.exports=t()}else{e.returnExports=t()}})(this,function(){\"use strict\";var e=Function.call.bind(Function.apply);var t=Function.call.bind(Function.call);var r=Array.isArray;var n=Object.keys;var o=function notThunker(t){return function notThunk(){return!e(t,this,arguments)}};var i=function(e){try{e();return false}catch(t){return true}};var a=function valueOrFalseIfThrows(e){try{return e()}catch(t){return false}};var u=o(i);var f=function(){return!i(function(){return Object.defineProperty({},\"x\",{get:function(){}})})};var s=!!Object.defineProperty&&f();var c=function foo(){}.name===\"foo\";var l=Function.call.bind(Array.prototype.forEach);var p=Function.call.bind(Array.prototype.reduce);var v=Function.call.bind(Array.prototype.filter);var y=Function.call.bind(Array.prototype.some);var h=function(e,t,r,n){if(!n&&t in e){return}if(s){Object.defineProperty(e,t,{configurable:true,enumerable:false,writable:true,value:r})}else{e[t]=r}};var b=function(e,t,r){l(n(t),function(n){var o=t[n];h(e,n,o,!!r)})};var g=Function.call.bind(Object.prototype.toString);var d=typeof/abc/===\"function\"?function IsCallableSlow(e){return typeof e===\"function\"&&g(e)===\"[object Function]\"}:function IsCallableFast(e){return typeof e===\"function\"};var m={getter:function(e,t,r){if(!s){throw new TypeError(\"getters require true ES5 support\")}Object.defineProperty(e,t,{configurable:true,enumerable:false,get:r})},proxy:function(e,t,r){if(!s){throw new TypeError(\"getters require true ES5 support\")}var n=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,{configurable:n.configurable,enumerable:n.enumerable,get:function getKey(){return e[t]},set:function setKey(r){e[t]=r}})},redefine:function(e,t,r){if(s){var n=Object.getOwnPropertyDescriptor(e,t);n.value=r;Object.defineProperty(e,t,n)}else{e[t]=r}},defineByDescriptor:function(e,t,r){if(s){Object.defineProperty(e,t,r)}else if(\"value\"in r){e[t]=r.value}},preserveToString:function(e,t){if(t&&d(t.toString)){h(e,\"toString\",t.toString.bind(t),true)}}};var O=Object.create||function(e,t){var r=function Prototype(){};r.prototype=e;var o=new r;if(typeof t!==\"undefined\"){n(t).forEach(function(e){m.defineByDescriptor(o,e,t[e])})}return o};var w=function(e,t){if(!Object.setPrototypeOf){return false}return a(function(){var r=function Subclass(t){var r=new e(t);Object.setPrototypeOf(r,Subclass.prototype);return r};Object.setPrototypeOf(r,e);r.prototype=O(e.prototype,{constructor:{value:r}});return t(r)})};var j=function(){if(typeof self!==\"undefined\"){return self}if(typeof window!==\"undefined\"){return window}if(typeof global!==\"undefined\"){return global}throw new Error(\"unable to locate global object\")};var S=j();var T=S.isFinite;var I=Function.call.bind(String.prototype.indexOf);var E=Function.apply.bind(Array.prototype.indexOf);var P=Function.call.bind(Array.prototype.concat);var C=Function.call.bind(String.prototype.slice);var M=Function.call.bind(Array.prototype.push);var x=Function.apply.bind(Array.prototype.push);var N=Function.call.bind(Array.prototype.shift);var A=Math.max;var R=Math.min;var _=Math.floor;var k=Math.abs;var L=Math.exp;var F=Math.log;var D=Math.sqrt;var z=Function.call.bind(Object.prototype.hasOwnProperty);var q;var W=function(){};var G=S.Map;var H=G&&G.prototype[\"delete\"];var V=G&&G.prototype.get;var B=G&&G.prototype.has;var U=G&&G.prototype.set;var $=S.Symbol||{};var J=$.species||\"@@species\";var X=Number.isNaN||function isNaN(e){return e!==e};var K=Number.isFinite||function isFinite(e){return typeof e===\"number\"&&T(e)};var Z=d(Math.sign)?Math.sign:function sign(e){var t=Number(e);if(t===0){return t}if(X(t)){return t}return t<0?-1:1};var Y=function log1p(e){var t=Number(e);if(t<-1||X(t)){return NaN}if(t===0||t===Infinity){return t}if(t===-1){return-Infinity}return 1+t-1===0?t:t*(F(1+t)/(1+t-1))};var Q=function isArguments(e){return g(e)===\"[object Arguments]\"};var ee=function isArguments(e){return e!==null&&typeof e===\"object\"&&typeof e.length===\"number\"&&e.length>=0&&g(e)!==\"[object Array]\"&&g(e.callee)===\"[object Function]\"};var te=Q(arguments)?Q:ee;var re={primitive:function(e){return e===null||typeof e!==\"function\"&&typeof e!==\"object\"},string:function(e){return g(e)===\"[object String]\"},regex:function(e){return g(e)===\"[object RegExp]\"},symbol:function(e){return typeof S.Symbol===\"function\"&&typeof e===\"symbol\"}};var ne=function overrideNative(e,t,r){var n=e[t];h(e,t,r,true);m.preserveToString(e[t],n)};var oe=typeof $===\"function\"&&typeof $[\"for\"]===\"function\"&&re.symbol($());var ie=re.symbol($.iterator)?$.iterator:\"_es6-shim iterator_\";if(S.Set&&typeof(new S.Set)[\"@@iterator\"]===\"function\"){ie=\"@@iterator\"}if(!S.Reflect){h(S,\"Reflect\",{},true)}var ae=S.Reflect;var ue=String;var fe=typeof document===\"undefined\"||!document?null:document.all;var se=fe==null?function isNullOrUndefined(e){return e==null}:function isNullOrUndefinedAndNotDocumentAll(e){return e==null&&e!==fe};var ce={Call:function Call(t,r){var n=arguments.length>2?arguments[2]:[];if(!ce.IsCallable(t)){throw new TypeError(t+\" is not a function\")}return e(t,r,n)},RequireObjectCoercible:function(e,t){if(se(e)){throw new TypeError(t||\"Cannot call method on \"+e)}return e},TypeIsObject:function(e){if(e===void 0||e===null||e===true||e===false){return false}return typeof e===\"function\"||typeof e===\"object\"||e===fe},ToObject:function(e,t){return Object(ce.RequireObjectCoercible(e,t))},IsCallable:d,IsConstructor:function(e){return ce.IsCallable(e)},ToInt32:function(e){return ce.ToNumber(e)>>0},ToUint32:function(e){return ce.ToNumber(e)>>>0},ToNumber:function(e){if(g(e)===\"[object Symbol]\"){throw new TypeError(\"Cannot convert a Symbol value to a number\")}return+e},ToInteger:function(e){var t=ce.ToNumber(e);if(X(t)){return 0}if(t===0||!K(t)){return t}return(t>0?1:-1)*_(k(t))},ToLength:function(e){var t=ce.ToInteger(e);if(t<=0){return 0}if(t>Number.MAX_SAFE_INTEGER){return Number.MAX_SAFE_INTEGER}return t},SameValue:function(e,t){if(e===t){if(e===0){return 1/e===1/t}return true}return X(e)&&X(t)},SameValueZero:function(e,t){return e===t||X(e)&&X(t)},IsIterable:function(e){return ce.TypeIsObject(e)&&(typeof e[ie]!==\"undefined\"||te(e))},GetIterator:function(e){if(te(e)){return new q(e,\"value\")}var t=ce.GetMethod(e,ie);if(!ce.IsCallable(t)){throw new TypeError(\"value is not an iterable\")}var r=ce.Call(t,e);if(!ce.TypeIsObject(r)){throw new TypeError(\"bad iterator\")}return r},GetMethod:function(e,t){var r=ce.ToObject(e)[t];if(se(r)){return void 0}if(!ce.IsCallable(r)){throw new TypeError(\"Method not callable: \"+t)}return r},IteratorComplete:function(e){return!!e.done},IteratorClose:function(e,t){var r=ce.GetMethod(e,\"return\");if(r===void 0){return}var n,o;try{n=ce.Call(r,e)}catch(i){o=i}if(t){return}if(o){throw o}if(!ce.TypeIsObject(n)){throw new TypeError(\"Iterator's return method returned a non-object.\")}},IteratorNext:function(e){var t=arguments.length>1?e.next(arguments[1]):e.next();if(!ce.TypeIsObject(t)){throw new TypeError(\"bad iterator\")}return t},IteratorStep:function(e){var t=ce.IteratorNext(e);var r=ce.IteratorComplete(t);return r?false:t},Construct:function(e,t,r,n){var o=typeof r===\"undefined\"?e:r;if(!n&&ae.construct){return ae.construct(e,t,o)}var i=o.prototype;if(!ce.TypeIsObject(i)){i=Object.prototype}var a=O(i);var u=ce.Call(e,a,t);return ce.TypeIsObject(u)?u:a},SpeciesConstructor:function(e,t){var r=e.constructor;if(r===void 0){return t}if(!ce.TypeIsObject(r)){throw new TypeError(\"Bad constructor\")}var n=r[J];if(se(n)){return t}if(!ce.IsConstructor(n)){throw new TypeError(\"Bad @@species\")}return n},CreateHTML:function(e,t,r,n){var o=ce.ToString(e);var i=\"<\"+t;if(r!==\"\"){var a=ce.ToString(n);var u=a.replace(/\"/g,\"&quot;\");i+=\" \"+r+'=\"'+u+'\"'}var f=i+\">\";var s=f+o;return s+\"</\"+t+\">\"},IsRegExp:function IsRegExp(e){if(!ce.TypeIsObject(e)){return false}var t=e[$.match];if(typeof t!==\"undefined\"){return!!t}return re.regex(e)},ToString:function ToString(e){return ue(e)}};if(s&&oe){var le=function defineWellKnownSymbol(e){if(re.symbol($[e])){return $[e]}var t=$[\"for\"](\"Symbol.\"+e);Object.defineProperty($,e,{configurable:false,enumerable:false,writable:false,value:t});return t};if(!re.symbol($.search)){var pe=le(\"search\");var ve=String.prototype.search;h(RegExp.prototype,pe,function search(e){return ce.Call(ve,e,[this])});var ye=function search(e){var t=ce.RequireObjectCoercible(this);if(!se(e)){var r=ce.GetMethod(e,pe);if(typeof r!==\"undefined\"){return ce.Call(r,e,[t])}}return ce.Call(ve,t,[ce.ToString(e)])};ne(String.prototype,\"search\",ye)}if(!re.symbol($.replace)){var he=le(\"replace\");var be=String.prototype.replace;h(RegExp.prototype,he,function replace(e,t){return ce.Call(be,e,[this,t])});var ge=function replace(e,t){var r=ce.RequireObjectCoercible(this);if(!se(e)){var n=ce.GetMethod(e,he);if(typeof n!==\"undefined\"){return ce.Call(n,e,[r,t])}}return ce.Call(be,r,[ce.ToString(e),t])};ne(String.prototype,\"replace\",ge)}if(!re.symbol($.split)){var de=le(\"split\");var me=String.prototype.split;h(RegExp.prototype,de,function split(e,t){return ce.Call(me,e,[this,t])});var Oe=function split(e,t){var r=ce.RequireObjectCoercible(this);if(!se(e)){var n=ce.GetMethod(e,de);if(typeof n!==\"undefined\"){return ce.Call(n,e,[r,t])}}return ce.Call(me,r,[ce.ToString(e),t])};ne(String.prototype,\"split\",Oe)}var we=re.symbol($.match);var je=we&&function(){var e={};e[$.match]=function(){return 42};return\"a\".match(e)!==42}();if(!we||je){var Se=le(\"match\");var Te=String.prototype.match;h(RegExp.prototype,Se,function match(e){return ce.Call(Te,e,[this])});var Ie=function match(e){var t=ce.RequireObjectCoercible(this);if(!se(e)){var r=ce.GetMethod(e,Se);if(typeof r!==\"undefined\"){return ce.Call(r,e,[t])}}return ce.Call(Te,t,[ce.ToString(e)])};ne(String.prototype,\"match\",Ie)}}var Ee=function wrapConstructor(e,t,r){m.preserveToString(t,e);if(Object.setPrototypeOf){Object.setPrototypeOf(e,t)}if(s){l(Object.getOwnPropertyNames(e),function(n){if(n in W||r[n]){return}m.proxy(e,n,t)})}else{l(Object.keys(e),function(n){if(n in W||r[n]){return}t[n]=e[n]})}t.prototype=e.prototype;m.redefine(e.prototype,\"constructor\",t)};var Pe=function(){return this};var Ce=function(e){if(s&&!z(e,J)){m.getter(e,J,Pe)}};var Me=function(e,t){var r=t||function iterator(){return this};h(e,ie,r);if(!e[ie]&&re.symbol(ie)){e[ie]=r}};var xe=function createDataProperty(e,t,r){if(s){Object.defineProperty(e,t,{configurable:true,enumerable:true,writable:true,value:r})}else{e[t]=r}};var Ne=function createDataPropertyOrThrow(e,t,r){xe(e,t,r);if(!ce.SameValue(e[t],r)){throw new TypeError(\"property is nonconfigurable\")}};var Ae=function(e,t,r,n){if(!ce.TypeIsObject(e)){throw new TypeError(\"Constructor requires `new`: \"+t.name)}var o=t.prototype;if(!ce.TypeIsObject(o)){o=r}var i=O(o);for(var a in n){if(z(n,a)){var u=n[a];h(i,a,u,true)}}return i};if(String.fromCodePoint&&String.fromCodePoint.length!==1){var Re=String.fromCodePoint;ne(String,\"fromCodePoint\",function fromCodePoint(e){return ce.Call(Re,this,arguments)})}var _e={fromCodePoint:function fromCodePoint(e){var t=[];var r;for(var n=0,o=arguments.length;n<o;n++){r=Number(arguments[n]);if(!ce.SameValue(r,ce.ToInteger(r))||r<0||r>1114111){throw new RangeError(\"Invalid code point \"+r)}if(r<65536){M(t,String.fromCharCode(r))}else{r-=65536;M(t,String.fromCharCode((r>>10)+55296));M(t,String.fromCharCode(r%1024+56320))}}return t.join(\"\")},raw:function raw(e){var t=ce.ToObject(e,\"bad callSite\");var r=ce.ToObject(t.raw,\"bad raw value\");var n=r.length;var o=ce.ToLength(n);if(o<=0){return\"\"}var i=[];var a=0;var u,f,s,c;while(a<o){u=ce.ToString(a);s=ce.ToString(r[u]);M(i,s);if(a+1>=o){break}f=a+1<arguments.length?arguments[a+1]:\"\";c=ce.ToString(f);M(i,c);a+=1}return i.join(\"\")}};if(String.raw&&String.raw({raw:{0:\"x\",1:\"y\",length:2}})!==\"xy\"){ne(String,\"raw\",_e.raw)}b(String,_e);var ke=function repeat(e,t){if(t<1){return\"\"}if(t%2){return repeat(e,t-1)+e}var r=repeat(e,t/2);return r+r};var Le=Infinity;var Fe={repeat:function repeat(e){var t=ce.ToString(ce.RequireObjectCoercible(this));var r=ce.ToInteger(e);if(r<0||r>=Le){throw new RangeError(\"repeat count must be less than infinity and not overflow maximum string size\")}return ke(t,r)},startsWith:function startsWith(e){var t=ce.ToString(ce.RequireObjectCoercible(this));if(ce.IsRegExp(e)){throw new TypeError('Cannot call method \"startsWith\" with a regex')}var r=ce.ToString(e);var n;if(arguments.length>1){n=arguments[1]}var o=A(ce.ToInteger(n),0);return C(t,o,o+r.length)===r},endsWith:function endsWith(e){var t=ce.ToString(ce.RequireObjectCoercible(this));if(ce.IsRegExp(e)){throw new TypeError('Cannot call method \"endsWith\" with a regex')}var r=ce.ToString(e);var n=t.length;var o;if(arguments.length>1){o=arguments[1]}var i=typeof o===\"undefined\"?n:ce.ToInteger(o);var a=R(A(i,0),n);return C(t,a-r.length,a)===r},includes:function includes(e){if(ce.IsRegExp(e)){throw new TypeError('\"includes\" does not accept a RegExp')}var t=ce.ToString(e);var r;if(arguments.length>1){r=arguments[1]}return I(this,t,r)!==-1},codePointAt:function codePointAt(e){var t=ce.ToString(ce.RequireObjectCoercible(this));var r=ce.ToInteger(e);var n=t.length;if(r>=0&&r<n){var o=t.charCodeAt(r);var i=r+1===n;if(o<55296||o>56319||i){return o}var a=t.charCodeAt(r+1);if(a<56320||a>57343){return o}return(o-55296)*1024+(a-56320)+65536}}};if(String.prototype.includes&&\"a\".includes(\"a\",Infinity)!==false){ne(String.prototype,\"includes\",Fe.includes)}if(String.prototype.startsWith&&String.prototype.endsWith){var De=i(function(){return\"/a/\".startsWith(/a/)});var ze=a(function(){return\"abc\".startsWith(\"a\",Infinity)===false});if(!De||!ze){ne(String.prototype,\"startsWith\",Fe.startsWith);ne(String.prototype,\"endsWith\",Fe.endsWith)}}if(oe){var qe=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".startsWith(e)});if(!qe){ne(String.prototype,\"startsWith\",Fe.startsWith)}var We=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".endsWith(e)});if(!We){ne(String.prototype,\"endsWith\",Fe.endsWith)}var Ge=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".includes(e)});if(!Ge){ne(String.prototype,\"includes\",Fe.includes)}}b(String.prototype,Fe);var He=[\"\\t\\n\\x0B\\f\\r \\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\",\"\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\",\"\\u2029\\ufeff\"].join(\"\");var Ve=new RegExp(\"(^[\"+He+\"]+)|([\"+He+\"]+$)\",\"g\");var Be=function trim(){return ce.ToString(ce.RequireObjectCoercible(this)).replace(Ve,\"\")};var Ue=[\"\\x85\",\"\\u200b\",\"\\ufffe\"].join(\"\");var $e=new RegExp(\"[\"+Ue+\"]\",\"g\");var Je=/^[-+]0x[0-9a-f]+$/i;var Xe=Ue.trim().length!==Ue.length;h(String.prototype,\"trim\",Be,Xe);var Ke=function(e){return{value:e,done:arguments.length===0}};var Ze=function(e){ce.RequireObjectCoercible(e);this._s=ce.ToString(e);this._i=0};Ze.prototype.next=function(){var e=this._s;var t=this._i;if(typeof e===\"undefined\"||t>=e.length){this._s=void 0;return Ke()}var r=e.charCodeAt(t);var n,o;if(r<55296||r>56319||t+1===e.length){o=1}else{n=e.charCodeAt(t+1);o=n<56320||n>57343?1:2}this._i=t+o;return Ke(e.substr(t,o))};Me(Ze.prototype);Me(String.prototype,function(){return new Ze(this)});var Ye={from:function from(e){var r=this;var n;if(arguments.length>1){n=arguments[1]}var o,i;if(typeof n===\"undefined\"){o=false}else{if(!ce.IsCallable(n)){throw new TypeError(\"Array.from: when provided, the second argument must be a function\")}if(arguments.length>2){i=arguments[2]}o=true}var a=typeof(te(e)||ce.GetMethod(e,ie))!==\"undefined\";var u,f,s;if(a){f=ce.IsConstructor(r)?Object(new r):[];var c=ce.GetIterator(e);var l,p;s=0;while(true){l=ce.IteratorStep(c);if(l===false){break}p=l.value;try{if(o){p=typeof i===\"undefined\"?n(p,s):t(n,i,p,s)}f[s]=p}catch(v){ce.IteratorClose(c,true);throw v}s+=1}u=s}else{var y=ce.ToObject(e);u=ce.ToLength(y.length);f=ce.IsConstructor(r)?Object(new r(u)):new Array(u);var h;for(s=0;s<u;++s){h=y[s];if(o){h=typeof i===\"undefined\"?n(h,s):t(n,i,h,s)}Ne(f,s,h)}}f.length=u;return f},of:function of(){var e=arguments.length;var t=this;var n=r(t)||!ce.IsCallable(t)?new Array(e):ce.Construct(t,[e]);for(var o=0;o<e;++o){Ne(n,o,arguments[o])}n.length=e;return n}};b(Array,Ye);Ce(Array);q=function(e,t){this.i=0;this.array=e;this.kind=t};b(q.prototype,{next:function(){var e=this.i;var t=this.array;if(!(this instanceof q)){throw new TypeError(\"Not an ArrayIterator\")}if(typeof t!==\"undefined\"){var r=ce.ToLength(t.length);for(;e<r;e++){var n=this.kind;var o;if(n===\"key\"){o=e}else if(n===\"value\"){o=t[e]}else if(n===\"entry\"){o=[e,t[e]]}this.i=e+1;return Ke(o)}}this.array=void 0;return Ke()}});Me(q.prototype);var Qe=Array.of===Ye.of||function(){var e=function Foo(e){this.length=e};e.prototype=[];var t=Array.of.apply(e,[1,2]);return t instanceof e&&t.length===2}();if(!Qe){ne(Array,\"of\",Ye.of)}var et={copyWithin:function copyWithin(e,t){var r=ce.ToObject(this);var n=ce.ToLength(r.length);var o=ce.ToInteger(e);var i=ce.ToInteger(t);var a=o<0?A(n+o,0):R(o,n);var u=i<0?A(n+i,0):R(i,n);var f;if(arguments.length>2){f=arguments[2]}var s=typeof f===\"undefined\"?n:ce.ToInteger(f);var c=s<0?A(n+s,0):R(s,n);var l=R(c-u,n-a);var p=1;if(u<a&&a<u+l){p=-1;u+=l-1;a+=l-1}while(l>0){if(u in r){r[a]=r[u]}else{delete r[a]}u+=p;a+=p;l-=1}return r},fill:function fill(e){var t;if(arguments.length>1){t=arguments[1]}var r;if(arguments.length>2){r=arguments[2]}var n=ce.ToObject(this);var o=ce.ToLength(n.length);t=ce.ToInteger(typeof t===\"undefined\"?0:t);r=ce.ToInteger(typeof r===\"undefined\"?o:r);var i=t<0?A(o+t,0):R(t,o);var a=r<0?o+r:r;for(var u=i;u<o&&u<a;++u){n[u]=e}return n},find:function find(e){var r=ce.ToObject(this);var n=ce.ToLength(r.length);if(!ce.IsCallable(e)){throw new TypeError(\"Array#find: predicate must be a function\")}var o=arguments.length>1?arguments[1]:null;for(var i=0,a;i<n;i++){a=r[i];if(o){if(t(e,o,a,i,r)){return a}}else if(e(a,i,r)){return a}}},findIndex:function findIndex(e){var r=ce.ToObject(this);var n=ce.ToLength(r.length);if(!ce.IsCallable(e)){throw new TypeError(\"Array#findIndex: predicate must be a function\")}var o=arguments.length>1?arguments[1]:null;for(var i=0;i<n;i++){if(o){if(t(e,o,r[i],i,r)){return i}}else if(e(r[i],i,r)){return i}}return-1},keys:function keys(){return new q(this,\"key\")},values:function values(){return new q(this,\"value\")},entries:function entries(){return new q(this,\"entry\")}};if(Array.prototype.keys&&!ce.IsCallable([1].keys().next)){delete Array.prototype.keys}if(Array.prototype.entries&&!ce.IsCallable([1].entries().next)){delete Array.prototype.entries}if(Array.prototype.keys&&Array.prototype.entries&&!Array.prototype.values&&Array.prototype[ie]){b(Array.prototype,{values:Array.prototype[ie]});if(re.symbol($.unscopables)){Array.prototype[$.unscopables].values=true}}if(c&&Array.prototype.values&&Array.prototype.values.name!==\"values\"){var tt=Array.prototype.values;ne(Array.prototype,\"values\",function values(){return ce.Call(tt,this,arguments)});h(Array.prototype,ie,Array.prototype.values,true)}b(Array.prototype,et);if(1/[true].indexOf(true,-0)<0){h(Array.prototype,\"indexOf\",function indexOf(e){var t=E(this,arguments);if(t===0&&1/t<0){return 0}return t},true)}Me(Array.prototype,function(){return this.values()});if(Object.getPrototypeOf){Me(Object.getPrototypeOf([].values()))}var rt=function(){return a(function(){return Array.from({length:-1}).length===0})}();var nt=function(){var e=Array.from([0].entries());return e.length===1&&r(e[0])&&e[0][0]===0&&e[0][1]===0}();if(!rt||!nt){ne(Array,\"from\",Ye.from)}var ot=function(){return a(function(){return Array.from([0],void 0)})}();if(!ot){var it=Array.from;ne(Array,\"from\",function from(e){if(arguments.length>1&&typeof arguments[1]!==\"undefined\"){return ce.Call(it,this,arguments)}else{return t(it,this,e)}})}var at=-(Math.pow(2,32)-1);var ut=function(e,r){var n={length:at};n[r?(n.length>>>0)-1:0]=true;return a(function(){t(e,n,function(){throw new RangeError(\"should not reach here\")},[]);return true})};if(!ut(Array.prototype.forEach)){var ft=Array.prototype.forEach;ne(Array.prototype,\"forEach\",function forEach(e){return ce.Call(ft,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.map)){var st=Array.prototype.map;ne(Array.prototype,\"map\",function map(e){return ce.Call(st,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.filter)){var ct=Array.prototype.filter;ne(Array.prototype,\"filter\",function filter(e){return ce.Call(ct,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.some)){var lt=Array.prototype.some;ne(Array.prototype,\"some\",function some(e){return ce.Call(lt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.every)){var pt=Array.prototype.every;ne(Array.prototype,\"every\",function every(e){return ce.Call(pt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.reduce)){var vt=Array.prototype.reduce;ne(Array.prototype,\"reduce\",function reduce(e){return ce.Call(vt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.reduceRight,true)){var yt=Array.prototype.reduceRight;ne(Array.prototype,\"reduceRight\",function reduceRight(e){return ce.Call(yt,this.length>=0?this:[],arguments)},true)}var ht=Number(\"0o10\")!==8;var bt=Number(\"0b10\")!==2;var gt=y(Ue,function(e){return Number(e+0+e)===0});if(ht||bt||gt){var dt=Number;var mt=/^0b[01]+$/i;var Ot=/^0o[0-7]+$/i;var wt=mt.test.bind(mt);var jt=Ot.test.bind(Ot);var St=function(e){var t;if(typeof e.valueOf===\"function\"){t=e.valueOf();if(re.primitive(t)){return t}}if(typeof e.toString===\"function\"){t=e.toString();if(re.primitive(t)){return t}}throw new TypeError(\"No default value\")};var Tt=$e.test.bind($e);var It=Je.test.bind(Je);var Et=function(){var e=function Number(t){var r;if(arguments.length>0){r=re.primitive(t)?t:St(t,\"number\")}else{r=0}if(typeof r===\"string\"){r=ce.Call(Be,r);if(wt(r)){r=parseInt(C(r,2),2)}else if(jt(r)){r=parseInt(C(r,2),8)}else if(Tt(r)||It(r)){r=NaN}}var n=this;var o=a(function(){dt.prototype.valueOf.call(n);return true});if(n instanceof e&&!o){return new dt(r)}return dt(r)};return e}();Ee(dt,Et,{});b(Et,{NaN:dt.NaN,MAX_VALUE:dt.MAX_VALUE,MIN_VALUE:dt.MIN_VALUE,NEGATIVE_INFINITY:dt.NEGATIVE_INFINITY,POSITIVE_INFINITY:dt.POSITIVE_INFINITY});Number=Et;m.redefine(S,\"Number\",Et)}var Pt=Math.pow(2,53)-1;b(Number,{MAX_SAFE_INTEGER:Pt,MIN_SAFE_INTEGER:-Pt,EPSILON:2.220446049250313e-16,parseInt:S.parseInt,parseFloat:S.parseFloat,isFinite:K,isInteger:function isInteger(e){return K(e)&&ce.ToInteger(e)===e},isSafeInteger:function isSafeInteger(e){return Number.isInteger(e)&&k(e)<=Number.MAX_SAFE_INTEGER},isNaN:X});h(Number,\"parseInt\",S.parseInt,Number.parseInt!==S.parseInt);if([,1].find(function(){return true})===1){ne(Array.prototype,\"find\",et.find)}if([,1].findIndex(function(){return true})!==0){ne(Array.prototype,\"findIndex\",et.findIndex)}var Ct=Function.bind.call(Function.bind,Object.prototype.propertyIsEnumerable);var Mt=function ensureEnumerable(e,t){if(s&&Ct(e,t)){Object.defineProperty(e,t,{enumerable:false})}};var xt=function sliceArgs(){var e=Number(this);var t=arguments.length;var r=t-e;var n=new Array(r<0?0:r);for(var o=e;o<t;++o){n[o-e]=arguments[o]}return n};var Nt=function assignTo(e){return function assignToSource(t,r){t[r]=e[r];return t}};var At=function(e,t){var r=n(Object(t));var o;if(ce.IsCallable(Object.getOwnPropertySymbols)){o=v(Object.getOwnPropertySymbols(Object(t)),Ct(t))}return p(P(r,o||[]),Nt(t),e)};var Rt={assign:function(e,t){var r=ce.ToObject(e,\"Cannot convert undefined or null to object\");return p(ce.Call(xt,1,arguments),At,r)},is:function is(e,t){return ce.SameValue(e,t)}};var _t=Object.assign&&Object.preventExtensions&&function(){var e=Object.preventExtensions({1:2});try{Object.assign(e,\"xy\")}catch(t){return e[1]===\"y\"}}();if(_t){ne(Object,\"assign\",Rt.assign)}b(Object,Rt);if(s){var kt={setPrototypeOf:function(e,r){var n;var o=function(e,t){if(!ce.TypeIsObject(e)){throw new TypeError(\"cannot set prototype on a non-object\")}if(!(t===null||ce.TypeIsObject(t))){throw new TypeError(\"can only set prototype to an object or null\"+t)}};var i=function(e,r){o(e,r);t(n,e,r);return e};try{n=e.getOwnPropertyDescriptor(e.prototype,r).set;t(n,{},null)}catch(a){if(e.prototype!=={}[r]){return}n=function(e){this[r]=e};i.polyfill=i(i({},null),e.prototype)instanceof e}return i}(Object,\"__proto__\")};b(Object,kt)}if(Object.setPrototypeOf&&Object.getPrototypeOf&&Object.getPrototypeOf(Object.setPrototypeOf({},null))!==null&&Object.getPrototypeOf(Object.create(null))===null){(function(){var e=Object.create(null);var t=Object.getPrototypeOf;var r=Object.setPrototypeOf;Object.getPrototypeOf=function(r){var n=t(r);return n===e?null:n};Object.setPrototypeOf=function(t,n){var o=n===null?e:n;return r(t,o)};Object.setPrototypeOf.polyfill=false})()}var Lt=!i(function(){return Object.keys(\"foo\")});if(!Lt){var Ft=Object.keys;ne(Object,\"keys\",function keys(e){return Ft(ce.ToObject(e))});n=Object.keys}var Dt=i(function(){return Object.keys(/a/g)});if(Dt){var zt=Object.keys;ne(Object,\"keys\",function keys(e){if(re.regex(e)){var t=[];for(var r in e){if(z(e,r)){M(t,r)}}return t}return zt(e)});n=Object.keys}if(Object.getOwnPropertyNames){var qt=!i(function(){return Object.getOwnPropertyNames(\"foo\")});if(!qt){var Wt=typeof window===\"object\"?Object.getOwnPropertyNames(window):[];var Gt=Object.getOwnPropertyNames;ne(Object,\"getOwnPropertyNames\",function getOwnPropertyNames(e){var t=ce.ToObject(e);if(g(t)===\"[object Window]\"){try{return Gt(t)}catch(r){return P([],Wt)}}return Gt(t)})}}if(Object.getOwnPropertyDescriptor){var Ht=!i(function(){return Object.getOwnPropertyDescriptor(\"foo\",\"bar\")});if(!Ht){var Vt=Object.getOwnPropertyDescriptor;ne(Object,\"getOwnPropertyDescriptor\",function getOwnPropertyDescriptor(e,t){return Vt(ce.ToObject(e),t)})}}if(Object.seal){var Bt=!i(function(){return Object.seal(\"foo\")});if(!Bt){var Ut=Object.seal;ne(Object,\"seal\",function seal(e){if(!ce.TypeIsObject(e)){return e}return Ut(e)})}}if(Object.isSealed){var $t=!i(function(){return Object.isSealed(\"foo\")});if(!$t){var Jt=Object.isSealed;ne(Object,\"isSealed\",function isSealed(e){if(!ce.TypeIsObject(e)){return true}return Jt(e)})}}if(Object.freeze){var Xt=!i(function(){return Object.freeze(\"foo\")});if(!Xt){var Kt=Object.freeze;ne(Object,\"freeze\",function freeze(e){if(!ce.TypeIsObject(e)){return e}return Kt(e)})}}if(Object.isFrozen){var Zt=!i(function(){return Object.isFrozen(\"foo\")});if(!Zt){var Yt=Object.isFrozen;ne(Object,\"isFrozen\",function isFrozen(e){if(!ce.TypeIsObject(e)){return true}return Yt(e)})}}if(Object.preventExtensions){var Qt=!i(function(){return Object.preventExtensions(\"foo\")});if(!Qt){var er=Object.preventExtensions;ne(Object,\"preventExtensions\",function preventExtensions(e){if(!ce.TypeIsObject(e)){return e}return er(e)})}}if(Object.isExtensible){var tr=!i(function(){return Object.isExtensible(\"foo\")});if(!tr){var rr=Object.isExtensible;ne(Object,\"isExtensible\",function isExtensible(e){if(!ce.TypeIsObject(e)){return false}return rr(e)})}}if(Object.getPrototypeOf){var nr=!i(function(){return Object.getPrototypeOf(\"foo\")});if(!nr){var or=Object.getPrototypeOf;ne(Object,\"getPrototypeOf\",function getPrototypeOf(e){return or(ce.ToObject(e))})}}var ir=s&&function(){var e=Object.getOwnPropertyDescriptor(RegExp.prototype,\"flags\");return e&&ce.IsCallable(e.get)}();if(s&&!ir){var ar=function flags(){if(!ce.TypeIsObject(this)){throw new TypeError(\"Method called on incompatible type: must be an object.\")}var e=\"\";if(this.global){e+=\"g\"}if(this.ignoreCase){e+=\"i\"}if(this.multiline){e+=\"m\"}if(this.unicode){e+=\"u\"}if(this.sticky){e+=\"y\"}return e};m.getter(RegExp.prototype,\"flags\",ar)}var ur=s&&a(function(){return String(new RegExp(/a/g,\"i\"))===\"/a/i\"});var fr=oe&&s&&function(){var e=/./;e[$.match]=false;return RegExp(e)===e}();var sr=a(function(){return RegExp.prototype.toString.call({source:\"abc\"})===\"/abc/\"});var cr=sr&&a(function(){return RegExp.prototype.toString.call({source:\"a\",flags:\"b\"})===\"/a/b\"});if(!sr||!cr){var lr=RegExp.prototype.toString;h(RegExp.prototype,\"toString\",function toString(){var e=ce.RequireObjectCoercible(this);if(re.regex(e)){return t(lr,e)}var r=ue(e.source);var n=ue(e.flags);return\"/\"+r+\"/\"+n},true);m.preserveToString(RegExp.prototype.toString,lr)}if(s&&(!ur||fr)){var pr=Object.getOwnPropertyDescriptor(RegExp.prototype,\"flags\").get;var vr=Object.getOwnPropertyDescriptor(RegExp.prototype,\"source\")||{};var yr=function(){return this.source};var hr=ce.IsCallable(vr.get)?vr.get:yr;var br=RegExp;var gr=function(){return function RegExp(e,t){var r=ce.IsRegExp(e);var n=this instanceof RegExp;if(!n&&r&&typeof t===\"undefined\"&&e.constructor===RegExp){return e}var o=e;var i=t;if(re.regex(e)){o=ce.Call(hr,e);i=typeof t===\"undefined\"?ce.Call(pr,e):t;return new RegExp(o,i)}else if(r){o=e.source;i=typeof t===\"undefined\"?e.flags:t}return new br(e,t)}}();Ee(br,gr,{$input:true});RegExp=gr;m.redefine(S,\"RegExp\",gr)}if(s){var dr={input:\"$_\",lastMatch:\"$&\",lastParen:\"$+\",leftContext:\"$`\",rightContext:\"$'\"};l(n(dr),function(e){if(e in RegExp&&!(dr[e]in RegExp)){m.getter(RegExp,dr[e],function get(){return RegExp[e]})}})}Ce(RegExp);var mr=1/Number.EPSILON;var Or=function roundTiesToEven(e){return e+mr-mr};var wr=Math.pow(2,-23);var jr=Math.pow(2,127)*(2-wr);var Sr=Math.pow(2,-126);var Tr=Math.E;var Ir=Math.LOG2E;var Er=Math.LOG10E;var Pr=Number.prototype.clz;delete Number.prototype.clz;var Cr={acosh:function acosh(e){var t=Number(e);if(X(t)||e<1){return NaN}if(t===1){return 0}if(t===Infinity){return t}var r=1/(t*t);if(t<2){return Y(t-1+D(1-r)*t)}var n=t/2;return Y(n+D(1-r)*n-1)+1/Ir},asinh:function asinh(e){var t=Number(e);if(t===0||!T(t)){return t}var r=k(t);var n=r*r;var o=Z(t);if(r<1){return o*Y(r+n/(D(n+1)+1))}return o*(Y(r/2+D(1+1/n)*r/2-1)+1/Ir)},atanh:function atanh(e){var t=Number(e);if(t===0){return t}if(t===-1){return-Infinity}if(t===1){return Infinity}if(X(t)||t<-1||t>1){return NaN}var r=k(t);return Z(t)*Y(2*r/(1-r))/2},cbrt:function cbrt(e){var t=Number(e);if(t===0){return t}var r=t<0;var n;if(r){t=-t}if(t===Infinity){n=Infinity}else{n=L(F(t)/3);n=(t/(n*n)+2*n)/3}return r?-n:n},clz32:function clz32(e){var t=Number(e);var r=ce.ToUint32(t);if(r===0){return 32}return Pr?ce.Call(Pr,r):31-_(F(r+.5)*Ir)},cosh:function cosh(e){var t=Number(e);if(t===0){return 1}if(X(t)){return NaN}if(!T(t)){return Infinity}var r=L(k(t)-1);return(r+1/(r*Tr*Tr))*(Tr/2)},expm1:function expm1(e){var t=Number(e);if(t===-Infinity){return-1}if(!T(t)||t===0){return t}if(k(t)>.5){return L(t)-1}var r=t;var n=0;var o=1;while(n+r!==n){n+=r;o+=1;r*=t/o}return n},hypot:function hypot(e,t){var r=0;var n=0;for(var o=0;o<arguments.length;++o){var i=k(Number(arguments[o]));if(n<i){r*=n/i*(n/i);r+=1;n=i}else{r+=i>0?i/n*(i/n):i}}return n===Infinity?Infinity:n*D(r)},log2:function log2(e){return F(e)*Ir},log10:function log10(e){return F(e)*Er},log1p:Y,sign:Z,sinh:function sinh(e){var t=Number(e);if(!T(t)||t===0){return t}var r=k(t);if(r<1){var n=Math.expm1(r);return Z(t)*n*(1+1/(n+1))/2}var o=L(r-1);return Z(t)*(o-1/(o*Tr*Tr))*(Tr/2)},tanh:function tanh(e){var t=Number(e);if(X(t)||t===0){return t}if(t>=20){return 1}if(t<=-20){return-1}return(Math.expm1(t)-Math.expm1(-t))/(L(t)+L(-t))},trunc:function trunc(e){var t=Number(e);return t<0?-_(-t):_(t)},imul:function imul(e,t){var r=ce.ToUint32(e);var n=ce.ToUint32(t);var o=r>>>16&65535;var i=r&65535;var a=n>>>16&65535;var u=n&65535;return i*u+(o*u+i*a<<16>>>0)|0},fround:function fround(e){var t=Number(e);if(t===0||t===Infinity||t===-Infinity||X(t)){return t}var r=Z(t);var n=k(t);if(n<Sr){return r*Or(n/Sr/wr)*Sr*wr}var o=(1+wr/Number.EPSILON)*n;var i=o-(o-n);if(i>jr||X(i)){return r*Infinity}return r*i}};var Mr=function withinULPDistance(e,t,r){return k(1-e/t)/Number.EPSILON<(r||8)};b(Math,Cr);h(Math,\"sinh\",Cr.sinh,Math.sinh(710)===Infinity);h(Math,\"cosh\",Cr.cosh,Math.cosh(710)===Infinity);h(Math,\"log1p\",Cr.log1p,Math.log1p(-1e-17)!==-1e-17);h(Math,\"asinh\",Cr.asinh,Math.asinh(-1e7)!==-Math.asinh(1e7));h(Math,\"asinh\",Cr.asinh,Math.asinh(1e300)===Infinity);h(Math,\"atanh\",Cr.atanh,Math.atanh(1e-300)===0);h(Math,\"tanh\",Cr.tanh,Math.tanh(-2e-17)!==-2e-17);\nh(Math,\"acosh\",Cr.acosh,Math.acosh(Number.MAX_VALUE)===Infinity);h(Math,\"acosh\",Cr.acosh,!Mr(Math.acosh(1+Number.EPSILON),Math.sqrt(2*Number.EPSILON)));h(Math,\"cbrt\",Cr.cbrt,!Mr(Math.cbrt(1e-300),1e-100));h(Math,\"sinh\",Cr.sinh,Math.sinh(-2e-17)!==-2e-17);var xr=Math.expm1(10);h(Math,\"expm1\",Cr.expm1,xr>22025.465794806718||xr<22025.465794806718);var Nr=Math.round;var Ar=Math.round(.5-Number.EPSILON/4)===0&&Math.round(-.5+Number.EPSILON/3.99)===1;var Rr=mr+1;var _r=2*mr-1;var kr=[Rr,_r].every(function(e){return Math.round(e)===e});h(Math,\"round\",function round(e){var t=_(e);var r=t===-1?-0:t+1;return e-t<.5?t:r},!Ar||!kr);m.preserveToString(Math.round,Nr);var Lr=Math.imul;if(Math.imul(4294967295,5)!==-5){Math.imul=Cr.imul;m.preserveToString(Math.imul,Lr)}if(Math.imul.length!==2){ne(Math,\"imul\",function imul(e,t){return ce.Call(Lr,Math,arguments)})}var Fr=function(){var e=S.setTimeout;if(typeof e!==\"function\"&&typeof e!==\"object\"){return}ce.IsPromise=function(e){if(!ce.TypeIsObject(e)){return false}if(typeof e._promise===\"undefined\"){return false}return true};var r=function(e){if(!ce.IsConstructor(e)){throw new TypeError(\"Bad promise constructor\")}var t=this;var r=function(e,r){if(t.resolve!==void 0||t.reject!==void 0){throw new TypeError(\"Bad Promise implementation!\")}t.resolve=e;t.reject=r};t.resolve=void 0;t.reject=void 0;t.promise=new e(r);if(!(ce.IsCallable(t.resolve)&&ce.IsCallable(t.reject))){throw new TypeError(\"Bad promise constructor\")}};var n;if(typeof window!==\"undefined\"&&ce.IsCallable(window.postMessage)){n=function(){var e=[];var t=\"zero-timeout-message\";var r=function(r){M(e,r);window.postMessage(t,\"*\")};var n=function(r){if(r.source===window&&r.data===t){r.stopPropagation();if(e.length===0){return}var n=N(e);n()}};window.addEventListener(\"message\",n,true);return r}}var o=function(){var e=S.Promise;var t=e&&e.resolve&&e.resolve();return t&&function(e){return t.then(e)}};var i=ce.IsCallable(S.setImmediate)?S.setImmediate:typeof process===\"object\"&&process.nextTick?process.nextTick:o()||(ce.IsCallable(n)?n():function(t){e(t,0)});var a=function(e){return e};var u=function(e){throw e};var f=0;var s=1;var c=2;var l=0;var p=1;var v=2;var y={};var h=function(e,t,r){i(function(){g(e,t,r)})};var g=function(e,t,r){var n,o;if(t===y){return e(r)}try{n=e(r);o=t.resolve}catch(i){n=i;o=t.reject}o(n)};var d=function(e,t){var r=e._promise;var n=r.reactionLength;if(n>0){h(r.fulfillReactionHandler0,r.reactionCapability0,t);r.fulfillReactionHandler0=void 0;r.rejectReactions0=void 0;r.reactionCapability0=void 0;if(n>1){for(var o=1,i=0;o<n;o++,i+=3){h(r[i+l],r[i+v],t);e[i+l]=void 0;e[i+p]=void 0;e[i+v]=void 0}}}r.result=t;r.state=s;r.reactionLength=0};var m=function(e,t){var r=e._promise;var n=r.reactionLength;if(n>0){h(r.rejectReactionHandler0,r.reactionCapability0,t);r.fulfillReactionHandler0=void 0;r.rejectReactions0=void 0;r.reactionCapability0=void 0;if(n>1){for(var o=1,i=0;o<n;o++,i+=3){h(r[i+p],r[i+v],t);e[i+l]=void 0;e[i+p]=void 0;e[i+v]=void 0}}}r.result=t;r.state=c;r.reactionLength=0};var O=function(e){var t=false;var r=function(r){var n;if(t){return}t=true;if(r===e){return m(e,new TypeError(\"Self resolution\"))}if(!ce.TypeIsObject(r)){return d(e,r)}try{n=r.then}catch(o){return m(e,o)}if(!ce.IsCallable(n)){return d(e,r)}i(function(){j(e,r,n)})};var n=function(r){if(t){return}t=true;return m(e,r)};return{resolve:r,reject:n}};var w=function(e,r,n,o){if(e===I){t(e,r,n,o,y)}else{t(e,r,n,o)}};var j=function(e,t,r){var n=O(e);var o=n.resolve;var i=n.reject;try{w(r,t,o,i)}catch(a){i(a)}};var T,I;var E=function(){var e=function Promise(t){if(!(this instanceof e)){throw new TypeError('Constructor Promise requires \"new\"')}if(this&&this._promise){throw new TypeError(\"Bad construction\")}if(!ce.IsCallable(t)){throw new TypeError(\"not a valid resolver\")}var r=Ae(this,e,T,{_promise:{result:void 0,state:f,reactionLength:0,fulfillReactionHandler0:void 0,rejectReactionHandler0:void 0,reactionCapability0:void 0}});var n=O(r);var o=n.reject;try{t(n.resolve,o)}catch(i){o(i)}return r};return e}();T=E.prototype;var P=function(e,t,r,n){var o=false;return function(i){if(o){return}o=true;t[e]=i;if(--n.count===0){var a=r.resolve;a(t)}}};var C=function(e,t,r){var n=e.iterator;var o=[];var i={count:1};var a,u;var f=0;while(true){try{a=ce.IteratorStep(n);if(a===false){e.done=true;break}u=a.value}catch(s){e.done=true;throw s}o[f]=void 0;var c=t.resolve(u);var l=P(f,o,r,i);i.count+=1;w(c.then,c,l,r.reject);f+=1}if(--i.count===0){var p=r.resolve;p(o)}return r.promise};var x=function(e,t,r){var n=e.iterator;var o,i,a;while(true){try{o=ce.IteratorStep(n);if(o===false){e.done=true;break}i=o.value}catch(u){e.done=true;throw u}a=t.resolve(i);w(a.then,a,r.resolve,r.reject)}return r.promise};b(E,{all:function all(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Promise is not object\")}var n=new r(t);var o,i;try{o=ce.GetIterator(e);i={iterator:o,done:false};return C(i,t,n)}catch(a){var u=a;if(i&&!i.done){try{ce.IteratorClose(o,true)}catch(f){u=f}}var s=n.reject;s(u);return n.promise}},race:function race(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Promise is not object\")}var n=new r(t);var o,i;try{o=ce.GetIterator(e);i={iterator:o,done:false};return x(i,t,n)}catch(a){var u=a;if(i&&!i.done){try{ce.IteratorClose(o,true)}catch(f){u=f}}var s=n.reject;s(u);return n.promise}},reject:function reject(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Bad promise constructor\")}var n=new r(t);var o=n.reject;o(e);return n.promise},resolve:function resolve(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Bad promise constructor\")}if(ce.IsPromise(e)){var n=e.constructor;if(n===t){return e}}var o=new r(t);var i=o.resolve;i(e);return o.promise}});b(T,{\"catch\":function(e){return this.then(null,e)},then:function then(e,t){var n=this;if(!ce.IsPromise(n)){throw new TypeError(\"not a promise\")}var o=ce.SpeciesConstructor(n,E);var i;var b=arguments.length>2&&arguments[2]===y;if(b&&o===E){i=y}else{i=new r(o)}var g=ce.IsCallable(e)?e:a;var d=ce.IsCallable(t)?t:u;var m=n._promise;var O;if(m.state===f){if(m.reactionLength===0){m.fulfillReactionHandler0=g;m.rejectReactionHandler0=d;m.reactionCapability0=i}else{var w=3*(m.reactionLength-1);m[w+l]=g;m[w+p]=d;m[w+v]=i}m.reactionLength+=1}else if(m.state===s){O=m.result;h(g,i,O)}else if(m.state===c){O=m.result;h(d,i,O)}else{throw new TypeError(\"unexpected Promise state\")}return i.promise}});y=new r(E);I=T.then;return E}();if(S.Promise){delete S.Promise.accept;delete S.Promise.defer;delete S.Promise.prototype.chain}if(typeof Fr===\"function\"){b(S,{Promise:Fr});var Dr=w(S.Promise,function(e){return e.resolve(42).then(function(){})instanceof e});var zr=!i(function(){return S.Promise.reject(42).then(null,5).then(null,W)});var qr=i(function(){return S.Promise.call(3,W)});var Wr=function(e){var t=e.resolve(5);t.constructor={};var r=e.resolve(t);try{r.then(null,W).then(null,W)}catch(n){return true}return t===r}(S.Promise);var Gr=s&&function(){var e=0;var t=Object.defineProperty({},\"then\",{get:function(){e+=1}});Promise.resolve(t);return e===1}();var Hr=function BadResolverPromise(e){var t=new Promise(e);e(3,function(){});this.then=t.then;this.constructor=BadResolverPromise};Hr.prototype=Promise.prototype;Hr.all=Promise.all;var Vr=a(function(){return!!Hr.all([1,2])});if(!Dr||!zr||!qr||Wr||!Gr||Vr){Promise=Fr;ne(S,\"Promise\",Fr)}if(Promise.all.length!==1){var Br=Promise.all;ne(Promise,\"all\",function all(e){return ce.Call(Br,this,arguments)})}if(Promise.race.length!==1){var Ur=Promise.race;ne(Promise,\"race\",function race(e){return ce.Call(Ur,this,arguments)})}if(Promise.resolve.length!==1){var $r=Promise.resolve;ne(Promise,\"resolve\",function resolve(e){return ce.Call($r,this,arguments)})}if(Promise.reject.length!==1){var Jr=Promise.reject;ne(Promise,\"reject\",function reject(e){return ce.Call(Jr,this,arguments)})}Mt(Promise,\"all\");Mt(Promise,\"race\");Mt(Promise,\"resolve\");Mt(Promise,\"reject\");Ce(Promise)}var Xr=function(e){var t=n(p(e,function(e,t){e[t]=true;return e},{}));return e.join(\":\")===t.join(\":\")};var Kr=Xr([\"z\",\"a\",\"bb\"]);var Zr=Xr([\"z\",1,\"a\",\"3\",2]);if(s){var Yr=function fastkey(e,t){if(!t&&!Kr){return null}if(se(e)){return\"^\"+ce.ToString(e)}else if(typeof e===\"string\"){return\"$\"+e}else if(typeof e===\"number\"){if(!Zr){return\"n\"+e}return e}else if(typeof e===\"boolean\"){return\"b\"+e}return null};var Qr=function emptyObject(){return Object.create?Object.create(null):{}};var en=function addIterableToMap(e,n,o){if(r(o)||re.string(o)){l(o,function(e){if(!ce.TypeIsObject(e)){throw new TypeError(\"Iterator value \"+e+\" is not an entry object\")}n.set(e[0],e[1])})}else if(o instanceof e){t(e.prototype.forEach,o,function(e,t){n.set(t,e)})}else{var i,a;if(!se(o)){a=n.set;if(!ce.IsCallable(a)){throw new TypeError(\"bad map\")}i=ce.GetIterator(o)}if(typeof i!==\"undefined\"){while(true){var u=ce.IteratorStep(i);if(u===false){break}var f=u.value;try{if(!ce.TypeIsObject(f)){throw new TypeError(\"Iterator value \"+f+\" is not an entry object\")}t(a,n,f[0],f[1])}catch(s){ce.IteratorClose(i,true);throw s}}}}};var tn=function addIterableToSet(e,n,o){if(r(o)||re.string(o)){l(o,function(e){n.add(e)})}else if(o instanceof e){t(e.prototype.forEach,o,function(e){n.add(e)})}else{var i,a;if(!se(o)){a=n.add;if(!ce.IsCallable(a)){throw new TypeError(\"bad set\")}i=ce.GetIterator(o)}if(typeof i!==\"undefined\"){while(true){var u=ce.IteratorStep(i);if(u===false){break}var f=u.value;try{t(a,n,f)}catch(s){ce.IteratorClose(i,true);throw s}}}}};var rn={Map:function(){var e={};var r=function MapEntry(e,t){this.key=e;this.value=t;this.next=null;this.prev=null};r.prototype.isRemoved=function isRemoved(){return this.key===e};var n=function isMap(e){return!!e._es6map};var o=function requireMapSlot(e,t){if(!ce.TypeIsObject(e)||!n(e)){throw new TypeError(\"Method Map.prototype.\"+t+\" called on incompatible receiver \"+ce.ToString(e))}};var i=function MapIterator(e,t){o(e,\"[[MapIterator]]\");this.head=e._head;this.i=this.head;this.kind=t};i.prototype={isMapIterator:true,next:function next(){if(!this.isMapIterator){throw new TypeError(\"Not a MapIterator\")}var e=this.i;var t=this.kind;var r=this.head;if(typeof this.i===\"undefined\"){return Ke()}while(e.isRemoved()&&e!==r){e=e.prev}var n;while(e.next!==r){e=e.next;if(!e.isRemoved()){if(t===\"key\"){n=e.key}else if(t===\"value\"){n=e.value}else{n=[e.key,e.value]}this.i=e;return Ke(n)}}this.i=void 0;return Ke()}};Me(i.prototype);var a;var u=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}if(this&&this._es6map){throw new TypeError(\"Bad construction\")}var e=Ae(this,Map,a,{_es6map:true,_head:null,_map:G?new G:null,_size:0,_storage:Qr()});var t=new r(null,null);t.next=t.prev=t;e._head=t;if(arguments.length>0){en(Map,e,arguments[0])}return e};a=u.prototype;m.getter(a,\"size\",function(){if(typeof this._size===\"undefined\"){throw new TypeError(\"size method called on incompatible Map\")}return this._size});b(a,{get:function get(e){o(this,\"get\");var t;var r=Yr(e,true);if(r!==null){t=this._storage[r];if(t){return t.value}else{return}}if(this._map){t=V.call(this._map,e);if(t){return t.value}else{return}}var n=this._head;var i=n;while((i=i.next)!==n){if(ce.SameValueZero(i.key,e)){return i.value}}},has:function has(e){o(this,\"has\");var t=Yr(e,true);if(t!==null){return typeof this._storage[t]!==\"undefined\"}if(this._map){return B.call(this._map,e)}var r=this._head;var n=r;while((n=n.next)!==r){if(ce.SameValueZero(n.key,e)){return true}}return false},set:function set(e,t){o(this,\"set\");var n=this._head;var i=n;var a;var u=Yr(e,true);if(u!==null){if(typeof this._storage[u]!==\"undefined\"){this._storage[u].value=t;return this}else{a=this._storage[u]=new r(e,t);i=n.prev}}else if(this._map){if(B.call(this._map,e)){V.call(this._map,e).value=t}else{a=new r(e,t);U.call(this._map,e,a);i=n.prev}}while((i=i.next)!==n){if(ce.SameValueZero(i.key,e)){i.value=t;return this}}a=a||new r(e,t);if(ce.SameValue(-0,e)){a.key=+0}a.next=this._head;a.prev=this._head.prev;a.prev.next=a;a.next.prev=a;this._size+=1;return this},\"delete\":function(t){o(this,\"delete\");var r=this._head;var n=r;var i=Yr(t,true);if(i!==null){if(typeof this._storage[i]===\"undefined\"){return false}n=this._storage[i].prev;delete this._storage[i]}else if(this._map){if(!B.call(this._map,t)){return false}n=V.call(this._map,t).prev;H.call(this._map,t)}while((n=n.next)!==r){if(ce.SameValueZero(n.key,t)){n.key=e;n.value=e;n.prev.next=n.next;n.next.prev=n.prev;this._size-=1;return true}}return false},clear:function clear(){o(this,\"clear\");this._map=G?new G:null;this._size=0;this._storage=Qr();var t=this._head;var r=t;var n=r.next;while((r=n)!==t){r.key=e;r.value=e;n=r.next;r.next=r.prev=t}t.next=t.prev=t},keys:function keys(){o(this,\"keys\");return new i(this,\"key\")},values:function values(){o(this,\"values\");return new i(this,\"value\")},entries:function entries(){o(this,\"entries\");return new i(this,\"key+value\")},forEach:function forEach(e){o(this,\"forEach\");var r=arguments.length>1?arguments[1]:null;var n=this.entries();for(var i=n.next();!i.done;i=n.next()){if(r){t(e,r,i.value[1],i.value[0],this)}else{e(i.value[1],i.value[0],this)}}}});Me(a,a.entries);return u}(),Set:function(){var e=function isSet(e){return e._es6set&&typeof e._storage!==\"undefined\"};var r=function requireSetSlot(t,r){if(!ce.TypeIsObject(t)||!e(t)){throw new TypeError(\"Set.prototype.\"+r+\" called on incompatible receiver \"+ce.ToString(t))}};var o;var i=function Set(){if(!(this instanceof Set)){throw new TypeError('Constructor Set requires \"new\"')}if(this&&this._es6set){throw new TypeError(\"Bad construction\")}var e=Ae(this,Set,o,{_es6set:true,\"[[SetData]]\":null,_storage:Qr()});if(!e._es6set){throw new TypeError(\"bad set\")}if(arguments.length>0){tn(Set,e,arguments[0])}return e};o=i.prototype;var a=function(e){var t=e;if(t===\"^null\"){return null}else if(t===\"^undefined\"){return void 0}else{var r=t.charAt(0);if(r===\"$\"){return C(t,1)}else if(r===\"n\"){return+C(t,1)}else if(r===\"b\"){return t===\"btrue\"}}return+t};var u=function ensureMap(e){if(!e[\"[[SetData]]\"]){var t=new rn.Map;e[\"[[SetData]]\"]=t;l(n(e._storage),function(e){var r=a(e);t.set(r,r)});e[\"[[SetData]]\"]=t}e._storage=null};m.getter(i.prototype,\"size\",function(){r(this,\"size\");if(this._storage){return n(this._storage).length}u(this);return this[\"[[SetData]]\"].size});b(i.prototype,{has:function has(e){r(this,\"has\");var t;if(this._storage&&(t=Yr(e))!==null){return!!this._storage[t]}u(this);return this[\"[[SetData]]\"].has(e)},add:function add(e){r(this,\"add\");var t;if(this._storage&&(t=Yr(e))!==null){this._storage[t]=true;return this}u(this);this[\"[[SetData]]\"].set(e,e);return this},\"delete\":function(e){r(this,\"delete\");var t;if(this._storage&&(t=Yr(e))!==null){var n=z(this._storage,t);return delete this._storage[t]&&n}u(this);return this[\"[[SetData]]\"][\"delete\"](e)},clear:function clear(){r(this,\"clear\");if(this._storage){this._storage=Qr()}if(this[\"[[SetData]]\"]){this[\"[[SetData]]\"].clear()}},values:function values(){r(this,\"values\");u(this);return new f(this[\"[[SetData]]\"].values())},entries:function entries(){r(this,\"entries\");u(this);return new f(this[\"[[SetData]]\"].entries())},forEach:function forEach(e){r(this,\"forEach\");var n=arguments.length>1?arguments[1]:null;var o=this;u(o);this[\"[[SetData]]\"].forEach(function(r,i){if(n){t(e,n,i,i,o)}else{e(i,i,o)}})}});h(i.prototype,\"keys\",i.prototype.values,true);Me(i.prototype,i.prototype.values);var f=function SetIterator(e){this.it=e};f.prototype={isSetIterator:true,next:function next(){if(!this.isSetIterator){throw new TypeError(\"Not a SetIterator\")}return this.it.next()}};Me(f.prototype);return i}()};var nn=S.Set&&!Set.prototype[\"delete\"]&&Set.prototype.remove&&Set.prototype.items&&Set.prototype.map&&Array.isArray((new Set).keys);if(nn){S.Set=rn.Set}if(S.Map||S.Set){var on=a(function(){return new Map([[1,2]]).get(1)===2});if(!on){S.Map=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}var e=new G;if(arguments.length>0){en(Map,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,S.Map.prototype);return e};S.Map.prototype=O(G.prototype);h(S.Map.prototype,\"constructor\",S.Map,true);m.preserveToString(S.Map,G)}var an=new Map;var un=function(){var e=new Map([[1,0],[2,0],[3,0],[4,0]]);e.set(-0,e);return e.get(0)===e&&e.get(-0)===e&&e.has(0)&&e.has(-0)}();var fn=an.set(1,2)===an;if(!un||!fn){ne(Map.prototype,\"set\",function set(e,r){t(U,this,e===0?0:e,r);return this})}if(!un){b(Map.prototype,{get:function get(e){return t(V,this,e===0?0:e)},has:function has(e){return t(B,this,e===0?0:e)}},true);m.preserveToString(Map.prototype.get,V);m.preserveToString(Map.prototype.has,B)}var sn=new Set;var cn=Set.prototype[\"delete\"]&&Set.prototype.add&&Set.prototype.has&&function(e){e[\"delete\"](0);e.add(-0);return!e.has(0)}(sn);var ln=sn.add(1)===sn;if(!cn||!ln){var pn=Set.prototype.add;Set.prototype.add=function add(e){t(pn,this,e===0?0:e);return this};m.preserveToString(Set.prototype.add,pn)}if(!cn){var vn=Set.prototype.has;Set.prototype.has=function has(e){return t(vn,this,e===0?0:e)};m.preserveToString(Set.prototype.has,vn);var yn=Set.prototype[\"delete\"];Set.prototype[\"delete\"]=function SetDelete(e){return t(yn,this,e===0?0:e)};m.preserveToString(Set.prototype[\"delete\"],yn)}var hn=w(S.Map,function(e){var t=new e([]);t.set(42,42);return t instanceof e});var bn=Object.setPrototypeOf&&!hn;var gn=function(){try{return!(S.Map()instanceof S.Map)}catch(e){return e instanceof TypeError}}();if(S.Map.length!==0||bn||!gn){S.Map=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}var e=new G;if(arguments.length>0){en(Map,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,Map.prototype);return e};S.Map.prototype=G.prototype;h(S.Map.prototype,\"constructor\",S.Map,true);m.preserveToString(S.Map,G)}var dn=w(S.Set,function(e){var t=new e([]);t.add(42,42);return t instanceof e});var mn=Object.setPrototypeOf&&!dn;var On=function(){try{return!(S.Set()instanceof S.Set)}catch(e){return e instanceof TypeError}}();if(S.Set.length!==0||mn||!On){var wn=S.Set;S.Set=function Set(){if(!(this instanceof Set)){throw new TypeError('Constructor Set requires \"new\"')}var e=new wn;if(arguments.length>0){tn(Set,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,Set.prototype);return e};S.Set.prototype=wn.prototype;h(S.Set.prototype,\"constructor\",S.Set,true);m.preserveToString(S.Set,wn)}var jn=new S.Map;var Sn=!a(function(){return jn.keys().next().done});if(typeof S.Map.prototype.clear!==\"function\"||(new S.Set).size!==0||jn.size!==0||typeof S.Map.prototype.keys!==\"function\"||typeof S.Set.prototype.keys!==\"function\"||typeof S.Map.prototype.forEach!==\"function\"||typeof S.Set.prototype.forEach!==\"function\"||u(S.Map)||u(S.Set)||typeof jn.keys().next!==\"function\"||Sn||!hn){b(S,{Map:rn.Map,Set:rn.Set},true)}if(S.Set.prototype.keys!==S.Set.prototype.values){h(S.Set.prototype,\"keys\",S.Set.prototype.values,true)}Me(Object.getPrototypeOf((new S.Map).keys()));Me(Object.getPrototypeOf((new S.Set).keys()));if(c&&S.Set.prototype.has.name!==\"has\"){var Tn=S.Set.prototype.has;ne(S.Set.prototype,\"has\",function has(e){return t(Tn,this,e)})}}b(S,rn);Ce(S.Map);Ce(S.Set)}var In=function throwUnlessTargetIsObject(e){if(!ce.TypeIsObject(e)){throw new TypeError(\"target must be an object\")}};var En={apply:function apply(){return ce.Call(ce.Call,null,arguments)},construct:function construct(e,t){if(!ce.IsConstructor(e)){throw new TypeError(\"First argument must be a constructor.\")}var r=arguments.length>2?arguments[2]:e;if(!ce.IsConstructor(r)){throw new TypeError(\"new.target must be a constructor.\")}return ce.Construct(e,t,r,\"internal\")},deleteProperty:function deleteProperty(e,t){In(e);if(s){var r=Object.getOwnPropertyDescriptor(e,t);if(r&&!r.configurable){return false}}return delete e[t]},has:function has(e,t){In(e);return t in e}};if(Object.getOwnPropertyNames){Object.assign(En,{ownKeys:function ownKeys(e){In(e);var t=Object.getOwnPropertyNames(e);if(ce.IsCallable(Object.getOwnPropertySymbols)){x(t,Object.getOwnPropertySymbols(e))}return t}})}var Pn=function ConvertExceptionToBoolean(e){return!i(e)};if(Object.preventExtensions){Object.assign(En,{isExtensible:function isExtensible(e){In(e);return Object.isExtensible(e)},preventExtensions:function preventExtensions(e){In(e);return Pn(function(){return Object.preventExtensions(e)})}})}if(s){var Cn=function get(e,t,r){var n=Object.getOwnPropertyDescriptor(e,t);if(!n){var o=Object.getPrototypeOf(e);if(o===null){return void 0}return Cn(o,t,r)}if(\"value\"in n){return n.value}if(n.get){return ce.Call(n.get,r)}return void 0};var Mn=function set(e,r,n,o){var i=Object.getOwnPropertyDescriptor(e,r);if(!i){var a=Object.getPrototypeOf(e);if(a!==null){return Mn(a,r,n,o)}i={value:void 0,writable:true,enumerable:true,configurable:true}}if(\"value\"in i){if(!i.writable){return false}if(!ce.TypeIsObject(o)){return false}var u=Object.getOwnPropertyDescriptor(o,r);if(u){return ae.defineProperty(o,r,{value:n})}else{return ae.defineProperty(o,r,{value:n,writable:true,enumerable:true,configurable:true})}}if(i.set){t(i.set,o,n);return true}return false};Object.assign(En,{defineProperty:function defineProperty(e,t,r){In(e);return Pn(function(){return Object.defineProperty(e,t,r)})},getOwnPropertyDescriptor:function getOwnPropertyDescriptor(e,t){In(e);return Object.getOwnPropertyDescriptor(e,t)},get:function get(e,t){In(e);var r=arguments.length>2?arguments[2]:e;return Cn(e,t,r)},set:function set(e,t,r){In(e);var n=arguments.length>3?arguments[3]:e;return Mn(e,t,r,n)}})}if(Object.getPrototypeOf){var xn=Object.getPrototypeOf;En.getPrototypeOf=function getPrototypeOf(e){In(e);return xn(e)}}if(Object.setPrototypeOf&&En.getPrototypeOf){var Nn=function(e,t){var r=t;while(r){if(e===r){return true}r=En.getPrototypeOf(r)}return false};Object.assign(En,{setPrototypeOf:function setPrototypeOf(e,t){In(e);if(t!==null&&!ce.TypeIsObject(t)){throw new TypeError(\"proto must be an object or null\")}if(t===ae.getPrototypeOf(e)){return true}if(ae.isExtensible&&!ae.isExtensible(e)){return false}if(Nn(e,t)){return false}Object.setPrototypeOf(e,t);return true}})}var An=function(e,t){if(!ce.IsCallable(S.Reflect[e])){h(S.Reflect,e,t)}else{var r=a(function(){S.Reflect[e](1);S.Reflect[e](NaN);S.Reflect[e](true);return true});if(r){ne(S.Reflect,e,t)}}};Object.keys(En).forEach(function(e){An(e,En[e])});var Rn=S.Reflect.getPrototypeOf;if(c&&Rn&&Rn.name!==\"getPrototypeOf\"){ne(S.Reflect,\"getPrototypeOf\",function getPrototypeOf(e){return t(Rn,S.Reflect,e)})}if(S.Reflect.setPrototypeOf){if(a(function(){S.Reflect.setPrototypeOf(1,{});return true})){ne(S.Reflect,\"setPrototypeOf\",En.setPrototypeOf)}}if(S.Reflect.defineProperty){if(!a(function(){var e=!S.Reflect.defineProperty(1,\"test\",{value:1});var t=typeof Object.preventExtensions!==\"function\"||!S.Reflect.defineProperty(Object.preventExtensions({}),\"test\",{});return e&&t})){ne(S.Reflect,\"defineProperty\",En.defineProperty)}}if(S.Reflect.construct){if(!a(function(){var e=function F(){};return S.Reflect.construct(function(){},[],e)instanceof e})){ne(S.Reflect,\"construct\",En.construct)}}if(String(new Date(NaN))!==\"Invalid Date\"){var _n=Date.prototype.toString;var kn=function toString(){var e=+this;if(e!==e){return\"Invalid Date\"}return ce.Call(_n,this)};ne(Date.prototype,\"toString\",kn)}var Ln={anchor:function anchor(e){return ce.CreateHTML(this,\"a\",\"name\",e)},big:function big(){return ce.CreateHTML(this,\"big\",\"\",\"\")},blink:function blink(){return ce.CreateHTML(this,\"blink\",\"\",\"\")},bold:function bold(){return ce.CreateHTML(this,\"b\",\"\",\"\")},fixed:function fixed(){return ce.CreateHTML(this,\"tt\",\"\",\"\")},fontcolor:function fontcolor(e){return ce.CreateHTML(this,\"font\",\"color\",e)},fontsize:function fontsize(e){return ce.CreateHTML(this,\"font\",\"size\",e)},italics:function italics(){return ce.CreateHTML(this,\"i\",\"\",\"\")},link:function link(e){return ce.CreateHTML(this,\"a\",\"href\",e)},small:function small(){return ce.CreateHTML(this,\"small\",\"\",\"\")},strike:function strike(){return ce.CreateHTML(this,\"strike\",\"\",\"\")},sub:function sub(){return ce.CreateHTML(this,\"sub\",\"\",\"\")},sup:function sub(){return ce.CreateHTML(this,\"sup\",\"\",\"\")}};l(Object.keys(Ln),function(e){var r=String.prototype[e];var n=false;if(ce.IsCallable(r)){var o=t(r,\"\",' \" ');var i=P([],o.match(/\"/g)).length;n=o!==o.toLowerCase()||i>2}else{n=true}if(n){ne(String.prototype,e,Ln[e])}});var Fn=function(){if(!oe){return false}var e=typeof JSON===\"object\"&&typeof JSON.stringify===\"function\"?JSON.stringify:null;if(!e){return false}if(typeof e($())!==\"undefined\"){return true}if(e([$()])!==\"[null]\"){return true}var t={a:$()};t[$()]=true;if(e(t)!==\"{}\"){return true}return false}();var Dn=a(function(){if(!oe){return true}return JSON.stringify(Object($()))===\"{}\"&&JSON.stringify([Object($())])===\"[{}]\"});if(Fn||!Dn){var zn=JSON.stringify;ne(JSON,\"stringify\",function stringify(e){if(typeof e===\"symbol\"){return}var n;if(arguments.length>1){n=arguments[1]}var o=[e];if(!r(n)){var i=ce.IsCallable(n)?n:null;var a=function(e,r){var n=i?t(i,this,e,r):r;if(typeof n!==\"symbol\"){if(re.symbol(n)){return Nt({})(n)}else{return n}}};o.push(a)}else{o.push(n)}if(arguments.length>2){o.push(arguments[2])}return zn.apply(this,o)})}return S});\n//# sourceMappingURL=es6-shim.map\n/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */\n!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return t(e)}:t(e)}(\"undefined\"!=typeof window?window:this,function(C,e){\"use strict\";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return\"function\"==typeof e&&\"number\"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement(\"script\");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?n[o.call(e)]||\"object\":typeof e}var f=\"3.4.1\",k=function(e,t){return new k.fn.init(e,t)},p=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;function d(e){var t=!!e&&\"length\"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&0<t&&t-1 in e)}k.fn=k.prototype={jquery:f,constructor:k,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=k.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return k.each(this,e)},map:function(n){return this.pushStack(k.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},k.extend=k.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for(\"boolean\"==typeof a&&(l=a,a=arguments[s]||{},s++),\"object\"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],\"__proto__\"!==t&&a!==r&&(l&&r&&(k.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||k.isPlainObject(n)?n:{},i=!1,a[t]=k.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},k.extend({expando:\"jQuery\"+(f+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||\"[object Object]\"!==o.call(e))&&(!(t=r(e))||\"function\"==typeof(n=v.call(t,\"constructor\")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t){b(e,{nonce:t&&t.nonce})},each:function(e,t){var n,r=0;if(d(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?\"\":(e+\"\").replace(p,\"\")},makeArray:function(e,t){var n=t||[];return null!=e&&(d(Object(e))?k.merge(n,\"string\"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(d(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g.apply([],a)},guid:1,support:y}),\"function\"==typeof Symbol&&(k.fn[Symbol.iterator]=t[Symbol.iterator]),k.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){n[\"[object \"+t+\"]\"]=t.toLowerCase()});var h=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,k=\"sizzle\"+1*new Date,m=n.document,S=0,r=0,p=ue(),x=ue(),N=ue(),A=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",M=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",I=\"(?:\\\\\\\\.|[\\\\w-]|[^\\0-\\\\xa0])+\",W=\"\\\\[\"+M+\"*(\"+I+\")(?:\"+M+\"*([*^$|!~]?=)\"+M+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+I+\"))|)\"+M+\"*\\\\]\",$=\":(\"+I+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+W+\")*)|.*)\\\\)|)\",F=new RegExp(M+\"+\",\"g\"),B=new RegExp(\"^\"+M+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+M+\"+$\",\"g\"),_=new RegExp(\"^\"+M+\"*,\"+M+\"*\"),z=new RegExp(\"^\"+M+\"*([>+~]|\"+M+\")\"+M+\"*\"),U=new RegExp(M+\"|>\"),X=new RegExp($),V=new RegExp(\"^\"+I+\"$\"),G={ID:new RegExp(\"^#(\"+I+\")\"),CLASS:new RegExp(\"^\\\\.(\"+I+\")\"),TAG:new RegExp(\"^(\"+I+\"|[*])\"),ATTR:new RegExp(\"^\"+W),PSEUDO:new RegExp(\"^\"+$),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+M+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+M+\"*(?:([+-]|)\"+M+\"*(\\\\d+)|))\"+M+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+R+\")$\",\"i\"),needsContext:new RegExp(\"^\"+M+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+M+\"*((?:-\\\\d)?\\\\d*)\"+M+\"*\\\\)|)(?=[^-]|$)\",\"i\")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\\d$/i,K=/^[^{]+\\{\\s*\\[native \\w/,Z=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,ee=/[+~]/,te=new RegExp(\"\\\\\\\\([\\\\da-f]{1,6}\"+M+\"?|(\"+M+\")|.)\",\"ig\"),ne=function(e,t,n){var r=\"0x\"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,ie=function(e,t){return t?\"\\0\"===e?\"\\ufffd\":e.slice(0,-1)+\"\\\\\"+e.charCodeAt(e.length-1).toString(16)+\" \":\"\\\\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&\"fieldset\"===e.nodeName.toLowerCase()},{dir:\"parentNode\",next:\"legend\"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],\"string\"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+\" \"]&&(!v||!v.test(t))&&(1!==p||\"object\"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute(\"id\"))?s=s.replace(re,ie):e.setAttribute(\"id\",s=k),o=(l=h(t)).length;while(o--)l[o]=\"#\"+s+\" \"+xe(l[o]);c=l.join(\",\"),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute(\"id\")}}}return g(t.replace(B,\"$1\"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+\" \")>b.cacheLength&&delete e[r.shift()],e[t+\" \"]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement(\"fieldset\");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split(\"|\"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return\"input\"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return(\"input\"===t||\"button\"===t)&&e.type===n}}function ge(t){return function(e){return\"form\"in e?e.parentNode&&!1===e.disabled?\"label\"in e?\"label\"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:\"label\"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&\"undefined\"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||\"HTML\")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener(\"unload\",oe,!1):n.attachEvent&&n.attachEvent(\"onunload\",oe)),d.attributes=ce(function(e){return e.className=\"i\",!e.getAttribute(\"className\")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment(\"\")),!e.getElementsByTagName(\"*\").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute(\"id\")===t}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t=\"undefined\"!=typeof e.getAttributeNode&&e.getAttributeNode(\"id\");return t&&t.value===n}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return\"undefined\"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if(\"*\"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if(\"undefined\"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML=\"<a id='\"+k+\"'></a><select id='\"+k+\"-\\r\\\\' msallowcapture=''><option selected=''></option></select>\",e.querySelectorAll(\"[msallowcapture^='']\").length&&v.push(\"[*^$]=\"+M+\"*(?:''|\\\"\\\")\"),e.querySelectorAll(\"[selected]\").length||v.push(\"\\\\[\"+M+\"*(?:value|\"+R+\")\"),e.querySelectorAll(\"[id~=\"+k+\"-]\").length||v.push(\"~=\"),e.querySelectorAll(\":checked\").length||v.push(\":checked\"),e.querySelectorAll(\"a#\"+k+\"+*\").length||v.push(\".#.+[+~]\")}),ce(function(e){e.innerHTML=\"<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>\";var t=C.createElement(\"input\");t.setAttribute(\"type\",\"hidden\"),e.appendChild(t).setAttribute(\"name\",\"D\"),e.querySelectorAll(\"[name=d]\").length&&v.push(\"name\"+M+\"*[*^$|!~]?=\"),2!==e.querySelectorAll(\":enabled\").length&&v.push(\":enabled\",\":disabled\"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(\":disabled\").length&&v.push(\":enabled\",\":disabled\"),e.querySelectorAll(\"*,:x\"),v.push(\",.*:\")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,\"*\"),c.call(e,\"[s!='']:x\"),s.push(\"!=\",$)}),v=v.length&&new RegExp(v.join(\"|\")),s=s.length&&new RegExp(s.join(\"|\")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+\" \"]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!==C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!==C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+\"\").replace(re,ie)},se.error=function(e){throw new Error(\"Syntax error, unrecognized expression: \"+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n=\"\",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if(\"string\"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||\"\").replace(te,ne),\"~=\"===e[2]&&(e[3]=\" \"+e[3]+\" \"),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),\"nth\"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*(\"even\"===e[3]||\"odd\"===e[3])),e[5]=+(e[7]+e[8]||\"odd\"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||\"\":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(\")\",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return\"*\"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+\" \"];return t||(t=new RegExp(\"(^|\"+M+\")\"+e+\"(\"+M+\"|$)\"))&&p(e,function(e){return t.test(\"string\"==typeof e.className&&e.className||\"undefined\"!=typeof e.getAttribute&&e.getAttribute(\"class\")||\"\")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?\"!=\"===r:!r||(t+=\"\",\"=\"===r?t===i:\"!=\"===r?t!==i:\"^=\"===r?i&&0===t.indexOf(i):\"*=\"===r?i&&-1<t.indexOf(i):\"$=\"===r?i&&t.slice(-i.length)===i:\"~=\"===r?-1<(\" \"+t.replace(F,\" \")+\" \").indexOf(i):\"|=\"===r&&(t===i||t.slice(0,i.length+1)===i+\"-\"))}},CHILD:function(h,e,t,g,v){var y=\"nth\"!==h.slice(0,3),m=\"last\"!==h.slice(-4),x=\"of-type\"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?\"nextSibling\":\"previousSibling\",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l=\"only\"===h&&!u&&\"nextSibling\"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[S,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[S,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error(\"unsupported pseudo: \"+e);return a[k]?a(o):1<a.length?(t=[e,e,\"\",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace(B,\"$1\"));return s[k]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||\"\")||se.error(\"unsupported lang: \"+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute(\"xml:lang\")||e.getAttribute(\"lang\"))return(t=t.toLowerCase())===n||0===t.indexOf(n+\"-\")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&!!e.checked||\"option\"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&\"button\"===e.type||\"button\"===t},text:function(e){var t;return\"input\"===e.nodeName.toLowerCase()&&\"text\"===e.type&&(null==(t=e.getAttribute(\"type\"))||\"text\"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r=\"\";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&\"parentNode\"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[S,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[k]||(e[k]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===S&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[k]&&(v=Ce(v)),y&&!y[k]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||\"*\",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[\" \"],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[k]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:\" \"===e[s-2].type?\"*\":\"\"})).replace(B,\"$1\"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+\" \"];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace(B,\" \")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=N[e+\" \"];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[k]?i.push(a):o.push(a);(a=N(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l=\"0\",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG(\"*\",i),h=S+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t===C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument===C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(S=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(S=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l=\"function\"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&\"ID\"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=k.split(\"\").sort(D).join(\"\")===k,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement(\"fieldset\"))}),ce(function(e){return e.innerHTML=\"<a href='#'></a>\",\"#\"===e.firstChild.getAttribute(\"href\")})||fe(\"type|href|height|width\",function(e,t,n){if(!n)return e.getAttribute(t,\"type\"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML=\"<input/>\",e.firstChild.setAttribute(\"value\",\"\"),\"\"===e.firstChild.getAttribute(\"value\")})||fe(\"value\",function(e,t,n){if(!n&&\"input\"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute(\"disabled\")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);k.find=h,k.expr=h.selectors,k.expr[\":\"]=k.expr.pseudos,k.uniqueSort=k.unique=h.uniqueSort,k.text=h.getText,k.isXMLDoc=h.isXML,k.contains=h.contains,k.escapeSelector=h.escape;var T=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&k(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},N=k.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var D=/^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):\"string\"!=typeof n?k.grep(e,function(e){return-1<i.call(n,e)!==r}):k.filter(n,e,r)}k.filter=function(e,t,n){var r=t[0];return n&&(e=\":not(\"+e+\")\"),1===t.length&&1===r.nodeType?k.find.matchesSelector(r,e)?[r]:[]:k.find.matches(e,k.grep(t,function(e){return 1===e.nodeType}))},k.fn.extend({find:function(e){var t,n,r=this.length,i=this;if(\"string\"!=typeof e)return this.pushStack(k(e).filter(function(){for(t=0;t<r;t++)if(k.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)k.find(e,i[t],n);return 1<r?k.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,\"string\"==typeof e&&N.test(e)?k(e):e||[],!1).length}});var q,L=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,\"string\"==typeof e){if(!(r=\"<\"===e[0]&&\">\"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(k.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a=\"string\"!=typeof e&&k(e);if(!N.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&k.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?k.uniqueSort(o):o)},index:function(e){return e?\"string\"==typeof e?i.call(k(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(k.uniqueSort(k.merge(this.get(),k(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),k.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return T(e,\"parentNode\")},parentsUntil:function(e,t,n){return T(e,\"parentNode\",n)},next:function(e){return P(e,\"nextSibling\")},prev:function(e){return P(e,\"previousSibling\")},nextAll:function(e){return T(e,\"nextSibling\")},prevAll:function(e){return T(e,\"previousSibling\")},nextUntil:function(e,t,n){return T(e,\"nextSibling\",n)},prevUntil:function(e,t,n){return T(e,\"previousSibling\",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return\"undefined\"!=typeof e.contentDocument?e.contentDocument:(A(e,\"template\")&&(e=e.content||e),k.merge([],e.childNodes))}},function(r,i){k.fn[r]=function(e,t){var n=k.map(this,i,e);return\"Until\"!==r.slice(-5)&&(t=e),t&&\"string\"==typeof t&&(n=k.filter(t,n)),1<this.length&&(O[r]||k.uniqueSort(n),H.test(r)&&n.reverse()),this.pushStack(n)}});var R=/[^\\x20\\t\\r\\n\\f]+/g;function M(e){return e}function I(e){throw e}function W(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}k.Callbacks=function(r){var e,n;r=\"string\"==typeof r?(e=r,n={},k.each(e.match(R)||[],function(e,t){n[t]=!0}),n):k.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:\"\")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){k.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&\"string\"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return k.each(arguments,function(e,t){var n;while(-1<(n=k.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<k.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t=\"\",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=\"\"),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},k.extend({Deferred:function(e){var o=[[\"notify\",\"progress\",k.Callbacks(\"memory\"),k.Callbacks(\"memory\"),2],[\"resolve\",\"done\",k.Callbacks(\"once memory\"),k.Callbacks(\"once memory\"),0,\"resolved\"],[\"reject\",\"fail\",k.Callbacks(\"once memory\"),k.Callbacks(\"once memory\"),1,\"rejected\"]],i=\"pending\",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},\"catch\":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return k.Deferred(function(r){k.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+\"With\"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError(\"Thenable self-resolution\");t=e&&(\"object\"==typeof e||\"function\"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,M,s),l(u,o,I,s)):(u++,t.call(e,l(u,o,M,s),l(u,o,I,s),l(u,o,M,o.notifyWith))):(a!==M&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){k.Deferred.exceptionHook&&k.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==I&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(k.Deferred.getStackHook&&(t.stackTrace=k.Deferred.getStackHook()),C.setTimeout(t))}}return k.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:M,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:M)),o[2][3].add(l(0,e,m(n)?n:I))}).promise()},promise:function(e){return null!=e?k.extend(e,a):a}},s={};return k.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+\"With\"](this===s?void 0:this,arguments),this},s[t[0]+\"With\"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=k.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(W(e,o.done(a(t)).resolve,o.reject,!n),\"pending\"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)W(i[t],a(t),o.reject);return o.promise()}});var $=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;k.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&$.test(e.name)&&C.console.warn(\"jQuery.Deferred exception: \"+e.message,e.stack,t)},k.readyException=function(e){C.setTimeout(function(){throw e})};var F=k.Deferred();function B(){E.removeEventListener(\"DOMContentLoaded\",B),C.removeEventListener(\"load\",B),k.ready()}k.fn.ready=function(e){return F.then(e)[\"catch\"](function(e){k.readyException(e)}),this},k.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--k.readyWait:k.isReady)||(k.isReady=!0)!==e&&0<--k.readyWait||F.resolveWith(E,[k])}}),k.ready.then=F.then,\"complete\"===E.readyState||\"loading\"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(k.ready):(E.addEventListener(\"DOMContentLoaded\",B),C.addEventListener(\"load\",B));var _=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if(\"object\"===w(n))for(s in i=!0,n)_(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(k(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},z=/^-ms-/,U=/-([a-z])/g;function X(e,t){return t.toUpperCase()}function V(e){return e.replace(z,\"ms-\").replace(U,X)}var G=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function Y(){this.expando=k.expando+Y.uid++}Y.uid=1,Y.prototype={cache:function(e){var t=e[this.expando];return t||(t={},G(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if(\"string\"==typeof t)i[V(t)]=n;else for(r in t)i[V(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][V(t)]},access:function(e,t,n){return void 0===t||t&&\"string\"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(V):(t=V(t))in r?[t]:t.match(R)||[]).length;while(n--)delete r[t[n]]}(void 0===t||k.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!k.isEmptyObject(t)}};var Q=new Y,J=new Y,K=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,Z=/[A-Z]/g;function ee(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r=\"data-\"+t.replace(Z,\"-$&\").toLowerCase(),\"string\"==typeof(n=e.getAttribute(r))){try{n=\"true\"===(i=n)||\"false\"!==i&&(\"null\"===i?null:i===+i+\"\"?+i:K.test(i)?JSON.parse(i):i)}catch(e){}J.set(e,t,n)}else n=void 0;return n}k.extend({hasData:function(e){return J.hasData(e)||Q.hasData(e)},data:function(e,t,n){return J.access(e,t,n)},removeData:function(e,t){J.remove(e,t)},_data:function(e,t,n){return Q.access(e,t,n)},_removeData:function(e,t){Q.remove(e,t)}}),k.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=J.get(o),1===o.nodeType&&!Q.get(o,\"hasDataAttrs\"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf(\"data-\")&&(r=V(r.slice(5)),ee(o,r,i[r]));Q.set(o,\"hasDataAttrs\",!0)}return i}return\"object\"==typeof n?this.each(function(){J.set(this,n)}):_(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=J.get(o,n))?t:void 0!==(t=ee(o,n))?t:void 0;this.each(function(){J.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){J.remove(this,e)})}}),k.extend({queue:function(e,t,n){var r;if(e)return t=(t||\"fx\")+\"queue\",r=Q.get(e,t),n&&(!r||Array.isArray(n)?r=Q.access(e,t,k.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||\"fx\";var n=k.queue(e,t),r=n.length,i=n.shift(),o=k._queueHooks(e,t);\"inprogress\"===i&&(i=n.shift(),r--),i&&(\"fx\"===t&&n.unshift(\"inprogress\"),delete o.stop,i.call(e,function(){k.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+\"queueHooks\";return Q.get(e,n)||Q.access(e,n,{empty:k.Callbacks(\"once memory\").add(function(){Q.remove(e,[t+\"queue\",n])})})}}),k.fn.extend({queue:function(t,n){var e=2;return\"string\"!=typeof t&&(n=t,t=\"fx\",e--),arguments.length<e?k.queue(this[0],t):void 0===n?this:this.each(function(){var e=k.queue(this,t,n);k._queueHooks(this,t),\"fx\"===t&&\"inprogress\"!==e[0]&&k.dequeue(this,t)})},dequeue:function(e){return this.each(function(){k.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||\"fx\",[])},promise:function(e,t){var n,r=1,i=k.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};\"string\"!=typeof e&&(t=e,e=void 0),e=e||\"fx\";while(a--)(n=Q.get(o[a],e+\"queueHooks\"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var te=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,ne=new RegExp(\"^(?:([+-])=|)(\"+te+\")([a-z%]*)$\",\"i\"),re=[\"Top\",\"Right\",\"Bottom\",\"Left\"],ie=E.documentElement,oe=function(e){return k.contains(e.ownerDocument,e)},ae={composed:!0};ie.getRootNode&&(oe=function(e){return k.contains(e.ownerDocument,e)||e.getRootNode(ae)===e.ownerDocument});var se=function(e,t){return\"none\"===(e=t||e).style.display||\"\"===e.style.display&&oe(e)&&\"none\"===k.css(e,\"display\")},ue=function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];for(o in i=n.apply(e,r||[]),t)e.style[o]=a[o];return i};function le(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return k.css(e,t,\"\")},u=s(),l=n&&n[3]||(k.cssNumber[t]?\"\":\"px\"),c=e.nodeType&&(k.cssNumber[t]||\"px\"!==l&&+u)&&ne.exec(k.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)k.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,k.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ce={};function fe(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?(\"none\"===n&&(l[c]=Q.get(r,\"display\")||null,l[c]||(r.style.display=\"\")),\"\"===r.style.display&&se(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ce[s])||(o=a.body.appendChild(a.createElement(s)),u=k.css(o,\"display\"),o.parentNode.removeChild(o),\"none\"===u&&(u=\"block\"),ce[s]=u)))):\"none\"!==n&&(l[c]=\"none\",Q.set(r,\"display\",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}k.fn.extend({show:function(){return fe(this,!0)},hide:function(){return fe(this)},toggle:function(e){return\"boolean\"==typeof e?e?this.show():this.hide():this.each(function(){se(this)?k(this).show():k(this).hide()})}});var pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i,he=/^$|^module$|\\/(?:java|ecma)script/i,ge={option:[1,\"<select multiple='multiple'>\",\"</select>\"],thead:[1,\"<table>\",\"</table>\"],col:[2,\"<table><colgroup>\",\"</colgroup></table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:[0,\"\",\"\"]};function ve(e,t){var n;return n=\"undefined\"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):\"undefined\"!=typeof e.querySelectorAll?e.querySelectorAll(t||\"*\"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Q.set(e[n],\"globalEval\",!t||Q.get(t[n],\"globalEval\"))}ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;var me,xe,be=/<|&#?\\w+;/;function we(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if(\"object\"===w(o))k.merge(p,o.nodeType?[o]:o);else if(be.test(o)){a=a||f.appendChild(t.createElement(\"div\")),s=(de.exec(o)||[\"\",\"\"])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+k.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;k.merge(p,a.childNodes),(a=f.firstChild).textContent=\"\"}else p.push(t.createTextNode(o));f.textContent=\"\",d=0;while(o=p[d++])if(r&&-1<k.inArray(o,r))i&&i.push(o);else if(l=oe(o),a=ve(f.appendChild(o),\"script\"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||\"\")&&n.push(o)}return f}me=E.createDocumentFragment().appendChild(E.createElement(\"div\")),(xe=E.createElement(\"input\")).setAttribute(\"type\",\"radio\"),xe.setAttribute(\"checked\",\"checked\"),xe.setAttribute(\"name\",\"t\"),me.appendChild(xe),y.checkClone=me.cloneNode(!0).cloneNode(!0).lastChild.checked,me.innerHTML=\"<textarea>x</textarea>\",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==(\"focus\"===t)}function Ae(e,t,n,r,i,o){var a,s;if(\"object\"==typeof t){for(s in\"string\"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&(\"string\"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return\"undefined\"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||\"\").match(R)||[\"\"]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(\".\")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||\"\").match(R)||[\"\"]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&(\"**\"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,\"handle events\")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,\"events\")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t<arguments.length;t++)u[t]=arguments[t];if(s.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,s)){a=k.event.handlers.call(this,s,l),t=0;while((i=a[t++])&&!s.isPropagationStopped()){s.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!s.isImmediatePropagationStopped())s.rnamespace&&!1!==o.namespace&&!s.rnamespace.test(o.namespace)||(s.handleObj=o,s.data=o.data,void 0!==(r=((k.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,u))&&!1===(s.result=r)&&(s.preventDefault(),s.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,s),s.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!(\"click\"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&(\"click\"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+\" \"]&&(a[i]=r.needsContext?-1<k(i,this).index(l):k.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(k.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[k.expando]?e:new k.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,\"input\")&&De(t,\"click\",ke),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,\"input\")&&De(t,\"click\"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,\"input\")&&Q.get(t,\"click\")||A(t,\"a\")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},k.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},k.Event=function(e,t){if(!(this instanceof k.Event))return new k.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?ke:Se,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&k.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[k.expando]=!0},k.Event.prototype={constructor:k.Event,isDefaultPrevented:Se,isPropagationStopped:Se,isImmediatePropagationStopped:Se,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=ke,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=ke,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=ke,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},k.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,\"char\":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&Te.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&Ce.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},k.event.addProp),k.each({focus:\"focusin\",blur:\"focusout\"},function(e,t){k.event.special[e]={setup:function(){return De(this,e,Ne),!1},trigger:function(){return De(this,e),!0},delegateType:t}}),k.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(e,i){k.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||k.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),k.fn.extend({on:function(e,t,n,r){return Ae(this,e,t,n,r)},one:function(e,t,n,r){return Ae(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,k(e.delegateTarget).off(r.namespace?r.origType+\".\"+r.namespace:r.origType,r.selector,r.handler),this;if(\"object\"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&\"function\"!=typeof t||(n=t,t=void 0),!1===n&&(n=Se),this.each(function(){k.event.remove(this,e,n,t)})}});var je=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)[^>]*)\\/>/gi,qe=/<script|<style|<link/i,Le=/checked\\s*(?:[^=]|=\\s*.checked.)/i,He=/^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;function Oe(e,t){return A(e,\"table\")&&A(11!==t.nodeType?t:t.firstChild,\"tr\")&&k(e).children(\"tbody\")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute(\"type\"))+\"/\"+e.type,e}function Re(e){return\"true/\"===(e.type||\"\").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute(\"type\"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n<r;n++)k.event.add(t,i,l[i][n]);J.hasData(e)&&(s=J.access(e),u=k.extend({},s),J.set(t,u))}}function Ie(n,r,i,o){r=g.apply([],r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&\"string\"==typeof d&&!y.checkClone&&Le.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Ie(t,r,i,o)});if(f&&(t=(e=we(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=k.map(ve(e,\"script\"),Pe)).length;c<f;c++)u=e,c!==p&&(u=k.clone(u,!0,!0),s&&k.merge(a,ve(u,\"script\"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,k.map(a,Re),c=0;c<s;c++)u=a[c],he.test(u.type||\"\")&&!Q.access(u,\"globalEval\")&&k.contains(l,u)&&(u.src&&\"module\"!==(u.type||\"\").toLowerCase()?k._evalUrl&&!u.noModule&&k._evalUrl(u.src,{nonce:u.nonce||u.getAttribute(\"nonce\")}):b(u.textContent.replace(He,\"\"),u,l))}return n}function We(e,t,n){for(var r,i=t?k.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||k.cleanData(ve(r)),r.parentNode&&(n&&oe(r)&&ye(ve(r,\"script\")),r.parentNode.removeChild(r));return e}k.extend({htmlPrefilter:function(e){return e.replace(je,\"<$1></$2>\")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,\"input\"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:\"input\"!==l&&\"textarea\"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Me(o[r],a[r]);else Me(e,c);return 0<(a=ve(c,\"script\")).length&&ye(a,!f&&ve(e,\"script\")),c},cleanData:function(e){for(var t,n,r,i=k.event.special,o=0;void 0!==(n=e[o]);o++)if(G(n)){if(t=n[Q.expando]){if(t.events)for(r in t.events)i[r]?k.event.remove(n,r):k.removeEvent(n,r,t.handle);n[Q.expando]=void 0}n[J.expando]&&(n[J.expando]=void 0)}}}),k.fn.extend({detach:function(e){return We(this,e,!0)},remove:function(e){return We(this,e)},text:function(e){return _(this,function(e){return void 0===e?k.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Ie(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Oe(this,e).appendChild(e)})},prepend:function(){return Ie(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Oe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(k.cleanData(ve(e,!1)),e.textContent=\"\");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return k.clone(this,e,t)})},html:function(e){return _(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if(\"string\"==typeof e&&!qe.test(e)&&!ge[(de.exec(e)||[\"\",\"\"])[1].toLowerCase()]){e=k.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(k.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Ie(this,arguments,function(e){var t=this.parentNode;k.inArray(this,n)<0&&(k.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),k.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(e,a){k.fn[e]=function(e){for(var t,n=[],r=k(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),k(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var $e=new RegExp(\"^(\"+te+\")(?!px)[a-z%]+$\",\"i\"),Fe=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},Be=new RegExp(re.join(\"|\"),\"i\");function _e(e,t,n){var r,i,o,a,s=e.style;return(n=n||Fe(e))&&(\"\"!==(a=n.getPropertyValue(t)||n[t])||oe(e)||(a=k.style(e,t)),!y.pixelBoxStyles()&&$e.test(a)&&Be.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+\"\":a}function ze(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(u){s.style.cssText=\"position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0\",u.style.cssText=\"position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%\",ie.appendChild(s).appendChild(u);var e=C.getComputedStyle(u);n=\"1%\"!==e.top,a=12===t(e.marginLeft),u.style.right=\"60%\",o=36===t(e.right),r=36===t(e.width),u.style.position=\"absolute\",i=12===t(u.offsetWidth/3),ie.removeChild(s),u=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s=E.createElement(\"div\"),u=E.createElement(\"div\");u.style&&(u.style.backgroundClip=\"content-box\",u.cloneNode(!0).style.backgroundClip=\"\",y.clearCloneStyle=\"content-box\"===u.style.backgroundClip,k.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),a},scrollboxSize:function(){return e(),i}}))}();var Ue=[\"Webkit\",\"Moz\",\"ms\"],Xe=E.createElement(\"div\").style,Ve={};function Ge(e){var t=k.cssProps[e]||Ve[e];return t||(e in Xe?e:Ve[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Ue.length;while(n--)if((e=Ue[n]+t)in Xe)return e}(e)||e)}var Ye=/^(none|table(?!-c[ea]).+)/,Qe=/^--/,Je={position:\"absolute\",visibility:\"hidden\",display:\"block\"},Ke={letterSpacing:\"0\",fontWeight:\"400\"};function Ze(e,t,n){var r=ne.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||\"px\"):t}function et(e,t,n,r,i,o){var a=\"width\"===t?1:0,s=0,u=0;if(n===(r?\"border\":\"content\"))return 0;for(;a<4;a+=2)\"margin\"===n&&(u+=k.css(e,n+re[a],!0,i)),r?(\"content\"===n&&(u-=k.css(e,\"padding\"+re[a],!0,i)),\"margin\"!==n&&(u-=k.css(e,\"border\"+re[a]+\"Width\",!0,i))):(u+=k.css(e,\"padding\"+re[a],!0,i),\"padding\"!==n?u+=k.css(e,\"border\"+re[a]+\"Width\",!0,i):s+=k.css(e,\"border\"+re[a]+\"Width\",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e[\"offset\"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function tt(e,t,n){var r=Fe(e),i=(!y.boxSizingReliable()||n)&&\"border-box\"===k.css(e,\"boxSizing\",!1,r),o=i,a=_e(e,t,r),s=\"offset\"+t[0].toUpperCase()+t.slice(1);if($e.test(a)){if(!n)return a;a=\"auto\"}return(!y.boxSizingReliable()&&i||\"auto\"===a||!parseFloat(a)&&\"inline\"===k.css(e,\"display\",!1,r))&&e.getClientRects().length&&(i=\"border-box\"===k.css(e,\"boxSizing\",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+et(e,t,n||(i?\"border\":\"content\"),o,r,a)+\"px\"}function nt(e,t,n,r,i){return new nt.prototype.init(e,t,n,r,i)}k.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=_e(e,\"opacity\");return\"\"===n?\"1\":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=V(t),u=Qe.test(t),l=e.style;if(u||(t=Ge(s)),a=k.cssHooks[t]||k.cssHooks[s],void 0===n)return a&&\"get\"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];\"string\"===(o=typeof n)&&(i=ne.exec(n))&&i[1]&&(n=le(e,t,i),o=\"number\"),null!=n&&n==n&&(\"number\"!==o||u||(n+=i&&i[3]||(k.cssNumber[s]?\"\":\"px\")),y.clearCloneStyle||\"\"!==n||0!==t.indexOf(\"background\")||(l[t]=\"inherit\"),a&&\"set\"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=V(t);return Qe.test(t)||(t=Ge(s)),(a=k.cssHooks[t]||k.cssHooks[s])&&\"get\"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=_e(e,t,r)),\"normal\"===i&&t in Ke&&(i=Ke[t]),\"\"===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),k.each([\"height\",\"width\"],function(e,u){k.cssHooks[u]={get:function(e,t,n){if(t)return!Ye.test(k.css(e,\"display\"))||e.getClientRects().length&&e.getBoundingClientRect().width?tt(e,u,n):ue(e,Je,function(){return tt(e,u,n)})},set:function(e,t,n){var r,i=Fe(e),o=!y.scrollboxSize()&&\"absolute\"===i.position,a=(o||n)&&\"border-box\"===k.css(e,\"boxSizing\",!1,i),s=n?et(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e[\"offset\"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-et(e,u,\"border\",!1,i)-.5)),s&&(r=ne.exec(t))&&\"px\"!==(r[3]||\"px\")&&(e.style[u]=t,t=k.css(e,u)),Ze(0,t,s)}}}),k.cssHooks.marginLeft=ze(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(_e(e,\"marginLeft\"))||e.getBoundingClientRect().left-ue(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+\"px\"}),k.each({margin:\"\",padding:\"\",border:\"Width\"},function(i,o){k.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r=\"string\"==typeof e?e.split(\" \"):[e];t<4;t++)n[i+re[t]+o]=r[t]||r[t-2]||r[0];return n}},\"margin\"!==i&&(k.cssHooks[i+o].set=Ze)}),k.fn.extend({css:function(e,t){return _(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Fe(e),i=t.length;a<i;a++)o[t[a]]=k.css(e,t[a],!1,r);return o}return void 0!==n?k.style(e,t,n):k.css(e,t)},e,t,1<arguments.length)}}),((k.Tween=nt).prototype={constructor:nt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||k.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(k.cssNumber[n]?\"\":\"px\")},cur:function(){var e=nt.propHooks[this.prop];return e&&e.get?e.get(this):nt.propHooks._default.get(this)},run:function(e){var t,n=nt.propHooks[this.prop];return this.options.duration?this.pos=t=k.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):nt.propHooks._default.set(this),this}}).init.prototype=nt.prototype,(nt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=k.css(e.elem,e.prop,\"\"))&&\"auto\"!==t?t:0},set:function(e){k.fx.step[e.prop]?k.fx.step[e.prop](e):1!==e.elem.nodeType||!k.cssHooks[e.prop]&&null==e.elem.style[Ge(e.prop)]?e.elem[e.prop]=e.now:k.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=nt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},k.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:\"swing\"},k.fx=nt.prototype.init,k.fx.step={};var rt,it,ot,at,st=/^(?:toggle|show|hide)$/,ut=/queueHooks$/;function lt(){it&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(lt):C.setTimeout(lt,k.fx.interval),k.fx.tick())}function ct(){return C.setTimeout(function(){rt=void 0}),rt=Date.now()}function ft(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i[\"margin\"+(n=re[r])]=i[\"padding\"+n]=e;return t&&(i.opacity=i.width=e),i}function pt(e,t,n){for(var r,i=(dt.tweeners[t]||[]).concat(dt.tweeners[\"*\"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function dt(o,e,t){var n,a,r=0,i=dt.prefilters.length,s=k.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=rt||ct(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:k.extend({},e),opts:k.extend(!0,{specialEasing:{},easing:k.easing._default},t),originalProperties:e,originalOptions:t,startTime:rt||ct(),duration:t.duration,tweens:[],createTween:function(e,t){var n=k.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=V(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=k.cssHooks[r])&&\"expand\"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=dt.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(k._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return k.map(c,pt,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),k.fx.timer(k.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}k.Animation=k.extend(dt,{tweeners:{\"*\":[function(e,t){var n=this.createTween(e,t);return le(n.elem,e,ne.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=[\"*\"]):e=e.match(R);for(var n,r=0,i=e.length;r<i;r++)n=e[r],dt.tweeners[n]=dt.tweeners[n]||[],dt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f=\"width\"in t||\"height\"in t,p=this,d={},h=e.style,g=e.nodeType&&se(e),v=Q.get(e,\"fxshow\");for(r in n.queue||(null==(a=k._queueHooks(e,\"fx\")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,k.queue(e,\"fx\").length||a.empty.fire()})})),t)if(i=t[r],st.test(i)){if(delete t[r],o=o||\"toggle\"===i,i===(g?\"hide\":\"show\")){if(\"show\"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||k.style(e,r)}if((u=!k.isEmptyObject(t))||!k.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Q.get(e,\"display\")),\"none\"===(c=k.css(e,\"display\"))&&(l?c=l:(fe([e],!0),l=e.style.display||l,c=k.css(e,\"display\"),fe([e]))),(\"inline\"===c||\"inline-block\"===c&&null!=l)&&\"none\"===k.css(e,\"float\")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l=\"none\"===c?\"\":c)),h.display=\"inline-block\")),n.overflow&&(h.overflow=\"hidden\",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?\"hidden\"in v&&(g=v.hidden):v=Q.access(e,\"fxshow\",{display:l}),o&&(v.hidden=!g),g&&fe([e],!0),p.done(function(){for(r in g||fe([e]),Q.remove(e,\"fxshow\"),d)k.style(e,r,d[r])})),u=pt(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?dt.prefilters.unshift(e):dt.prefilters.push(e)}}),k.speed=function(e,t,n){var r=e&&\"object\"==typeof e?k.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return k.fx.off?r.duration=0:\"number\"!=typeof r.duration&&(r.duration in k.fx.speeds?r.duration=k.fx.speeds[r.duration]:r.duration=k.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue=\"fx\"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&k.dequeue(this,r.queue)},r},k.fn.extend({fadeTo:function(e,t,n,r){return this.filter(se).css(\"opacity\",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=k.isEmptyObject(t),o=k.speed(e,n,r),a=function(){var e=dt(this,k.extend({},t),o);(i||Q.get(this,\"finish\"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return\"string\"!=typeof i&&(o=e,e=i,i=void 0),e&&!1!==i&&this.queue(i||\"fx\",[]),this.each(function(){var e=!0,t=null!=i&&i+\"queueHooks\",n=k.timers,r=Q.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&ut.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||k.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||\"fx\"),this.each(function(){var e,t=Q.get(this),n=t[a+\"queue\"],r=t[a+\"queueHooks\"],i=k.timers,o=n?n.length:0;for(t.finish=!0,k.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),k.each([\"toggle\",\"show\",\"hide\"],function(e,r){var i=k.fn[r];k.fn[r]=function(e,t,n){return null==e||\"boolean\"==typeof e?i.apply(this,arguments):this.animate(ft(r,!0),e,t,n)}}),k.each({slideDown:ft(\"show\"),slideUp:ft(\"hide\"),slideToggle:ft(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(e,r){k.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),k.timers=[],k.fx.tick=function(){var e,t=0,n=k.timers;for(rt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||k.fx.stop(),rt=void 0},k.fx.timer=function(e){k.timers.push(e),k.fx.start()},k.fx.interval=13,k.fx.start=function(){it||(it=!0,lt())},k.fx.stop=function(){it=null},k.fx.speeds={slow:600,fast:200,_default:400},k.fn.delay=function(r,e){return r=k.fx&&k.fx.speeds[r]||r,e=e||\"fx\",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},ot=E.createElement(\"input\"),at=E.createElement(\"select\").appendChild(E.createElement(\"option\")),ot.type=\"checkbox\",y.checkOn=\"\"!==ot.value,y.optSelected=at.selected,(ot=E.createElement(\"input\")).value=\"t\",ot.type=\"radio\",y.radioValue=\"t\"===ot.value;var ht,gt=k.expr.attrHandle;k.fn.extend({attr:function(e,t){return _(this,k.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){k.removeAttr(this,e)})}}),k.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return\"undefined\"==typeof e.getAttribute?k.prop(e,t,n):(1===o&&k.isXMLDoc(e)||(i=k.attrHooks[t.toLowerCase()]||(k.expr.match.bool.test(t)?ht:void 0)),void 0!==n?null===n?void k.removeAttr(e,t):i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+\"\"),n):i&&\"get\"in i&&null!==(r=i.get(e,t))?r:null==(r=k.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&\"radio\"===t&&A(e,\"input\")){var n=e.value;return e.setAttribute(\"type\",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(R);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),ht={set:function(e,t,n){return!1===t?k.removeAttr(e,n):e.setAttribute(n,n),n}},k.each(k.expr.match.bool.source.match(/\\w+/g),function(e,t){var a=gt[t]||k.find.attr;gt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=gt[o],gt[o]=r,r=null!=a(e,t,n)?o:null,gt[o]=i),r}});var vt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;function mt(e){return(e.match(R)||[]).join(\" \")}function xt(e){return e.getAttribute&&e.getAttribute(\"class\")||\"\"}function bt(e){return Array.isArray(e)?e:\"string\"==typeof e&&e.match(R)||[]}k.fn.extend({prop:function(e,t){return _(this,k.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[k.propFix[e]||e]})}}),k.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&k.isXMLDoc(e)||(t=k.propFix[t]||t,i=k.propHooks[t]),void 0!==n?i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&\"get\"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=k.find.attr(e,\"tabindex\");return t?parseInt(t,10):vt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{\"for\":\"htmlFor\",\"class\":\"className\"}}),y.optSelected||(k.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),k.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){k.propFix[this.toLowerCase()]=this}),k.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).addClass(t.call(this,e,xt(this)))});if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&\" \"+mt(i)+\" \"){a=0;while(o=e[a++])r.indexOf(\" \"+o+\" \")<0&&(r+=o+\" \");i!==(s=mt(r))&&n.setAttribute(\"class\",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).removeClass(t.call(this,e,xt(this)))});if(!arguments.length)return this.attr(\"class\",\"\");if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&\" \"+mt(i)+\" \"){a=0;while(o=e[a++])while(-1<r.indexOf(\" \"+o+\" \"))r=r.replace(\" \"+o+\" \",\" \");i!==(s=mt(r))&&n.setAttribute(\"class\",s)}return this},toggleClass:function(i,t){var o=typeof i,a=\"string\"===o||Array.isArray(i);return\"boolean\"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){k(this).toggleClass(i.call(this,e,xt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=k(this),r=bt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&\"boolean\"!==o||((e=xt(this))&&Q.set(this,\"__className__\",e),this.setAttribute&&this.setAttribute(\"class\",e||!1===i?\"\":Q.get(this,\"__className__\")||\"\"))})},hasClass:function(e){var t,n,r=0;t=\" \"+e+\" \";while(n=this[r++])if(1===n.nodeType&&-1<(\" \"+mt(xt(n))+\" \").indexOf(t))return!0;return!1}});var wt=/\\r/g;k.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,k(this).val()):n)?t=\"\":\"number\"==typeof t?t+=\"\":Array.isArray(t)&&(t=k.map(t,function(e){return null==e?\"\":e+\"\"})),(r=k.valHooks[this.type]||k.valHooks[this.nodeName.toLowerCase()])&&\"set\"in r&&void 0!==r.set(this,t,\"value\")||(this.value=t))})):t?(r=k.valHooks[t.type]||k.valHooks[t.nodeName.toLowerCase()])&&\"get\"in r&&void 0!==(e=r.get(t,\"value\"))?e:\"string\"==typeof(e=t.value)?e.replace(wt,\"\"):null==e?\"\":e:void 0}}),k.extend({valHooks:{option:{get:function(e){var t=k.find.attr(e,\"value\");return null!=t?t:mt(k.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a=\"select-one\"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,\"optgroup\"))){if(t=k(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=k.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<k.inArray(k.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),k.each([\"radio\",\"checkbox\"],function(){k.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<k.inArray(k(e).val(),t)}},y.checkOn||(k.valHooks[this].get=function(e){return null===e.getAttribute(\"value\")?\"on\":e.value})}),y.focusin=\"onfocusin\"in C;var Tt=/^(?:focusinfocus|focusoutblur)$/,Ct=function(e){e.stopPropagation()};k.extend(k.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,\"type\")?e.type:e,h=v.call(e,\"namespace\")?e.namespace.split(\".\"):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!Tt.test(d+k.event.triggered)&&(-1<d.indexOf(\".\")&&(d=(h=d.split(\".\")).shift(),h.sort()),u=d.indexOf(\":\")<0&&\"on\"+d,(e=e[k.expando]?e:new k.Event(d,\"object\"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join(\".\"),e.rnamespace=e.namespace?new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:k.makeArray(t,[e]),c=k.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,Tt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Q.get(o,\"events\")||{})[e.type]&&Q.get(o,\"handle\"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&G(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!G(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),k.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,Ct),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,Ct),k.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=k.extend(new k.Event,n,{type:e,isSimulated:!0});k.event.trigger(r,null,t)}}),k.fn.extend({trigger:function(e,t){return this.each(function(){k.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return k.event.trigger(e,t,n,!0)}}),y.focusin||k.each({focus:\"focusin\",blur:\"focusout\"},function(n,r){var i=function(e){k.event.simulate(r,e.target,k.event.fix(e))};k.event.special[r]={setup:function(){var e=this.ownerDocument||this,t=Q.access(e,r);t||e.addEventListener(n,i,!0),Q.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this,t=Q.access(e,r)-1;t?Q.access(e,r,t):(e.removeEventListener(n,i,!0),Q.remove(e,r))}}});var Et=C.location,kt=Date.now(),St=/\\?/;k.parseXML=function(e){var t;if(!e||\"string\"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,\"text/xml\")}catch(e){t=void 0}return t&&!t.getElementsByTagName(\"parsererror\").length||k.error(\"Invalid XML: \"+e),t};var Nt=/\\[\\]$/,At=/\\r?\\n/g,Dt=/^(?:submit|button|image|reset|file)$/i,jt=/^(?:input|select|textarea|keygen)/i;function qt(n,e,r,i){var t;if(Array.isArray(e))k.each(e,function(e,t){r||Nt.test(n)?i(n,t):qt(n+\"[\"+(\"object\"==typeof t&&null!=t?e:\"\")+\"]\",t,r,i)});else if(r||\"object\"!==w(e))i(n,e);else for(t in e)qt(n+\"[\"+t+\"]\",e[t],r,i)}k.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+\"=\"+encodeURIComponent(null==n?\"\":n)};if(null==e)return\"\";if(Array.isArray(e)||e.jquery&&!k.isPlainObject(e))k.each(e,function(){i(this.name,this.value)});else for(n in e)qt(n,e[n],t,i);return r.join(\"&\")},k.fn.extend({serialize:function(){return k.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=k.prop(this,\"elements\");return e?k.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!k(this).is(\":disabled\")&&jt.test(this.nodeName)&&!Dt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=k(this).val();return null==n?null:Array.isArray(n)?k.map(n,function(e){return{name:t.name,value:e.replace(At,\"\\r\\n\")}}):{name:t.name,value:n.replace(At,\"\\r\\n\")}}).get()}});var Lt=/%20/g,Ht=/#.*$/,Ot=/([?&])_=[^&]*/,Pt=/^(.*?):[ \\t]*([^\\r\\n]*)$/gm,Rt=/^(?:GET|HEAD)$/,Mt=/^\\/\\//,It={},Wt={},$t=\"*/\".concat(\"*\"),Ft=E.createElement(\"a\");function Bt(o){return function(e,t){\"string\"!=typeof e&&(t=e,e=\"*\");var n,r=0,i=e.toLowerCase().match(R)||[];if(m(t))while(n=i[r++])\"+\"===n[0]?(n=n.slice(1)||\"*\",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function _t(t,i,o,a){var s={},u=t===Wt;function l(e){var r;return s[e]=!0,k.each(t[e]||[],function(e,t){var n=t(i,o,a);return\"string\"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s[\"*\"]&&l(\"*\")}function zt(e,t){var n,r,i=k.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&k.extend(!0,e,r),e}Ft.href=Et.href,k.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Et.href,type:\"GET\",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Et.protocol),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":$t,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":JSON.parse,\"text xml\":k.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,k.ajaxSettings),t):zt(k.ajaxSettings,e)},ajaxPrefilter:Bt(It),ajaxTransport:Bt(Wt),ajax:function(e,t){\"object\"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=k.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?k(y):k.event,x=k.Deferred(),b=k.Callbacks(\"once memory\"),w=v.statusCode||{},a={},s={},u=\"canceled\",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Pt.exec(p))n[t[1].toLowerCase()+\" \"]=(n[t[1].toLowerCase()+\" \"]||[]).concat(t[2])}t=n[e.toLowerCase()+\" \"]}return null==t?null:t.join(\", \")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Et.href)+\"\").replace(Mt,Et.protocol+\"//\"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||\"*\").toLowerCase().match(R)||[\"\"],null==v.crossDomain){r=E.createElement(\"a\");try{r.href=v.url,r.href=r.href,v.crossDomain=Ft.protocol+\"//\"+Ft.host!=r.protocol+\"//\"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&\"string\"!=typeof v.data&&(v.data=k.param(v.data,v.traditional)),_t(It,v,t,T),h)return T;for(i in(g=k.event&&v.global)&&0==k.active++&&k.event.trigger(\"ajaxStart\"),v.type=v.type.toUpperCase(),v.hasContent=!Rt.test(v.type),f=v.url.replace(Ht,\"\"),v.hasContent?v.data&&v.processData&&0===(v.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&(v.data=v.data.replace(Lt,\"+\")):(o=v.url.slice(f.length),v.data&&(v.processData||\"string\"==typeof v.data)&&(f+=(St.test(f)?\"&\":\"?\")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Ot,\"$1\"),o=(St.test(f)?\"&\":\"?\")+\"_=\"+kt+++o),v.url=f+o),v.ifModified&&(k.lastModified[f]&&T.setRequestHeader(\"If-Modified-Since\",k.lastModified[f]),k.etag[f]&&T.setRequestHeader(\"If-None-Match\",k.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader(\"Content-Type\",v.contentType),T.setRequestHeader(\"Accept\",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+(\"*\"!==v.dataTypes[0]?\", \"+$t+\"; q=0.01\":\"\"):v.accepts[\"*\"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u=\"abort\",b.add(v.complete),T.done(v.success),T.fail(v.error),c=_t(Wt,v,t,T)){if(T.readyState=1,g&&m.trigger(\"ajaxSend\",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort(\"timeout\")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,\"No Transport\");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||\"\",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while(\"*\"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader(\"Content-Type\"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+\" \"+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if(\"*\"===o)o=u;else if(\"*\"!==u&&u!==o){if(!(a=l[u+\" \"+o]||l[\"* \"+o]))for(i in l)if((s=i.split(\" \"))[1]===o&&(a=l[u+\" \"+s[0]]||l[\"* \"+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e[\"throws\"])t=a(t);else try{t=a(t)}catch(e){return{state:\"parsererror\",error:a?e:\"No conversion from \"+u+\" to \"+o}}}return{state:\"success\",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader(\"Last-Modified\"))&&(k.lastModified[f]=u),(u=T.getResponseHeader(\"etag\"))&&(k.etag[f]=u)),204===e||\"HEAD\"===v.type?l=\"nocontent\":304===e?l=\"notmodified\":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l=\"error\",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+\"\",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?\"ajaxSuccess\":\"ajaxError\",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger(\"ajaxComplete\",[T,v]),--k.active||k.event.trigger(\"ajaxStop\")))}return T},getJSON:function(e,t,n){return k.get(e,t,n,\"json\")},getScript:function(e,t){return k.get(e,void 0,t,\"script\")}}),k.each([\"get\",\"post\"],function(e,i){k[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),k.ajax(k.extend({url:e,type:i,dataType:r,data:t,success:n},k.isPlainObject(e)&&e))}}),k._evalUrl=function(e,t){return k.ajax({url:e,type:\"GET\",dataType:\"script\",cache:!0,async:!1,global:!1,converters:{\"text script\":function(){}},dataFilter:function(e){k.globalEval(e,t)}})},k.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=k(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){k(this).wrapInner(n.call(this,e))}):this.each(function(){var e=k(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){k(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not(\"body\").each(function(){k(this).replaceWith(this.childNodes)}),this}}),k.expr.pseudos.hidden=function(e){return!k.expr.pseudos.visible(e)},k.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},k.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var Ut={0:200,1223:204},Xt=k.ajaxSettings.xhr();y.cors=!!Xt&&\"withCredentials\"in Xt,y.ajax=Xt=!!Xt,k.ajaxTransport(function(i){var o,a;if(y.cors||Xt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e[\"X-Requested-With\"]||(e[\"X-Requested-With\"]=\"XMLHttpRequest\"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,\"abort\"===e?r.abort():\"error\"===e?\"number\"!=typeof r.status?t(0,\"error\"):t(r.status,r.statusText):t(Ut[r.status]||r.status,r.statusText,\"text\"!==(r.responseType||\"text\")||\"string\"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o(\"error\"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o(\"abort\");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),k.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),k.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(e){return k.globalEval(e),e}}}),k.ajaxPrefilter(\"script\",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type=\"GET\")}),k.ajaxTransport(\"script\",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=k(\"<script>\").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on(\"load error\",i=function(e){r.remove(),i=null,e&&t(\"error\"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\\?(?=&|$)|\\?\\?/;k.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var e=Gt.pop()||k.expando+\"_\"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter(\"json jsonp\",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?\"url\":\"string\"==typeof e.data&&0===(e.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&Yt.test(e.data)&&\"data\");if(a||\"jsonp\"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,\"$1\"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?\"&\":\"?\")+e.jsonp+\"=\"+r),e.converters[\"script json\"]=function(){return o||k.error(r+\" was not called\"),o[0]},e.dataTypes[0]=\"json\",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),\"script\"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument(\"\").body).innerHTML=\"<form></form><form></form>\",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return\"string\"!=typeof e?[]:(\"boolean\"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument(\"\")).createElement(\"base\")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(\" \");return-1<s&&(r=mt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&\"object\"==typeof t&&(i=\"POST\"),0<a.length&&k.ajax({url:e,type:i||\"GET\",dataType:\"html\",data:t}).done(function(e){o=arguments,a.html(r?k(\"<div>\").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,\"position\"),c=k(e),f={};\"static\"===l&&(e.style.position=\"relative\"),s=c.offset(),o=k.css(e,\"top\"),u=k.css(e,\"left\"),(\"absolute\"===l||\"fixed\"===l)&&-1<(o+u).indexOf(\"auto\")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),\"using\"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if(\"fixed\"===k.css(r,\"position\"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&\"static\"===k.css(e,\"position\"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,\"borderTopWidth\",!0),i.left+=k.css(e,\"borderLeftWidth\",!0))}return{top:t.top-i.top-k.css(r,\"marginTop\",!0),left:t.left-i.left-k.css(r,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&\"static\"===k.css(e,\"position\"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(t,i){var o=\"pageYOffset\"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each([\"top\",\"left\"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+\"px\":t})}),k.each({Height:\"height\",Width:\"width\"},function(a,s){k.each({padding:\"inner\"+a,content:s,\"\":\"outer\"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||\"boolean\"!=typeof e),i=r||(!0===e||!0===t?\"margin\":\"border\");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf(\"outer\")?e[\"inner\"+a]:e.document.documentElement[\"client\"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body[\"scroll\"+a],r[\"scroll\"+a],e.body[\"offset\"+a],r[\"offset\"+a],r[\"client\"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each(\"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu\".split(\" \"),function(e,n){k.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}}),k.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),k.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)}}),k.proxy=function(e,t){var n,r,i;if(\"string\"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||k.guid++,i},k.holdReady=function(e){e?k.readyWait++:k.ready(!0)},k.isArray=Array.isArray,k.parseJSON=JSON.parse,k.nodeName=A,k.isFunction=m,k.isWindow=x,k.camelCase=V,k.type=w,k.now=Date.now,k.isNumeric=function(e){var t=k.type(e);return(\"number\"===t||\"string\"===t)&&!isNaN(e-parseFloat(e))},\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return k});var Qt=C.jQuery,Jt=C.$;return k.noConflict=function(e){return C.$===k&&(C.$=Jt),e&&C.jQuery===k&&(C.jQuery=Qt),k},e||(C.jQuery=C.$=k),k});\n/*\n * jQuery throttle / debounce - v1.1 - 3/7/2010\n * http://benalman.com/projects/jquery-throttle-debounce-plugin/\n * \n * Copyright (c) 2010 \"Cowboy\" Ben Alman\n * Dual licensed under the MIT and GPL licenses.\n * http://benalman.com/about/license/\n */\n(function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!==\"boolean\"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this);\n/*!\n * imagesLoaded PACKAGED v4.1.0\n * JavaScript is all like \"You images are done yet or what?\"\n * MIT License\n */\n!function(t,e){\"function\"==typeof define&&define.amd?define(\"ev-emitter/ev-emitter\",e):\"object\"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}(this,function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var i=this._events=this._events||{},n=i[t]=i[t]||[];return-1==n.indexOf(e)&&n.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var i=this._onceEvents=this._onceEvents||{},n=i[t]=i[t]||[];return n[e]=!0,this}},e.off=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=i.indexOf(e);return-1!=n&&i.splice(n,1),this}},e.emitEvent=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=0,o=i[n];e=e||[];for(var r=this._onceEvents&&this._onceEvents[t];o;){var s=r&&r[o];s&&(this.off(t,o),delete r[o]),o.apply(this,e),n+=s?0:1,o=i[n]}return this}},t}),function(t,e){\"use strict\";\"function\"==typeof define&&define.amd?define([\"ev-emitter/ev-emitter\"],function(i){return e(t,i)}):\"object\"==typeof module&&module.exports?module.exports=e(t,require(\"ev-emitter\")):t.imagesLoaded=e(t,t.EvEmitter)}(window,function(t,e){function i(t,e){for(var i in e)t[i]=e[i];return t}function n(t){var e=[];if(Array.isArray(t))e=t;else if(\"number\"==typeof t.length)for(var i=0;i<t.length;i++)e.push(t[i]);else e.push(t);return e}function o(t,e,r){return this instanceof o?(\"string\"==typeof t&&(t=document.querySelectorAll(t)),this.elements=n(t),this.options=i({},this.options),\"function\"==typeof e?r=e:i(this.options,e),r&&this.on(\"always\",r),this.getImages(),h&&(this.jqDeferred=new h.Deferred),void setTimeout(function(){this.check()}.bind(this))):new o(t,e,r)}function r(t){this.img=t}function s(t,e){this.url=t,this.element=e,this.img=new Image}var h=t.jQuery,a=t.console;o.prototype=Object.create(e.prototype),o.prototype.options={},o.prototype.getImages=function(){this.images=[],this.elements.forEach(this.addElementImages,this)},o.prototype.addElementImages=function(t){\"IMG\"==t.nodeName&&this.addImage(t),this.options.background===!0&&this.addElementBackgroundImages(t);var e=t.nodeType;if(e&&d[e]){for(var i=t.querySelectorAll(\"img\"),n=0;n<i.length;n++){var o=i[n];this.addImage(o)}if(\"string\"==typeof this.options.background){var r=t.querySelectorAll(this.options.background);for(n=0;n<r.length;n++){var s=r[n];this.addElementBackgroundImages(s)}}}};var d={1:!0,9:!0,11:!0};return o.prototype.addElementBackgroundImages=function(t){var e=getComputedStyle(t);if(e)for(var i=/url\\((['\"])?(.*?)\\1\\)/gi,n=i.exec(e.backgroundImage);null!==n;){var o=n&&n[2];o&&this.addBackground(o,t),n=i.exec(e.backgroundImage)}},o.prototype.addImage=function(t){var e=new r(t);this.images.push(e)},o.prototype.addBackground=function(t,e){var i=new s(t,e);this.images.push(i)},o.prototype.check=function(){function t(t,i,n){setTimeout(function(){e.progress(t,i,n)})}var e=this;return this.progressedCount=0,this.hasAnyBroken=!1,this.images.length?void this.images.forEach(function(e){e.once(\"progress\",t),e.check()}):void this.complete()},o.prototype.progress=function(t,e,i){this.progressedCount++,this.hasAnyBroken=this.hasAnyBroken||!t.isLoaded,this.emitEvent(\"progress\",[this,t,e]),this.jqDeferred&&this.jqDeferred.notify&&this.jqDeferred.notify(this,t),this.progressedCount==this.images.length&&this.complete(),this.options.debug&&a&&a.log(\"progress: \"+i,t,e)},o.prototype.complete=function(){var t=this.hasAnyBroken?\"fail\":\"done\";if(this.isComplete=!0,this.emitEvent(t,[this]),this.emitEvent(\"always\",[this]),this.jqDeferred){var e=this.hasAnyBroken?\"reject\":\"resolve\";this.jqDeferred[e](this)}},r.prototype=Object.create(e.prototype),r.prototype.check=function(){var t=this.getIsImageComplete();return t?void this.confirm(0!==this.img.naturalWidth,\"naturalWidth\"):(this.proxyImage=new Image,this.proxyImage.addEventListener(\"load\",this),this.proxyImage.addEventListener(\"error\",this),this.img.addEventListener(\"load\",this),this.img.addEventListener(\"error\",this),void(this.proxyImage.src=this.img.src))},r.prototype.getIsImageComplete=function(){return this.img.complete&&void 0!==this.img.naturalWidth},r.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent(\"progress\",[this,this.img,e])},r.prototype.handleEvent=function(t){var e=\"on\"+t.type;this[e]&&this[e](t)},r.prototype.onload=function(){this.confirm(!0,\"onload\"),this.unbindEvents()},r.prototype.onerror=function(){this.confirm(!1,\"onerror\"),this.unbindEvents()},r.prototype.unbindEvents=function(){this.proxyImage.removeEventListener(\"load\",this),this.proxyImage.removeEventListener(\"error\",this),this.img.removeEventListener(\"load\",this),this.img.removeEventListener(\"error\",this)},s.prototype=Object.create(r.prototype),s.prototype.check=function(){this.img.addEventListener(\"load\",this),this.img.addEventListener(\"error\",this),this.img.src=this.url;var t=this.getIsImageComplete();t&&(this.confirm(0!==this.img.naturalWidth,\"naturalWidth\"),this.unbindEvents())},s.prototype.unbindEvents=function(){this.img.removeEventListener(\"load\",this),this.img.removeEventListener(\"error\",this)},s.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent(\"progress\",[this,this.element,e])},o.makeJQueryPlugin=function(e){e=e||t.jQuery,e&&(h=e,h.fn.imagesLoaded=function(t,e){var i=new o(this,t,e);return i.jqDeferred.promise(h(this))})},o.makeJQueryPlugin(),o});\n/*! lz-string-1.3.3-min.js | (c) 2013 Pieroxy | Licensed under a WTFPL license */\nvar LZString={_keyStr:\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\",_f:String.fromCharCode,compressToBase64:function(e){if(e==null)return\"\";var t=\"\";var n,r,i,s,o,u,a;var f=0;e=LZString.compress(e);while(f<e.length*2){if(f%2==0){n=e.charCodeAt(f/2)>>8;r=e.charCodeAt(f/2)&255;if(f/2+1<e.length)i=e.charCodeAt(f/2+1)>>8;else i=NaN}else{n=e.charCodeAt((f-1)/2)&255;if((f+1)/2<e.length){r=e.charCodeAt((f+1)/2)>>8;i=e.charCodeAt((f+1)/2)&255}else r=i=NaN}f+=3;s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+LZString._keyStr.charAt(s)+LZString._keyStr.charAt(o)+LZString._keyStr.charAt(u)+LZString._keyStr.charAt(a)}return t},decompressFromBase64:function(e){if(e==null)return\"\";var t=\"\",n=0,r,i,s,o,u,a,f,l,c=0,h=LZString._f;e=e.replace(/[^A-Za-z0-9\\+\\/\\=]/g,\"\");while(c<e.length){u=LZString._keyStr.indexOf(e.charAt(c++));a=LZString._keyStr.indexOf(e.charAt(c++));f=LZString._keyStr.indexOf(e.charAt(c++));l=LZString._keyStr.indexOf(e.charAt(c++));i=u<<2|a>>4;s=(a&15)<<4|f>>2;o=(f&3)<<6|l;if(n%2==0){r=i<<8;if(f!=64){t+=h(r|s)}if(l!=64){r=o<<8}}else{t=t+h(r|i);if(f!=64){r=s<<8}if(l!=64){t+=h(r|o)}}n+=3}return LZString.decompress(t)},compressToUTF16:function(e){if(e==null)return\"\";var t=\"\",n,r,i,s=0,o=LZString._f;e=LZString.compress(e);for(n=0;n<e.length;n++){r=e.charCodeAt(n);switch(s++){case 0:t+=o((r>>1)+32);i=(r&1)<<14;break;case 1:t+=o(i+(r>>2)+32);i=(r&3)<<13;break;case 2:t+=o(i+(r>>3)+32);i=(r&7)<<12;break;case 3:t+=o(i+(r>>4)+32);i=(r&15)<<11;break;case 4:t+=o(i+(r>>5)+32);i=(r&31)<<10;break;case 5:t+=o(i+(r>>6)+32);i=(r&63)<<9;break;case 6:t+=o(i+(r>>7)+32);i=(r&127)<<8;break;case 7:t+=o(i+(r>>8)+32);i=(r&255)<<7;break;case 8:t+=o(i+(r>>9)+32);i=(r&511)<<6;break;case 9:t+=o(i+(r>>10)+32);i=(r&1023)<<5;break;case 10:t+=o(i+(r>>11)+32);i=(r&2047)<<4;break;case 11:t+=o(i+(r>>12)+32);i=(r&4095)<<3;break;case 12:t+=o(i+(r>>13)+32);i=(r&8191)<<2;break;case 13:t+=o(i+(r>>14)+32);i=(r&16383)<<1;break;case 14:t+=o(i+(r>>15)+32,(r&32767)+32);s=0;break}}return t+o(i+32)},decompressFromUTF16:function(e){if(e==null)return\"\";var t=\"\",n,r,i=0,s=0,o=LZString._f;while(s<e.length){r=e.charCodeAt(s)-32;switch(i++){case 0:n=r<<1;break;case 1:t+=o(n|r>>14);n=(r&16383)<<2;break;case 2:t+=o(n|r>>13);n=(r&8191)<<3;break;case 3:t+=o(n|r>>12);n=(r&4095)<<4;break;case 4:t+=o(n|r>>11);n=(r&2047)<<5;break;case 5:t+=o(n|r>>10);n=(r&1023)<<6;break;case 6:t+=o(n|r>>9);n=(r&511)<<7;break;case 7:t+=o(n|r>>8);n=(r&255)<<8;break;case 8:t+=o(n|r>>7);n=(r&127)<<9;break;case 9:t+=o(n|r>>6);n=(r&63)<<10;break;case 10:t+=o(n|r>>5);n=(r&31)<<11;break;case 11:t+=o(n|r>>4);n=(r&15)<<12;break;case 12:t+=o(n|r>>3);n=(r&7)<<13;break;case 13:t+=o(n|r>>2);n=(r&3)<<14;break;case 14:t+=o(n|r>>1);n=(r&1)<<15;break;case 15:t+=o(n|r);i=0;break}s++}return LZString.decompress(t)},compress:function(e){if(e==null)return\"\";var t,n,r={},i={},s=\"\",o=\"\",u=\"\",a=2,f=3,l=2,c=\"\",h=0,p=0,d,v=LZString._f;for(d=0;d<e.length;d+=1){s=e.charAt(d);if(!Object.prototype.hasOwnProperty.call(r,s)){r[s]=f++;i[s]=true}o=u+s;if(Object.prototype.hasOwnProperty.call(r,o)){u=o}else{if(Object.prototype.hasOwnProperty.call(i,u)){if(u.charCodeAt(0)<256){for(t=0;t<l;t++){h=h<<1;if(p==15){p=0;c+=v(h);h=0}else{p++}}n=u.charCodeAt(0);for(t=0;t<8;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}else{n=1;for(t=0;t<l;t++){h=h<<1|n;if(p==15){p=0;c+=v(h);h=0}else{p++}n=0}n=u.charCodeAt(0);for(t=0;t<16;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}delete i[u]}else{n=r[u];for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}r[o]=f++;u=String(s)}}if(u!==\"\"){if(Object.prototype.hasOwnProperty.call(i,u)){if(u.charCodeAt(0)<256){for(t=0;t<l;t++){h=h<<1;if(p==15){p=0;c+=v(h);h=0}else{p++}}n=u.charCodeAt(0);for(t=0;t<8;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}else{n=1;for(t=0;t<l;t++){h=h<<1|n;if(p==15){p=0;c+=v(h);h=0}else{p++}n=0}n=u.charCodeAt(0);for(t=0;t<16;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}delete i[u]}else{n=r[u];for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}}n=2;for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}while(true){h=h<<1;if(p==15){c+=v(h);break}else p++}return c},decompress:function(e){if(e==null)return\"\";if(e==\"\")return null;var t=[],n,r=4,i=4,s=3,o=\"\",u=\"\",a,f,l,c,h,p,d,v=LZString._f,m={string:e,val:e.charCodeAt(0),position:32768,index:1};for(a=0;a<3;a+=1){t[a]=a}l=0;h=Math.pow(2,2);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}switch(n=l){case 0:l=0;h=Math.pow(2,8);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}d=v(l);break;case 1:l=0;h=Math.pow(2,16);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}d=v(l);break;case 2:return\"\"}t[3]=d;f=u=d;while(true){if(m.index>m.string.length){return\"\"}l=0;h=Math.pow(2,s);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}switch(d=l){case 0:l=0;h=Math.pow(2,8);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}t[i++]=v(l);d=i-1;r--;break;case 1:l=0;h=Math.pow(2,16);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}t[i++]=v(l);d=i-1;r--;break;case 2:return u}if(r==0){r=Math.pow(2,s);s++}if(t[d]){o=t[d]}else{if(d===i){o=f+f.charAt(0)}else{return null}}u+=o;t[i++]=f+o.charAt(0);r--;f=o;if(r==0){r=Math.pow(2,s);s++}}}};if(typeof module!==\"undefined\"&&module!=null){module.exports=LZString}\n/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */\nvar saveAs=saveAs||navigator.msSaveBlob&&navigator.msSaveBlob.bind(navigator)||function(e){\"use strict\";var t=e.document,n=function(){return e.URL||e.webkitURL||e},r=e.URL||e.webkitURL||e,i=t.createElementNS(\"http://www.w3.org/1999/xhtml\",\"a\"),s=\"download\"in i,o=function(n){var r=t.createEvent(\"MouseEvents\");r.initMouseEvent(\"click\",true,false,e,0,0,0,0,0,false,false,false,false,0,null);n.dispatchEvent(r)},u=e.webkitRequestFileSystem,a=e.requestFileSystem||u||e.mozRequestFileSystem,f=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},l=\"application/octet-stream\",c=0,h=[],p=function(){var e=h.length;while(e--){var t=h[e];if(typeof t===\"string\"){r.revokeObjectURL(t)}else{t.remove()}}h.length=0},d=function(e,t,n){t=[].concat(t);var r=t.length;while(r--){var i=e[\"on\"+t[r]];if(typeof i===\"function\"){try{i.call(e,n||e)}catch(s){f(s)}}}},v=function(t,r){var f=this,p=t.type,v=false,m,g,y=function(){var e=n().createObjectURL(t);h.push(e);return e},b=function(){d(f,\"writestart progress write writeend\".split(\" \"))},w=function(){if(v||!m){m=y(t)}if(g){g.location.href=m}else{window.open(m,\"_blank\")}f.readyState=f.DONE;b()},E=function(e){return function(){if(f.readyState!==f.DONE){return e.apply(this,arguments)}}},S={create:true,exclusive:false},x;f.readyState=f.INIT;if(!r){r=\"download\"}if(s){m=y(t);i.href=m;i.download=r;o(i);f.readyState=f.DONE;b();return}if(e.chrome&&p&&p!==l){x=t.slice||t.webkitSlice;t=x.call(t,0,t.size,l);v=true}if(u&&r!==\"download\"){r+=\".download\"}if(p===l||u){g=e}if(!a){w();return}c+=t.size;a(e.TEMPORARY,c,E(function(e){e.root.getDirectory(\"saved\",S,E(function(e){var n=function(){e.getFile(r,S,E(function(e){e.createWriter(E(function(n){n.onwriteend=function(t){g.location.href=e.toURL();h.push(e);f.readyState=f.DONE;d(f,\"writeend\",t)};n.onerror=function(){var e=n.error;if(e.code!==e.ABORT_ERR){w()}};\"writestart progress write abort\".split(\" \").forEach(function(e){n[\"on\"+e]=f[\"on\"+e]});n.write(t);f.abort=function(){n.abort();f.readyState=f.DONE};f.readyState=f.WRITING}),w)}),w)};e.getFile(r,{create:false},E(function(e){e.remove();n()}),E(function(e){if(e.code===e.NOT_FOUND_ERR){n()}else{w()}}))}),w)}),w)},m=v.prototype,g=function(e,t){return new v(e,t)};m.abort=function(){var e=this;e.readyState=e.DONE;d(e,\"abort\")};m.readyState=m.INIT=0;m.WRITING=1;m.DONE=2;m.error=m.onwritestart=m.onprogress=m.onwrite=m.onabort=m.onerror=m.onwriteend=null;e.addEventListener(\"unload\",p,false);return g}(self)\n/*! seedrandom.js v2.3.3 | (c) 2013 David Bau, all rights reserved. | Licensed under a BSD-style license */\n!function(a,b,c,d,e,f,g,h,i){function j(a){var b,c=a.length,e=this,f=0,g=e.i=e.j=0,h=e.S=[];for(c||(a=[c++]);d>f;)h[f]=f++;for(f=0;d>f;f++)h[f]=h[g=r&g+a[f%c]+(b=h[f])],h[g]=b;(e.g=function(a){for(var b,c=0,f=e.i,g=e.j,h=e.S;a--;)b=h[f=r&f+1],c=c*d+h[r&(h[f]=h[g=r&g+b])+(h[g]=b)];return e.i=f,e.j=g,c})(d)}function k(a,b){var c,d=[],e=typeof a;if(b&&\"object\"==e)for(c in a)try{d.push(k(a[c],b-1))}catch(f){}return d.length?d:\"string\"==e?a:a+\"\\0\"}function l(a,b){for(var c,d=a+\"\",e=0;e<d.length;)b[r&e]=r&(c^=19*b[r&e])+d.charCodeAt(e++);return n(b)}function m(c){try{return a.crypto.getRandomValues(c=new Uint8Array(d)),n(c)}catch(e){return[+new Date,a,(c=a.navigator)&&c.plugins,a.screen,n(b)]}}function n(a){return String.fromCharCode.apply(0,a)}var o=c.pow(d,e),p=c.pow(2,f),q=2*p,r=d-1,s=c[\"seed\"+i]=function(a,f,g){var h=[],r=l(k(f?[a,n(b)]:null==a?m():a,3),h),s=new j(h);return l(n(s.S),b),(g||function(a,b,d){return d?(c[i]=a,b):a})(function(){for(var a=s.g(e),b=o,c=0;p>a;)a=(a+c)*d,b*=d,c=s.g(1);for(;a>=q;)a/=2,b/=2,c>>>=1;return(a+c)/b},r,this==c)};l(c[i](),b),g&&g.exports?g.exports=s:h&&h.amd&&h(function(){return s})}(this,[],Math,256,6,52,\"object\"==typeof module&&module,\"function\"==typeof define&&define,\"random\");\n/*! console_hack.js | (c) 2015 Thomas Michael Edwards | Licensed under SugarCube's Simple BSD license */\n!function(){for(var methods=[\"assert\",\"clear\",\"count\",\"debug\",\"dir\",\"dirxml\",\"error\",\"exception\",\"group\",\"groupCollapsed\",\"groupEnd\",\"info\",\"log\",\"markTimeline\",\"profile\",\"profileEnd\",\"table\",\"time\",\"timeEnd\",\"timeline\",\"timelineEnd\",\"timeStamp\",\"trace\",\"warn\"],length=methods.length,noop=function(){},console=window.console=window.console||{};length--;){var method=methods[length];console[method]||(console[method]=noop)}}();\n}else{document.documentElement.setAttribute(\"data-init\", \"lacking\");}\n</script>\n<style id=\"style-normalize\" type=\"text/css\">/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\n\n/**\n * 1. Set default font family to sans-serif.\n * 2. Prevent iOS and IE text size adjust after device orientation change,\n *    without disabling user zoom.\n */\n\nhtml {\n  font-family: sans-serif; /* 1 */\n  -ms-text-size-adjust: 100%; /* 2 */\n  -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/**\n * Remove default margin.\n */\n\nbody {\n  margin: 0;\n}\n\n/* HTML5 display definitions\n   ========================================================================== */\n\n/**\n * Correct `block` display not defined for any HTML5 element in IE 8/9.\n * Correct `block` display not defined for `details` or `summary` in IE 10/11\n * and Firefox.\n * Correct `block` display not defined for `main` in IE 11.\n */\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\n\n/**\n * 1. Correct `inline-block` display not defined in IE 8/9.\n * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n */\n\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block; /* 1 */\n  vertical-align: baseline; /* 2 */\n}\n\n/**\n * Prevent modern browsers from displaying `audio` without controls.\n * Remove excess height in iOS 5 devices.\n */\n\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n\n/**\n * Address `[hidden]` styling not present in IE 8/9/10.\n * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.\n */\n\n[hidden],\ntemplate {\n  display: none;\n}\n\n/* Links\n   ========================================================================== */\n\n/**\n * Remove the gray background color from active links in IE 10.\n */\n\na {\n  background-color: transparent;\n}\n\n/**\n * Improve readability of focused elements when they are also in an\n * active/hover state.\n */\n\na:active,\na:hover {\n  outline: 0;\n}\n\n/* Text-level semantics\n   ========================================================================== */\n\n/**\n * Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n */\n\nabbr[title] {\n  border-bottom: 1px dotted;\n}\n\n/**\n * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n */\n\nb,\nstrong {\n  font-weight: bold;\n}\n\n/**\n * Address styling not present in Safari and Chrome.\n */\n\ndfn {\n  font-style: italic;\n}\n\n/**\n * Address variable `h1` font-size and margin within `section` and `article`\n * contexts in Firefox 4+, Safari, and Chrome.\n */\n\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\n/**\n * Address styling not present in IE 8/9.\n */\n\nmark {\n  background: #ff0;\n  color: #000;\n}\n\n/**\n * Address inconsistent and variable font size in all browsers.\n */\n\nsmall {\n  font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` affecting `line-height` in all browsers.\n */\n\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\n/* Embedded content\n   ========================================================================== */\n\n/**\n * Remove border when inside `a` element in IE 8/9/10.\n */\n\nimg {\n  border: 0;\n}\n\n/**\n * Correct overflow not hidden in IE 9/10/11.\n */\n\nsvg:not(:root) {\n  overflow: hidden;\n}\n\n/* Grouping content\n   ========================================================================== */\n\n/**\n * Address margin not present in IE 8/9 and Safari.\n */\n\nfigure {\n  margin: 1em 40px;\n}\n\n/**\n * Address differences between Firefox and other browsers.\n */\n\nhr {\n  box-sizing: content-box;\n  height: 0;\n}\n\n/**\n * Contain overflow in all browsers.\n */\n\npre {\n  overflow: auto;\n}\n\n/**\n * Address odd `em`-unit font size rendering in all browsers.\n */\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\n\n/* Forms\n   ========================================================================== */\n\n/**\n * Known limitation: by default, Chrome and Safari on OS X allow very limited\n * styling of `select`, unless a `border` property is set.\n */\n\n/**\n * 1. Correct color not being inherited.\n *    Known issue: affects color of disabled elements.\n * 2. Correct font properties not being inherited.\n * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit; /* 1 */\n  font: inherit; /* 2 */\n  margin: 0; /* 3 */\n}\n\n/**\n * Address `overflow` set to `hidden` in IE 8/9/10/11.\n */\n\nbutton {\n  overflow: visible;\n}\n\n/**\n * Address inconsistent `text-transform` inheritance for `button` and `select`.\n * All other form control elements do not inherit `text-transform` values.\n * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n * Correct `select` style inheritance in Firefox.\n */\n\nbutton,\nselect {\n  text-transform: none;\n}\n\n/**\n * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n *    and `video` controls.\n * 2. Correct inability to style clickable `input` types in iOS.\n * 3. Improve usability and consistency of cursor style between image-type\n *    `input` and others.\n */\n\nbutton,\nhtml input[type=\"button\"], /* 1 */\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button; /* 2 */\n  cursor: pointer; /* 3 */\n}\n\n/**\n * Re-set default cursor for disabled elements.\n */\n\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\n\n/**\n * Remove inner padding and border in Firefox 4+.\n */\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\n\n/**\n * Address Firefox 4+ setting `line-height` on `input` using `!important` in\n * the UA stylesheet.\n */\n\ninput {\n  line-height: normal;\n}\n\n/**\n * It's recommended that you don't attempt to style these elements.\n * Firefox's implementation doesn't respect box-sizing, padding, or width.\n *\n * 1. Address box sizing set to `content-box` in IE 8/9/10.\n * 2. Remove excess padding in IE 8/9/10.\n */\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Fix the cursor style for Chrome's increment/decrement buttons. For certain\n * `font-size` values of the `input`, it causes the cursor style of the\n * decrement button to change from `default` to `text`.\n */\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\n/**\n * 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.\n */\n\ninput[type=\"search\"] {\n  -webkit-appearance: textfield; /* 1 */\n  box-sizing: content-box; /* 2 */\n}\n\n/**\n * Remove inner padding and search cancel button in Safari and Chrome on OS X.\n * Safari (but not Chrome) clips the cancel button when the search input has\n * padding (and `textfield` appearance).\n */\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n/**\n * Define consistent border, margin, and padding.\n */\n\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\n\n/**\n * 1. Correct `color` not being inherited in IE 8/9/10/11.\n * 2. Remove padding so people aren't caught out if they zero out fieldsets.\n */\n\nlegend {\n  border: 0; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Remove default vertical scrollbar in IE 8/9/10/11.\n */\n\ntextarea {\n  overflow: auto;\n}\n\n/**\n * Don't inherit the `font-weight` (applied by a rule above).\n * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n */\n\noptgroup {\n  font-weight: bold;\n}\n\n/* Tables\n   ========================================================================== */\n\n/**\n * Remove most spacing between table cells.\n */\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\ntd,\nth {\n  padding: 0;\n}\n</style>\n<style id=\"style-init-screen\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/init-screen.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n@-webkit-keyframes init-loading-spin {\n\t0%   { -webkit-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); }\n}\n\n@-o-keyframes init-loading-spin {\n\t0%   { -o-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -o-transform: rotate(360deg); transform: rotate(360deg); }\n}\n\n@keyframes init-loading-spin {\n\t0%   { -webkit-transform: rotate(0deg); -o-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -webkit-transform: rotate(360deg); -o-transform: rotate(360deg); transform: rotate(360deg); }\n}\n#init-screen {\n\tdisplay: none;\n\tz-index: 500000;\n\tposition: fixed;\n\ttop: 0px;\n\tleft: 0px;\n\theight: 100%;\n\twidth: 100%;\n\tfont: 28px/1 Helmet, Freesans, sans-serif;\n\tfont-weight: bold;\n\tcolor: #eee;\n\tbackground-color: #111;\n\ttext-align: center;\n}\n#init-screen > div {\n\tdisplay: none;\n\tposition: relative;\n\tmargin: 0 auto;\n\tmax-width: 1136px;\n\ttop: 25%;\n}\nhtml[data-init=\"no-js\"] #init-screen, html[data-init=\"lacking\"] #init-screen, html[data-init=\"loading\"] #init-screen {\n\tdisplay: block;\n}\nhtml[data-init=\"no-js\"] #init-no-js, html[data-init=\"lacking\"] #init-lacking {\n\tdisplay: block;\n\tpadding: 0 1em;\n}\nhtml[data-init=\"no-js\"] #init-no-js {\n\tcolor: red;\n}\nhtml[data-init=\"loading\"] #init-loading {\n\tdisplay: block;\n\tborder: 24px solid transparent;\n\tborder-radius: 50%;\n\tborder-top-color: #7f7f7f;\n\tborder-bottom-color: #7f7f7f;\n\twidth: 100px;\n\theight: 100px;\n\t-webkit-animation: init-loading-spin 2s linear infinite;\n\t     -o-animation: init-loading-spin 2s linear infinite;\n\t        animation: init-loading-spin 2s linear infinite;\n}\nhtml[data-init=\"loading\"] #init-loading > div {\n\ttext-indent: 9999em;\n\toverflow: hidden;\n\twhite-space: nowrap;\n}\nhtml[data-init=\"loading\"] #ui-bar, html[data-init=\"loading\"] #passages {\n\tdisplay: none;\n}\n</style>\n<style id=\"style-font\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/font.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n@font-face {\n\t/*\n\t\ttme-fa-icons (2020-03-27)\n\n\t\t`tme-fa-icons` is a subset of the Font Awesome font v4.7.0 by Dave Gandy (http://fontawesome.com)\n\t\tand is licensed under the SIL OFL 1.1 (http://scripts.sil.org/OFL).\n\t*/\n\tfont-family: \"tme-fa-icons\";\n\tsrc: url('data:application/octet-stream;base64,d09GRgABAAAAADLAAA8AAAAAWHgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABWAAAADsAAABUIIslek9TLzIAAAGUAAAAQwAAAFY+IEkIY21hcAAAAdgAAAG8AAAF3rob9jFjdnQgAAADlAAAABMAAAAgBtX/BGZwZ20AAAOoAAAFkAAAC3CKkZBZZ2FzcAAACTgAAAAIAAAACAAAABBnbHlmAAAJQAAAI6gAADv+gJOpzGhlYWQAACzoAAAAMwAAADYY1IZaaGhlYQAALRwAAAAgAAAAJAfCBClobXR4AAAtPAAAAJEAAAFMBfb/0WxvY2EAAC3QAAAAqAAAAKhjiHI5bWF4cAAALngAAAAgAAAAIAFjDA9uYW1lAAAumAAAAY0AAAL94+zEpHBvc3QAADAoAAACHAAAA11cG/YjcHJlcAAAMkQAAAB6AAAAhuVBK7x4nGNgZGBg4GIwYLBjYHJx8wlh4MtJLMljkGJgYYAAkDwymzEnMz2RgQPGA8qxgGkOIGaDiAIAJjsFSAB4nGNgZNZgnMDAysDAVMW0h4GBoQdCMz5gMGRkAooysDIzYAUBaa4pDA4vGF4EMgf9z2KIYg5imAYUZgTJAQDSIQumAHic7dTVbltRAETR7dpNCikzQ8rMzMxt/M39mHnsU1/TfZz5jFpaV7pXJunMDLAZmOqaZjD5y4Tx+uPTyeL5lG2L5zN+L94zG8+ztr7ulXH1fra4bvK9M79xiWW2sNXPbWeFHexkF7vZw172sZ8DHOQQhznCUY5xnBOc5BSnOcNZVjnHeS5wkUtc5gpX/f3r3OAmt7jNHe5yj/s84CGPeMwTnvKM57zgJa94zRve8o73fOAjn/jMF77yje/84Ce/WGPun1zi/2tlXKbp3Xyc44bFyZanSWokJDXOOjXSk/LUSXn+pEwCKTNBaqQqZU5IjX+XMjukTBEp80TKZJEyY6RMGylzR8oEkjKLpEwlKfNJyqSSMrOkTC8pc0zKRJMy26RMOSnzTsrkk7IDpGwDKXtByoaQsiukbA0p+0PKJpGyU6RsFyl7RmosQcrukbKFpOwjKZtJyo6Ssq2k7C0pG0zKLpOy1aTsNymbTsrOk7L9pNwBUi4CKbeBlCtByr0g5XKQckNIuSak3BVSLgwpt4aUq0PK/SHlEpFyk0i5TqTcKVIuFim3i5QrRso9I+WykXLjXOYNzP8BuAPUwHicY2BAAxIQyBz0PwuEARJsA90AeJytVml300YUHXlJnIQsJQstamHExGmwRiZswYAJQbJjIF2crZWgixQ76b7xid/gX/Nk2nPoN35a7xsvJJC053Cak6N3583VzNtlElqS2AvrkZSbL8XU1iaN7DwJ6YZNy1F8KDt7IWWKyd8FURCtltq3HYdERCJQta6wRBD7HlmaZHzoUUbLtqRXTcotPekuW+NBvVXffho6yrE7oaRmM3RoPbIlVRhVokimPVLSpmWo+itJK7y/wsxXzVDCiE4iabwZxtBI3htntMpoNbbjKIpsstwoUiSa4UEUeZTVEufkigkMygfNkPLKpxHlw/yIrNijnFawS7bT/L4vead3OT+xX29RtuRAH8iO7ODsdCVfhFtbYdy0k+0oVBF213dCbNnsVP9mj/KaRgO3KzK90IxgqXyFECs/ocz+IVktnE/5kkejWrKRE0HrZU7sSz6B1uOIKXHNGFnQ3dEJEdT9kjMM9pg+Hvzx3imWCxMCeBzLekclnAgTKWFzNEnaMHJgJWWLKqn1rpg45XVaxFvCfu3a0ZfOaONQd2I8Ww8dWzlRyfFoUqeZTJ3aSc2jKQ2ilHQmeMyvAyg/oklebWM1iZVH0zhmxoREIgIt3EtTQSw7saQpBM2jGb25G6a5di1apMkD9dyj9/TmVri501PaDvSzRn9Wp2I62AvT6WnkL/Fp2uUiRen66Rl+TOJB1gIykS02w5SDB2/9DtLL15YchdcG2O7t8yuofdZE8KQB+xvQHk/VKQlMhZhViFZAYq1rWZbJ1awWqcjUd0OaVr6s0wSKchwXx76Mcf1fMzOWmBK+34nTsyMuPXPtSwjTHHybdT2a16nFcgFxZnlOp1mW7+s0x/IDneZZntfpCEtbp6MsP9RpgeVHOh1jeUELmnTfwZCLMOQCDpAwhKUDQ1hegiEsFQxhuQhDWBZhCMslGMLyYxjCchmGsLysZdXUU0nj2plYBmxCYGKOHrnMReVqKrlUQrtoVGpDnhJulVQUz6p/ZaBePPKGObAWSJfIml8xzpWPRuX41hUtbxo7V8Cx6m8fjvY58VLWi4U/Bf/V1lQlvWLNw5Or8BuGnmwnqjapeHRNl89VPbr+X1RUWAv0G0iFWCjKsmxwZyKEjzqdhmqglUPMbMw8tOt1y5qfw/03MUIWUP34NxQaC9yDTllJWe3grNXX27LcO4NyOBMsSTE38/pW+CIjs9J+kVnKno98HnAFjEpl2GoDrRW82ScxD5neJM8EcVtRNkja2M4EiQ0c84B5850EJmHqqg3kTuGGDfgFYW7BeSdconqjLIfuRezzKKT8W6fiRPaoaIzAs9kbYa/vQspvcQwkNPmlfgxUFaGpGDUV0DRSbqgGX8bZum1Cxg70Iyp2w7Ks4sPHFveVkm0ZhHykiNWjo5/WXqJOqtx+ZhSX752+BcEgNTF/e990cZDKu1rJMkdtA1O3GpVT15pD41WH6uZR9b3j7BM5a5puuiceel/TqtvBxVwssPZtDtJSJhfU9WGFDaLLxaVQ6mU0Se+4BxgWGNDvUIqN/6v62HyeK1WF0XEk307Ut9HnYAz8D9h/R/UD0Pdj6HINLs/3mhOfbvThbJmuohfrp+g3MGutuVm6BtzQdAPiIUetjrjKDXynBnF6pLkc6SHgY90V4gHAJoDF4BPdtYzmUwCj+Yw5PsDnzGHQZA6DLeYw2GbOGsAOcxjsMofBHnMYfMGcdYAvmcMgZA6DiDkMnjAnAHjKHAZfMYfB18xh8A1z7gN8yxwGMXMYJMxhsK/p1jDMLV7QXaC2QVWgA1NPWNzD4lBTZcj+jheG/b1BzP7BIKb+qOn2kPoTLwz1Z4OY+otBTP1V050h9TdeGOrvBjH1D4OY+ky/GMtlBr+MfJcKB5RdbD7n74n3D9vFQLkAAQAB//8AD3icrXsLcFzlleZ//v+++nb37dfte/VotVrdrW5JltuKpO6WJVluPyXbsmOEbGRjO4KVjWPZlsM4QIU4IYGlgCE2yxqKIQkJg2GreKQCTCZb1CZkiswjzOwOmSTATNVWTZLdDUwSMrVDsomD23vOf69assFAqgbk+773P4//nPOdc/5mwNjFl8WjosbaWblmxiOmIlTGYXzb11M7Z2ohAMbZCcZ5iG9prZl4whfwGju05xtttitUdwXYEUgkbQtWga5lC+XBaqJI285qpb8dVEc8Gnm5L5QM/f58yAlB399a7dD0mWAmdAqaMvBmKPKX9TdDwSjod9yhx03FAPcvI6Gk2lV33XoXUtKgL8C6Wa0WSzXbVjhg6JoqIPShCK0FOvOuE48K1V4B1VUQAVevugmP7Fz2CmTzW5/8+ZGP/+Kp7h/8oI4MuOZ7M5B9IvujH2Wf+PnCAjzn8ZK6AieMKRcvXnxWWSWCzGARlPcqtqs21WZzEBFgYIVDAYWzVJIrXBlH+hXGlWNM00GAJmYZ8sKBzTJFVZVppijqDFMVdTIWLa0o5JrdaHusPZGIG1IjFhQGK2mAZEe56kJnR1bTY7ZT7eivFGODBTdma3pHtlCNDVbwmgMHx/aO4R8ffeet5/ZCG6TfuV03IaSJU3oIzKsGO9+5PV+BwU5xqnOQx1aO8fW71yvD9fPn55/fA22PmsaFvfSgwZ8wzPiFvZ2DUMnzJ2hHVDMmHucPsSRrq7UQo4DMAV/AW7CANw/Zru3NIx20bBEpXwukArlxxOPReibaG63/SyQyiftzcBy3k1HuOHgjEgFHnkYfh4VodDJC4138Ff8hv5PlWbrWmm2O6grNEgGNCWGnbFtRm1Z04gzQPPWvkqMWF4eWU8DB267Df+gNe84bBvfRpfNI5Ny5yAmHDh5/PPLuByMlekDS9DsRR73nWHetwBShSO5PqCBQONO4E2wGlSvYZG6gMzeQ09SWFZC0tWION3oOVVXGTbGM+hrAzQj0O25yoN8R8YzzRsaZdzLwhpsGPEm783hAJ9+kq286eDX5pn/VydDjvk7i8EuchU21JJ3DNOqFzeABmywPcNXxhu/wB+3whrqwVw7Cn1j8vPfdDH6O7PR3fDV/Cb85wua/waSit309grZJHHOhHEQ9CA7zTGVCUb0ZvXzc1lrRe5Af+4An0aSL9op0IU9y6vRFtAYGKy7KJGFbQrdg2dXqGAwWilld0zUy9xLqd6A/zeFuy7gzYFmBOwOhZ6NNhZakm8YTI7S1pyM1mM032V26qevXGlzZ8+TKvROlB/BBkO9ACDalB7OZuBnuC5tRcAItpalENNOfhajVH1A2a1HjbHZ4N4r54oWLz4qPoe4jrMo2sonapm5QRQBQ3XycKVxwRRxjQuVCnWc6mrzOZ5FvBiraOmia5FubYRpok8n0ioRTKOQMNbWiszxYWAFZrQ1sB+dDJTFYghzyiBN3oB857ndIAha4Se/+YGUtjAkXXUO2xPE2eoe3TWPeMOXmzNi+j9w1HghvVbSAmu4c6nFac6MgbzXFU2baDr1241+98TfHtU/9t7df+MzU4msmfPYj06Wbw8Gqohda0/FkSyiyvtPGG/FsMKq1pLqmPvndkye/+y+08eYIHEJZpFmJra2Nop/VWuKcCwPvgRhnGlOFps6iIdAEmFVAKh53jblZyBU6nAFdbfX03tGwioZ9oGnEyDSWTQCyFzhoR+s/jdjgWLmc3L2K21zEmXCsM5aDm4g9Ny5v0PZVb+dY9Rcd/sl5eTiPj0nTaeiU+BhhW2qbuzJcUy2Nc2gCrjBkxWCqZiArGgOuwSzjAlDb5L91XfpvfYbpij6ZRIUWYoVcLqC2+UqNLddsMrekY3GZztVl2uQjpl4xjedIM+Uybc/r5viShuHgcgXuwQtpuoMHz8utCe/s8S+Y/7xMaYu2DX1yDrez3lp3cyyKdop+HLcLi878Uh9SKOSlj73cOIUFRVKVKHhaSS9JP452RCcYoJ3w85bz8Ckp9VN4xeZj9atpH4FnPCV4OtiDNIVYCrWwsbauK81VxUlaQnA+riFBisoUsiU0LbQpASCmmRAwg1MNJoH19uQ6WpriUV1jIQjphA5QjosiTfiy1tF+kPJKMTFYpAu6lkx40odnTv7VjYtC/QtTJyGH9HmMnKamGrcaqmaagRsMUwR9WeLmwsQREvIRevSvYa8uVFXo9Sc0w5A8/Rp5+jcxhXLuYAOIx/pbY+ggFp0FV8lNoLNAEQvyDkwBZR9T1ZC6xR0qFgsybix3DJcR7iIGwCsCHHQM0nYKVSBXQZPnqG7KDZiqrn8K524gpN9ghAx42k4GsvF3nohnA0kbnglkC9mrl7h4Db2TommKcVE1QOPRd97K5WJxsKO5nIjHbHtx/og3kK8iWys1he/EkKlqCbFOB6iKQp5Q5Yp6DB0AsjmPvHEFSGsoFraPaVpI2zLc2lmudErjJ/eeQwbKPoRBZulcwhwXYc6i1SdiEpiCF+KrFOIrAzKaHdhQ79tw4MAGuJv4rt8sQQu80jloGnnDfNVJBa+vn1WjSg1d8NHrg44FbTgdJ5+T77yy/gDI5wY7633yTbI7+CdyMDyEL2paDd0BvZjyfIYXH2/H+aqjDfXUisgnk3rFYMePoyZBegWanQpM5hKdlUSU1JnoQH2iG1d90IYADi0JPV2/oxMEeB7apm+aBngFw/ObMjzHzv7dgzyOh48fHZnmO9c8Wv+2RAGwHiP20UNnzx46mvYxyaMixDpZX22lQqQgRDqG4kYcMo92cpypAOo0Ti+iSYXJRGc5l8wvQhPfqpE0SYa7nDwkeQyh26OOlbecqVumoCwJ8+mDm+9/5T4eOyOt+4wk8WjavYTIG+7nD5Li2cWv8zGkMYoz51q2u3Y1JQSwfcumSn9JUxW0CZIWQ5isqKCo8zoGFPybx/lyHD2w4AaCBw7Ap1HIxAaHyZlr1tXG1owMt7h5Ox5QmxF4Iv6vDhaQoTFAYADuYIlnLa7b7RwtiOBDtVK1dbyCMXXxn5azOIIKfLFKaQP9K3HKIMYEQosvhkIWH23TQ9wIpCq9M4WxycnJsQIUYrEJ/bPGuOZohfHVzdmMaAmHm418c7DU3xdoyYPebFktPJtpHu7fefjw4R0VHiNTa06ZUTPe09a1sdTUVNrYtbo3nth11VW7tBa1d/U1a1t71rdG2u1IJNkWDYdbUs0pnnFT+OloWzISsdsjqVpvy9prqrNjed41POfPx2+J7TIXaWP5Wgf5bvToBEvpppQYOXPOJoda4gTQE6TsNK8sAvUSSHBFygfnfM9wL+8aK/Bddv0tZ8SufyKZ7ml7s20iCWdsPpPu4YVaXuur/2M6WX8riReTE21vtPUAnn4iyTxdf0vJ+/QM0pwsUL4D5BmUBQEeXpaU4W6RtExzN1In7eT9qHPpIoUdqAzSrdyHIPo1JNRps1uioCWJyIm2U/JG8oO4aZMXozF8b4RupRd5JJv7Nn8ZeUyxjlrakhJHcwO2gHMUDgGLR0MmS0GrIoMRWos0K81LUnPZYgmkw6sM8HtCoQTaT9y0Wu3f/MZuCYfijhMPhUVQNdL2hY8kMroS/8UvEqqeSfC/xzPV07k3vsqyrL+2ykYnhJjEz45OLIdbu4ncrbrWhImzltU7oqqaXAEdMWiHxPsSdvuF70K6/xf6FejjL13YBvFVP+UXrkwnyelZjBcltoLypQIoEmsoiDUw4C2QFS/I/J6yx5ybWOOqaMad0kJlKo+ElAdLqvRTMqOsgucuM64j3hgHU1H1mIkQ084Oje3eXT1lZwL1nwaD0BZMNfFTcHpv+sf7v6LEo4oZMlRbFNqH9tb60nEN0UkQ0mYawZNpR878eFuD1lWsl/Jb9J5iMbPlDKnkh3raBmS66U1M9Jm5rKUmMel1dKLOcxrVSgf5dJqU4o0g0pJyTlV37x4bytpCATOG8VUT4+m9cPoURiakE34ZMes/wbB0Roun+2p7h9oLSlwzQqZq2eIr+xe2/Rhp5QF8hHn5Hh/FfM9ibs32UrNG+l22ZbrnJ8N+fERAcD6YCp6nuPc2Aq/vWXiMfzKaye/BDfzTLPwe33MT8ns4P/y0uiLBdyZw3qRvNvGZegjF6H+escXvreOnkD7zm7IkADTbJEkU4sdw1jmwzpTj42smHLB82ijenjfx9YsXkccR+B5+I1azGtQk+4maTpnLlsBL75E7O1IPea+mzfPmUwQt00FJoG+nPxN/zruZzZprTljyx2GpXiHdYWBZtcINeB+2xVP16/GT9euDwf00TbqgK5gK7QvCmfp/wPn15WDa3BcM1l/Hy8F9wZQ31nf4Q2IjjrXyG+BnzXnMmqXiTuB5CLa01gINjvb8mesSTwHuSAEtzm8anp+uvwbdprkfhUs0wCNIxH6TP1l/vf6aPDThK0TXI5I+tjj+SX/8wIcaPxWX4y+CqsCiEIiAIzhsKrgfh+6qv+4L4RETPl6/zqMKukki9AA96OseZb3Zk7UKVKxZKt65tpR1J9p1sTGgP5Z4ah+KEzl73R/xEfr+I8H5fchlN/Jr0n0c3fSGkrz+vbhd5m2ZWltThDeKUaKh3WTZXWauS+WomBdMkjGvOCRuT9YfcIZxk0x24/5cT3q8redxe8TpTsLn03b9LIaFo/I0eQ7uxtjQm6rffI4elnTcJfbwX/qRFyG+Vw+SaJdyFIpugk0WXCcnaZFo1323viNAWHZPvk1+ugfjTf2sbcPR5LDT442bhwPj6Z5z9qi9wr8B85Ji51yXb3tISxlpSUtaZEYnFX8ZbHI6C8vk4ll2h5/YdRQbM0CUbSmXHsd5rH5zWz7fBnc/5iA1NLANwyQZ2+5JjiYfQ4mle+BxJA1prT9g+770dv4zTz9RnTPp+JlY4DJKoroOucmyT4fnsGIeFC3H9EtmB+qnGyP6413tPvs4BhIwipskDKakeIg+KKTgbl92JBkkHn1J3c8t+9ia2vBKhMFkGBJtEjrGDIzKE1SeAgTJiDAVRYpKmSGwMlksJor5gUWgjKlXYS0gurS4neaYflXJnaWBUjDKNAVhkWoF1WhHz7uJ2PapE8NHJkulySPD62/qVmLapMq10a997JqvnphQarc8dO3UQ2smYr38pfOWszK6fTs+eBKfHy4j8t2uWNrWnbDx5CNfe+TkxrHVE/EEW4ynxM9H2FhtpAeE2tnGFUH1J4xXChxD5hACLNXbLgOA3WU353rI37Y44SipbwdxwED/mEC0rOmuIzmlGkw7SBzNxZ6NN3519+zXRhV1Uosp3TdtGD68s4eXJo8uzHVtjyXc85gC9MYmRh+euuaRk+vhAG43Tm3RLGW7Clp52Oesq3N7dKVjnW9KxCdWjyFvi/nUs+Ja5CnPxtn+2t4NnVwLrELw76JqDMz1MacMGJoR0I5RVsA1lR/DLEdonLJLQWnOMcSamKlrszLnWWZ3mzcVOjsrnYWynTfVNmQ6aQFxrWtL9SQtgjqsojbxf5lp+qquSF1rVGyk02qZZEEKRkPdlv9ff3LVQ6MTFMas8xSft3fNVbd+vqg1KaF5w7RwBsirUye24UVXDS3oIcj/nz+56mF6qQlUAQ++gGoNytcxFG7P98DWMXMoHIL/6l/Z7p1riv8ko2oiyiru129WsSrmUjO1XdtWc0Pr7miOoWOV9YUQ07WQPmsCisWYDge5puAUAI3NIk6EQACmaQ+BGRaAwOSemV1TH90+vnlDrZBNFOi/nEUlLL96lYx5VZLqB5zDQLFQzGm6KuUX89L6YqxRuaPsCwXYTlJE1EVJt9ycWTo8bereoW7Wv38ewfOzmgI/N42Kn53LatjTxUCv85zbEyg+Y5hTcDddq99M2ysc8/51lABfjZ++8KvSxvUlnpCj7U+mIG3vR8yhXSbXEbaB3cDmatdds4lrhi9Z8hskNo2hkI+RQHWN6fMIUwKGFZiNhDmCNq6BoR1gejCoTzNdD86woB6cPDh33YFr91w99dHJLePr1tp525NylKZkzJtthLplN+ADzhOxjpiN1trRPwb/vhKfqIcMg8Mr3DDqd38o4cM36y9KWa+Tsn7v4/ocj134Vcg2TZsf/ABFKH4tYwrtObZYYxoF3QiQC+PjATwUho5+W8MkQlOOqUDxnlMNjZpsfB8zjJCxZe2afKeTjXeuboqT2XcOlsACB6XROFhWch7AeNy/VsZfx4fO5Aj8EjTVRPjLdtrmTS1NX7Azce6kmjZnnHf+1iuBiG0duzsmQTiZPzfjEoTGAqZ7xqt/nmmai8gXOWb0/sG9z8vyyPNOZjKDf9DlRgmQR93keVlHOU/9RTkfH8W8ieTQzWpsc21DGRM0Xw4soAUWDEDPtMB0oS9I5qeXC0PhMySPyTWjuYFctn9JEgWLp6FSXdz71TeSgzuQBmnXVHPXGqWhIhXkF+H2lQXxVqiSO5OthN9CQQSazmBOhdycwSgoZRJvQ28Yz8SVltDiwd3PUxMLN9De1dWehinH5783RvA9xhpyoHgnWAfGvE3sqtqOFT25rGIoMB4GBa0NAaepg2KYyiwVijQqFKGtopEeUFFYgQCboj0jZ8cCk7U1Q2W3MBBLjMRi0SCKxO0od6gD6Muon6Q35JGLDZS9DEpfLNZTA4aqrmrD0rwHCAO8Cs/Ur4a3J0Lql9WU4RfBJiYySfg+cviqaczLvipt59LuhbjXflPdSuRLUUd/9VV422jRv6SF/NbehYrcQ1p2AZ6jd80L5+kSRwE3WV+OVGTs9GvnU6yLDbJsrZ2aE+iijskqPtuHgTAktgz0r+xtaUaslZRRH6FKlRJrBwO9bK+lef8YXipg7j8GSJjM+GRPmSApRv6n//T4VrH3qqbRaNxoqoxSNMfwD6MV18yPulftrX+xZ7gXeka7vMCPgf2aQ8+N4bPuaKz7lg2LIGjjTT3x4T4jvubPYKL+cFtPTxscwm0DA+yVNaMjbFNt/cE9k+sUpoxgas8Gu1qjhG7GqUu+oAFel8B2gTDcgt+54If2XXv1VVsmVvRkM4m4TnnrYCGLtt5foc4F2rWO/NrIbxENvBHUy0WJBYqEg8hbyklAxoATvupfHMCZ3wAHaASEAFz/Y7pUPh+ZumWK7z65G1KGftgMJro0NbIzrOvbm1sCuhL9tBGKtrof1aLaZkdRjS4zYhzSDTDVw4bldnrPGtubWgKGiH0adR1JuR9VI/qErSgB72HMk0emp2+anr6F7kfTydZ+zdKSO0EdDRuTqaip3xAIjapaLa1aWqg/kmqNQEiXzza3ZFbqId3euezR4Iiqbkj5j7ZEIeTX7X4n9vLvLmKL2mAXILVUp0WPoyLCVJVGQ+/yNlGhjP8PNLq4y9vNy9rPrn+eW36OaPmdX0nTF7EIpu9XPlvW1XMgOiHbSHIL1ji1nsbpBdbAyXtlTRwjSHuCqyJvkjfAVEiMe317oeLEURlNKa/CI7tfVLxLp5qb4tFwUFVYJ3R6/STHqy1Xi1R9RLvvd6lSPIba14rZoo6zwa3w/7L18OGzRwC+N7B52+HD2zYPfA8OP3iIH9kyjkd4Fdwj9x85skUPzfXhQd9cSN96mB+97yjgoYUXvZ7kxYu/UW7mL7Eo+rwKK9byTKWsSWWz6N8VBaZxB5ShgDJZHerscm0J6L1at2fNGPH4CqQNZ+gAGTeaPZVNBB52IJ7nt/uI3N/B0707Do+8vmEH37rpdTLX8eEDd47Xr564Y3aIj+67azM8Q4dwYHjpHbJoOu1/8OkH++lk4s59Y2Lo+tsevG1ukA/N3uHb9f9TbkFebNRET61I/GEuOEtdCkxKcdfISpPptmSn01kdVNF4Y4NjHF1rWnh0cxWZKImsJdKcKPPIkZR5RIoYkcJ7dh665dDOHqV/4jgc2ILXkYz77zgwypGsH1zKst/L+ir6nJVsPdtR2zaC4aQTZC9CR4p0jigDQ6gmexJcUeeXdbS0xY7WslzDdpPF8uryAPX0L+tqoVNFD5QrFi7rbKGXwYnkJGCpwra4XMZe1th6JZcOCL0VgV445HepqL+l5jVdKMHP1VeH89a/WtYaK2/9Z/g4noyFYduzjf6WpSS0FIKDRovrC4aaQ9ZArQ9b1r/K58P0Yhi/4Msl4WPhFbUuzCTBb1OitsjmCVsAn+Qs3eokTJ1FeEQlI1nGXNlfnbS8tcc/sYz4wU8vsbd+lr/UII5u7mncOYBJ+WKc+5jsETe/L03AXCfmN4IlTVnCOYiVSxyWr5h45up7d/Lpu568c7ey4zRcu6yjzk9P3Xvu3im5qb9yaf98ab2AwZIsy0Zrq6nXxkG22zi121ScGiC71IoiZwcZqlAmzUCmvaU5GgkkzaQfoNCjlKimWnxvGhtR5b4r0roYFX59BZLFsvVB5NMRIVAGQ65bJoBsRuaFbLJM/0n3nZCLlZaWYKj+efWy88WezKv+yiG5dKnN23mX2uUJbi5bY+Rc4XgxBrHXGnlYb637gwLPEuXVBmD1ViiIyzgRfl5f9NddvfoB9NDxw0clWD9KV0FbdhMMjzfc+H7uJXEG8fo6Ns4O1q5fU+KCCq16PhXG3JuJcczFw6GwEaLSBXkQwNwF4DgLs1AgHDqA2FToAXEgCDpj+jTudDaDgUmnGsaG9bWx1UOVctJGzBlDf2HJWgZyh1HHkeV53RK5WC6Gc8fr45AzKSByxwlWHShTsxydSgfVLhALUZsXOiS8w0TlVOdJ006bC4ZayA43j7cN9WCqeCgYDTvGJzKnKG0Jn7ou6KSC18Frs8FUk2Jch1frv65/kWLdMMbf2fWfDKac4HFdaYpb8HY9ZDXZhnEylEgHP7t2L6YMcO46M22b111HA113zoFBDJQUpy/WLx6B36K+MxQdmlHBKerm0BIJKqUu68GgoLY0VSpexdChJiDC1WpC9qwK1cQYpS7U0BW0JAzeMrX6P+hRI2Dy4z/hqqmb4gS3jG8GLT77P1Ue5E4wfOFTFoioAS8NYVYZhv9umJapaPV6hct6wHdkHiowcqVYnvUivt5Qa+3vK/X2dBXy2Uy6pclBE4pR4XkwxWHTtq93vH+tv0l2U6pFvbNRePWrv51uBFbBWmgHbw/upXv+0LnRc1AxL/RjLrVgmvx/yP0Fq1KJxarV2A+PHct2HDvWwbvxJIYX60/THfzHrcdGH7shQm/iC2l6E/fXRumtaPU/ybeyx+p34UkVL0LJv9PAUHOomzL1w8q9uZaYoV3SIOoujHBKKii60eKMxhJHXUMgTQW0InVqqErq22AbYN6BHOMkFCMtlpWLDDc/0NM23tYLZ1uGMX5ZrWfPtkQj+chQ61lZiH+gZSiai0Sbz4JhDbeswXd2PSVr8E/twqtr8KXdu690Q2KpI6jHMMuhBjdRdbG9iQslEae6YVhDV7gBdOiHgK4iKtSERkv4yOpAP8ZMpimmNqtSRuUFG50FDD2AeaYRNrasGS0P2LTwuGDncpRJNtZ5Fpev85SVhMY6T3ewBJrtjAFIs8XZi95eSXOXLJkW75wKaXmE7afkst1TsjBDJxP3v3I//kG6Z9R+ce7WnfcfrvHRo6fPnT46CpteTMJZ7yXKMb2XTlHieMpspgUYLz+k3UsJV/LFTWNH7vvT08eHlfWHHtx+69yLSbZMRhHWhDn2SG0oYCC3qE/B0qAKuZqPg+b5XkErlwWmYkKlMkNY2eLmUAqF3OJinmKjrPIhuK1/W/IJ6z8kh5K1D2aK+/UTWqOzkz1fC4xVOgKKKqgjZqKV9nhTGGOgUGnZjiK4Mq8jJFKOMwJ0UxSLdlO/Ymvrtq8H3/UG+nBNcG0e7Vh79xt/yOf37KklDMPYaeyc3LZ1y8hwT671KoP8BApooL9agOqYUm2FATeRptTcdeQGxexmC3pWyw2u5ZSr4l9xsLCKW+DaaeqxVskXZql+XdTggY9NDrcHk331MoTzqZSj3fGlCe3GxJQT6IsGjeBkQOGQO53v+VKSb9E1EVMQ5vKs2/R7axiimWAmiVCh4/MZ1eYrecvvMWx9oa71KppmNkVhBs6G6m+veHkw8amOFi0QFY4pTI7RrikRxSd1jgBaCeytDEHmYSsUN/HTEEyqQVQ6ppY4937ER/nPmMXaWK6W8TvQy1cj+s28wcIlS70LHqQsSoS5rB18abP70ubwv0VMqrRhJALnb2SJXZ76vg7pAPc9++oF2+s8XzLyZUMt/3ajhy35encPGy4n+lIy4Xvvou1JERMJFmTa8zqHldSwlaBa9k6VC63heDzM/3cYttfndDMiKlbIwCN7eV2F8FS61toUNZhCzHltUoKChwg/yah6WVnr8jIXJer+ultoizj14CWn/GfvvEU5uIjTdtnx8nw86K1TlzWF5QsXBhYXGlw+3rLk/5IB/G8+gzZuYUagPa8ByoUaWfiRIuA35I4CrJOMVariLtOCaKD+Ryq3gvWTwSDci1AAfVtQi7zzsmWE4F5Vq/+RPKDe8714vX5SVSVGuXjxa2K/iCyN42qyOkbLkXwt6FIjmt5sRsHC11VB2yANZQl1HL+GWjFC9Em4Vx7Q2oKTeB2+oKkeL3xEkBU015zWlri4VEBrpICIlwZ7Eso2mgSVKs8GLeJN5YsLnmn7Lh7/45KS6ncSg5I/Por8NcaWi7UW27Te2JeyTGPqPg3VS9j2CzJyeznjn1qaGXCrpsq8ro655n7+1zi3WwkBRkGuRl5e3eMyi6L0TvDJcnYwTnM14fWG5Xyh5nXVLya56BmNJRUi25oYoiGRJBGXdaO+Rb1Y9R861mlZYzodsf21K8/wZ1mC8I75Hr9viTsF+fsW5BzxTSO1IFQNz6DJvnC/lPv9L6Ab4KcvfJU6gC94y9NfMP31s7i5XY5RIn6LJqKRxjAKDuOVppiQA65ycUhaEvVeQya8dVuF6uCYKClVFADVGd5FyGt9RTWAAgg50ahiNFm2YkcCarHv3QTW/6Jna0TY0VA0FEpnMkbciKJ0RGSrrMN/XzzKfy7p3saOsq21cUl7FVQ2Dboqxg8D38S4hnxooL2bGRU1qurqAtP1Q1M7xzd3Sd4MKlx9aN7cxtWq/1OQAi25ohrK0s0ilVHwbgmKVNGWD1T/IMmcmd2u68h5MhPsLpW6Mf7ZEUPfceC+0zfhdXy9uTm5cQffujnZrMQFzmZdv+n0HyDOnl33Z4RjOcFoIL338N50IIpBxBEd9+2+7fV+vGGHQ5Y18NCTDw1EwkITYRu/JwZe9fPMI+IfxFUsyjbSqvKhAcwt168pdedsTBbTzZxTnRzRxQyV/if8uggP8y2VcpqWw7iyTmgJOy3GuEu5oK35P5xC0L6GZFag308hopD9/6r3KyoE7rKG5Tqi3D9z8s6TM/3+7mEeeCxiPDanxdWDjxmRxwKIeebmVFVePajGtTl5VaWLcGDdLdMVpbTvxD0n9pWUyvQtew1RfioQFOU/1vU/Lotg4KmyMEz9nnuM2OINTVu8ETPuuUeXPuNZUcFYEmd9rFRbYSxfVUjLiN9dFerqyvd2yKWFBEEB548Fup3m1PWnBQHUERnjyKYur0O1v1pBfvl30u2Hnj4EwydOw/CBOyd23vd4+YefpuUbvHb84elmO9HXD1P3Tq1f48YM5VZ17msH5/d1fPtmWQndeOwTd1EnZNeXbtwsoBRbcbJ29T3T0GbGDO+3J95aen6KxViWDVCHL8i5wsPAxPLfE1FDb55RmQnmCYgrEoijOyX+6KeDoE66Tt5ONjkSgheKBA9LqL6qpqchU0E7QaSYtJ3+irSVimrrmpLJU3ej0gsK6vTRXbdlEXtnb9u17Z9B+Un9m9Hg5rmoE93YF4zCPwZ31H9b/6f6b3cEgzvAgAIYO4IwfMe64Q03nOX3fXzD8Lo7brzrLtiCz85tCkajwb6N0b9LJD738MOfSxTs2x7mj3yGsEgjzzBYB9Xw2hGCYAZOzYWG2uR6nFlvxlJeEZfO732ziNsX84be4ffMGz7/gRmQb1dyTX8Q/dtArU8Hb8Wybmgod53NBlQOilxbg9mPCIstK3sTAzE7O5BMJuTKkvJgwfulBskXM0CBMymXLQrpkSoDMVmJ6aA2QjGG4SJkRk38g5sd61dtYGoQ4St+jHY+U23r4aVWOEjtseoMnDgvfwCEm2+hp6r/X91AK4zYkU3HMVEaxnR3qBfqPzn+/wHPnsOreJxjYGRgYABi1vIsoXh+m68M3MwvgCIMt5YoxkDp2P9f/2exVDAHAbkcDEwgUQAz1Qu/AHicY2BkYGAO+p/FwMBS9v/r/68sFQxAERQQDACh8QbyeJxdT0sVwzAMy49AkAxAkbT3UQiAITGAISmAYQiA9th4ttUs7Q568UeSlVidiwSkB3PUPg+ESd6ZD/+8v7HyrtzwghY89ZB6BcyrYqc6RZhw48YhaA1Wc/v1PQtdeXJ/HppUmFM597nvBVK7D+Z+E8/uQZLBgDyaz3Llvxx02S3c/Hv813JrznryZP4F+6lSfQAAAAAAAAAAUAC2ATABaAGyAfoCJAKwAzYDmgQSBFwExgUyBbQF/AZOBvwHRAe2B/YISgigCPIJGglCCWQJignACgAKQAp2CroLAAtGC4oL8gxcDPINng5iDuYPag/6EF4RIBGGEeQSShKYEyQTbhOyFAoUYhS+FVoVphYoFooXHBeGGFoYnhjGGOwZChlOGXgZrBneGhwaWhqgGtIbLhvyHHQc2B1QHZ4d/wABAAAAUwBtAAYAAAAAAAIAIAAwAHMAAAB2C3AAAAAAeJx1kN9q2zAUh39q0441YxcbjN3tXJWWEcc1lEGvWkLbXZeSu8JUV/6T2VKQlY48w95ifYa9zt6jd/vFESUUYiP5O5/O8ZEE4AP+QWH9nHKsWeEdozXv4A0uIu/Sf488IN9G3sMQPyLv0/+MfICv+BV5iI/4wz+owVtGM/yNrPBZfYm8g/fqW+Rd+svIA/Jd5D18UovI+/S/Ix9gqp4iD3GoniduvvR1WQU5mhxLlmap3C/FUdVWN6IXoXK+k3MpnA2maVySuza0ZlToUZ07292YctFov6k2eWp8VzsrJ0m6qa+NNV4H87Dq1j2WWQiFFN61chX7yNy7mclDUoUwPxuPN/tjAoc5lvCoUaJCgOCI9pjfDGk/BPfMEGaus2pYaDQ0GgtWVP1Kx/ico2BkaQ0zGnKCnHNL09KNuK451721rLqhLfmfht5vzdrmp7Sr3nUfC07YL92afU1r+wrd7/Dh5WwdHrmLjDawanUK3+9acPXqPML7Wq3NaHL6pL+1QHuGMd8t5/8PvPGO3QAAAHicbZLnlpswEIV9DRiwvZtseu89Ib333vvmBWRZYMVC0pHEEufpg8BO/kTncOfTaLgMOtPr97o17P1/baKPACEiDBAjQYohRhhjDevYhu3YwA7sxC7sxh7sxT7sxwEcxCEcxhEcxTEcxwmcxCmcxhmcxTmcxwVcxCVkuIwruIpruI4buIlbuI07uIt7uI8HeIhHeIwneIpneI4XeIlXeI03eIt3eI8P+IhP+Iwv+Ipv+I5N/OiF1hEz9JKxUrtFrDl1lWF9NR9QIikToRaVjUouKxvOmNBjLxnlhgo2DbnM1djLKrNGnGPScSUzItzGv93yPP2bSQSX84z9cqFQdJ56yZRmMhW8mLlJJSaBI0XYPDaZKDUviZmvr6DrNjJMi0WcK1MTM02mqpbZlJtEsNx5SI238jSodJtoS7qv+BpPw67IY9xU+dg5TXjROTWwdGrIOzWhT+uA0jolxqjaZrSOnCF2Nmq16651EYpMm1fakAul9SJQeR5QVYQlk1VkZ8SwoVNFIVjWnKQrlBGdMToftdoZjrs77DajqXKrS02YEFxbbtdWkG0x44JJVUS5aBqKSlJwmhDrmOF2Hv9Wqsy4TNqoKhfmSrrQKuNSL5nvPG6p0s0AkEWkSWVZMy1Kx3ljk03qLuZ14lTmB8gNGmByGrGfjLrhlhJV2f7SaIneNF1ypQNbybBUSgZswQaWEUNngeay1/sD4l/60HicY/DewXAiKGIjI2Nf5AbGnRwMHAzJBRsZWJ02MTAyaIEYm7mYGDkgLD4GMIvNaRfTAaA0J5DN7rSLwQHCZmZw2ajC2BEYscGhI2Ijc4rLRjUQbxdHAwMji0NHckgESEkkEGzmYWLk0drB+L91A0vvRiYGFwAMdiP0AAA=') format('woff');\n}\n</style>\n<style id=\"style-core\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\nhtml {\n\t/*\n\t\tWe define the base font size and line height here as they affect the layout\n\t\tof the base page elements (i.e. `#ui-bar`, `#ui-dialog`, and `#story`).\n\t*/\n\tfont: 16px/1 Helmet, Freesans, sans-serif;\n}\n\n/* Story data styling. */\n#store-area, tw-storydata {\n\tdisplay: none !important;\n\tz-index: 0;\n}\n\n/* Special no transition styling. */\n.no-transition {\n\t-webkit-transition: none !important;\n\t-o-transition: none !important;\n\ttransition: none !important;\n}\n\n\n/*\n\tFullscreen appearance styles.\n*/\n*:-webkit-full-screen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\n*:-ms-fullscreen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\n*:fullscreen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\nbody::-ms-backdrop { /* Prevent IE 11 from hiding the `body` element's background. */\n\tbackground: none;\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n*:focus {\n\toutline: thin dotted;\n}\n*:disabled {\n\tcursor: not-allowed !important;\n}\nbody {\n\tcolor: #eee;\n\tbackground-color: #111;\n\toverflow: auto;\n}\na {\n\tcursor: pointer;\n\tcolor: #68d;\n\ttext-decoration: none;\n\t-webkit-transition-duration: 200ms;\n\t     -o-transition-duration: 200ms;\n\t        transition-duration: 200ms;\n}\na:hover {\n\tcolor: #8af;\n\ttext-decoration: underline;\n}\na.link-broken {\n\tcolor: #c22;\n}\na.link-broken:hover {\n\tcolor: #e44;\n}\na[disabled], span.link-disabled {\n\tcolor: #aaa;\n\tcursor: not-allowed !important;\n\t/*\n\t\tNOTE: Do not use `pointer-events` here as it disables\n\t\tthe display of a cursor in some browsers.\n\n\t\tpointer-events: none;\n\t*/\n\ttext-decoration: none;\n}\narea {\n\tcursor: pointer;\n}\nbutton {\n\tcursor: pointer;\n\tcolor: #eee;\n\tbackground-color: #35a;\n\tborder: 1px solid #57c;\n\tline-height: normal;\n\tpadding: 0.4em;\n\t-webkit-transition-duration: 200ms;\n\t     -o-transition-duration: 200ms;\n\t        transition-duration: 200ms;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\nbutton:hover {\n\tbackground-color: #57c;\n\tborder-color: #79e;\n}\nbutton:disabled {\n\tbackground-color: #444;\n\tborder: 1px solid #666;\n}\ninput, select, textarea {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tpadding: 0.4em;\n}\nselect {\n\tpadding: 0.34em 0.4em;\n}\ninput[type=\"text\"] {\n\tmin-width: 18em;\n}\ntextarea {\n\tmin-width: 30em;\n\tresize: vertical;\n}\ninput[type=\"checkbox\"], input[type=\"file\"], input[type=\"radio\"], select {\n\tcursor: pointer;\n}\n/* BEGIN: input[type=\"range\"] */\ninput[type=\"range\"] {\n\t-webkit-appearance: none;\n\tmin-height: 1.2em;\n}\ninput[type=\"range\"]:focus {\n\toutline: none;\n}\ninput[type=\"range\"]::-webkit-slider-runnable-track {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: 100%;\n}\ninput[type=\"range\"]::-webkit-slider-thumb {\n\t-webkit-appearance: none;\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 18px;\n\t/*\n\t\tNOTE: Ideally, `margin-top` should be `0` for Edge/Spartan (ca. v17), but\n\t\treal WebKit/Blink-based browsers need it.  Since there's more of them and\n\t\tEdge is co-opting the prefix anyway, we cater to them.  Edge will simply\n\t\thave to look ever so slightly off.\n\t*/\n\tmargin-top: -5px;\n\twidth: 33px;\n}\ninput[type=\"range\"]:focus::-webkit-slider-runnable-track {\n\tbackground: #222;\n}\ninput[type=\"range\"]::-moz-range-track {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: 100%;\n}\ninput[type=\"range\"]::-moz-range-thumb {\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 18px;\n\twidth: 33px;\n}\ninput[type=\"range\"]::-ms-track {\n\tbackground: transparent;\n\tborder-color: transparent;\n\tcolor: transparent;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: calc(100% - 1px);\n}\ninput[type=\"range\"]::-ms-fill-lower {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n}\ninput[type=\"range\"]::-ms-fill-upper {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n}\ninput[type=\"range\"]::-ms-thumb {\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 16px;\n\twidth: 33px;\n}\n/* END: input[type=\"range\"] */\ninput:not(:disabled):focus, select:not(:disabled):focus, textarea:not(:disabled):focus,\ninput:not(:disabled):hover, select:not(:disabled):hover, textarea:not(:disabled):hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\nhr {\n\tdisplay: block;\n\theight: 1px;\n\tborder: none;\n\tborder-top: 1px solid #eee;\n\tmargin: 1em 0;\n\tpadding: 0;\n}\naudio, canvas, progress, video {\n\tmax-width: 100%;\n\tvertical-align: middle;\n}\n\n.error-view {\n\tbackground-color: #511;\n\tborder-left: 0.5em solid #c22;\n\tdisplay: inline-block;\n\tmargin: 0.1em;\n\tmax-width: 100%;\n\tpadding: 0 0.25em;\n\tposition: relative;\n}\n.error-view > .error-toggle {\n\tbackground-color: transparent;\n\tborder: none;\n\tline-height: inherit;\n\tleft: 0;\n\tpadding: 0;\n\tposition: absolute;\n\ttop: 0;\n\twidth: 1.75em;\n}\n.error-view > .error {\n\tdisplay: inline-block;\n\tmargin-left: 0.25em;\n}\n.error-view > .error-toggle + .error {\n\tmargin-left: 1.5em;\n}\n.error-view > .error-source[hidden] {\n\tdisplay: none;\n}\n.error-view > .error-source:not([hidden]) {\n\tbackground-color: rgba(0, 0, 0, 0.2);\n\tdisplay: block;\n\tmargin: 0 0 0.25em;\n\toverflow-x: auto;\n\tpadding: 0.25em;\n}\n\n.highlight, .marked {\n\tcolor: yellow;\n\tfont-weight: bold;\n\tfont-style: italic;\n}\n.nobr {\n\twhite-space: nowrap;\n}\n\n[data-icon]:before,\n[data-icon-before]:before,\n[data-icon-after]:after,\n.error-view > .error-toggle:before,\n.error-view > .error:before,\na.link-external:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n[data-icon]:before {\n\tcontent: attr(data-icon);\n}\n[data-icon-before]:before {\n\tcontent: attr(data-icon-before) \"\\00a0\";\n}\n[data-icon-after]:after {\n\tcontent: \"\\00a0\" attr(data-icon-after);\n}\n.error-view > .error-toggle:before {\n\tcontent: \"\\e81a\";\n}\n.error-view > .error-toggle.enabled:before {\n\tcontent: \"\\e818\";\n}\n.error-view > .error:before {\n\tcontent: \"\\e80d\\00a0\\00a0\";\n}\na.link-external:after {\n\tcontent: \"\\00a0\\e80e\";\n}\n</style>\n<style id=\"style-core-display\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-display.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\n#story {\n\tz-index: 10;\n\tmargin: 2.5em;\n}\n@media screen and (max-width: 1136px) {\n\t#story {\n\t\tmargin-right: 1.5em;\n\t}\n}\n#passages {\n\tmax-width: 54em;\n\tmargin: 0 auto;\n}\n</style>\n<style id=\"style-core-passage\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-passage.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault appearance styles.\n*/\n.passage {\n\tline-height: 1.75;\n\ttext-align: left;\n\t-webkit-transition: opacity 400ms ease-in;\n\t-o-transition: opacity 400ms ease-in;\n\ttransition: opacity 400ms ease-in;\n}\n.passage-in {\n\topacity: 0;\n}\n.passage ul, .passage ol {\n\tmargin-left: 0.5em;\n\tpadding-left: 1.5em;\n}\n.passage table {\n\tmargin: 1em 0;\n\tborder-collapse: collapse;\n\tfont-size: 100%;\n}\n.passage tr, .passage th, .passage td, .passage caption {\n\tpadding: 3px;\n}\n</style>\n<style id=\"style-core-macro\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-macro.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault appearance styles.\n*/\n.macro-linkappend-insert,\n.macro-linkprepend-insert,\n.macro-linkreplace-insert,\n.macro-append-insert,\n.macro-prepend-insert,\n.macro-replace-insert,\n.macro-repeat-insert,\n.macro-timed-insert {\n\t-webkit-transition: opacity 400ms ease-in;\n\t-o-transition: opacity 400ms ease-in;\n\ttransition: opacity 400ms ease-in;\n}\n.macro-linkappend-in,\n.macro-linkprepend-in,\n.macro-linkreplace-in,\n.macro-append-in,\n.macro-prepend-in,\n.macro-replace-in,\n.macro-repeat-in,\n.macro-timed-in {\n\topacity: 0;\n}\n</style>\n<style id=\"style-ui-dialog\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-dialog.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tPatches to the core styles.\n*/\nhtml[data-dialog] body {\n\toverflow: hidden;\n}\n\n\n/*\n\tDefault structural styles.\n*/\n#ui-overlay.open {\n\tvisibility: visible;\n\t-webkit-transition: opacity 200ms ease-in;\n\t-o-transition: opacity 200ms ease-in;\n\ttransition: opacity 200ms ease-in;\n}\n#ui-overlay:not(.open) {\n\t-webkit-transition: visibility 200ms step-end, opacity 200ms ease-in;\n\t-o-transition: visibility 200ms step-end, opacity 200ms ease-in;\n\ttransition: visibility 200ms step-end, opacity 200ms ease-in;\n}\n#ui-overlay {\n\tvisibility: hidden;\n\topacity: 0;\n\tz-index: 100000;\n\tposition: fixed;\n\t/*\n\ttop: -50vh;\n\tleft: -50vw;\n\theight: 200vh;\n\twidth: 200vw;\n\t*/\n\ttop: -50%;\n\tleft: -50%;\n\theight: 200%;\n\twidth: 200%;\n}\n#ui-dialog.open {\n\tdisplay: block;\n\t-webkit-transition: opacity 200ms ease-in;\n\t-o-transition: opacity 200ms ease-in;\n\ttransition: opacity 200ms ease-in;\n}\n/*\n\tWe do not animate `#ui-dialog:not(.open)` for various reasons.  Chief among\n\tthem, however, is so that the dialog isn't in the middle of its animation\n\twhen other page updates happen.\n\n\te.g. The restoration of `overflow` on `body` would cause the still animating\n\t     dialog to jump around a little if a scrollbar were to pop in.\n\n\t     Any dialog action which performs a task which has its own animations\n\t     (e.g. passage display) or causes the page to reload in addition to\n\t     closing the dialog could cause display shenanigans.\n*/\n#ui-dialog {\n\tdisplay: none;\n\topacity: 0;\n\tz-index: 100100;\n\tposition: fixed;\n\ttop: 50px;\n\tmargin: 0;\n\tpadding: 0;\n}\n#ui-dialog > * {\n\t-webkit-box-sizing: border-box;\n\t        box-sizing: border-box;\n}\n#ui-dialog-titlebar {\n\tposition: relative;\n}\n#ui-dialog-close {\n\tdisplay: block;\n\tposition: absolute;\n\tright: 0;\n\ttop: 0;\n\twhite-space: nowrap;\n}\n#ui-dialog-body {\n\toverflow: auto;\n\tmin-width: 280px;\n\theight: 92%; /* fallback for browsers without support for calc() */\n\theight: calc(100% - 2.1em); /* parent - title(2.1em) */\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n#ui-overlay {\n\tbackground-color: #000;\n}\n#ui-overlay.open {\n\topacity: 0.8;\n}\n#ui-dialog {\n\tmax-width: 66em;\n}\n#ui-dialog.open {\n\topacity: 1;\n}\n#ui-dialog-titlebar {\n\tbackground-color: #444;\n\tmin-height: 24px;\n}\n#ui-dialog-title {\n\tmargin: 0;\n\tpadding: 0.2em 3.5em 0.2em 0.5em;\n\tfont-size: 1.5em;\n\ttext-align: center;\n\ttext-transform: uppercase;\n}\n#ui-dialog-close {\n\tcursor: pointer;\n\tfont-size: 120%;\n\tmargin: 0;\n\tpadding: 0;\n\twidth: 3.6em;\n\theight: 92%;\n\tbackground-color: transparent;\n\tborder: 1px solid transparent;\n\t-webkit-transition-duration: 200ms;\n\t     -o-transition-duration: 200ms;\n\t        transition-duration: 200ms;\n}\n#ui-dialog-close:hover {\n\tbackground-color: #b44;\n\tborder-color: #d66;\n}\n#ui-dialog-body {\n\tbackground-color: #111;\n\tborder: 1px solid #444;\n\ttext-align: left;\n\tline-height: 1.5;\n\tpadding: 1em;\n}\n#ui-dialog-body > *:first-child {\n\tmargin-top: 0;\n}\n#ui-dialog-body hr {\n\tbackground-color: #444;\n}\n\n/* Default dialog button bar styling. */\n#ui-dialog-body ul.buttons {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n#ui-dialog-body ul.buttons li {\n\tdisplay: inline-block;\n\tmargin: 0;\n\tpadding: 0.4em 0.4em 0 0;\n}\n#ui-dialog-body ul.buttons > li + li > button {\n\tmargin-left: 1em;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-dialog-close {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-dialog-close {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n</style>\n<style id=\"style-ui\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\n/* Settings dialog styling. */\n#ui-dialog-body.settings [id|=\"setting-body\"] > div:first-child {\n\tdisplay: table;\n\twidth: 100%;\n}\n#ui-dialog-body.settings [id|=\"setting-label\"] {\n\tdisplay: table-cell;\n\tpadding: 0.4em 2em 0.4em 0;\n}\n#ui-dialog-body.settings [id|=\"setting-label\"] + div {\n\tdisplay: table-cell;\n\tmin-width: 8em;\n\ttext-align: right;\n\tvertical-align: middle;\n\twhite-space: nowrap;\n}\n\n\n/*\n\tBuilt-in dialog appearance styles.\n*/\n/* List-based dialog styling (primarily for the Jumpto & Share dialogs). */\n#ui-dialog-body.list {\n\tpadding: 0;\n}\n#ui-dialog-body.list ul {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n\tborder: 1px solid transparent;\n}\n#ui-dialog-body.list li {\n\tmargin: 0;\n}\n#ui-dialog-body.list li:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.list li a {\n\tdisplay: block;\n\tpadding: 0.25em 0.75em;\n\tborder: 1px solid transparent;\n\tcolor: #eee;\n\ttext-decoration: none;\n}\n#ui-dialog-body.list li a:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n\n/* Saves dialog styling. */\n#ui-dialog-body.saves {\n\tpadding: 0 0 1px; /* Webkit/Blink need 1px bottom padding or they'll trigger the scroll bar */\n}\n#ui-dialog-body.saves > *:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.saves table {\n\tborder-spacing: 0;\n\twidth: 100%;\n}\n#ui-dialog-body.saves tr:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.saves td {\n\tpadding: 0.33em 0.33em;\n}\n#ui-dialog-body.saves td:first-child {\n\tmin-width: 1.5em;\n\ttext-align: center;\n}\n#ui-dialog-body.saves td:nth-child(3) {\n\tline-height: 1.2;\n}\n#ui-dialog-body.saves td:last-child {\n\ttext-align: right;\n}\n#ui-dialog-body.saves .empty {\n\tcolor: #999;\n\tspeak: none;\n\ttext-align: center;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n#ui-dialog-body.saves .datestamp {\n\tfont-size: 75%;\n\tmargin-left: 1em;\n}\n#ui-dialog-body.saves ul.buttons li {\n\tpadding: 0.4em;\n}\n#ui-dialog-body.saves ul.buttons > li + li > button {\n\tmargin-left: 0.2em;\n}\n#ui-dialog-body.saves ul.buttons li:last-child {\n\t/*\n\t\tUsing `position:absolute;right:0;` here can produce poor results,\n\t\tso we use `float:right` instead.\n\t*/\n\tfloat: right;\n}\n\n/* Settings dialog styling. */\n#ui-dialog-body.settings div[id|=\"header-body\"] {\n\tmargin: 1em 0;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"]:first-child {\n\tmargin-top: 0;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"]:not(:first-child) {\n\tborder-top: 1px solid #444;\n\tpadding-top: 1em;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"] > * {\n\tmargin: 0;\n}\n#ui-dialog-body.settings h2[id|=\"header-heading\"] {\n\tfont-size: 1.375em;\n}\n#ui-dialog-body.settings p[id|=\"header-desc\"],\n#ui-dialog-body.settings p[id|=\"setting-desc\"] {\n\tfont-size: 87.5%;\n\tmargin: 0 0 0 0.5em;\n}\n#ui-dialog-body.settings div[id|=\"setting-body\"] + div[id|=\"setting-body\"] {\n\tmargin: 1em 0;\n}\n#ui-dialog-body.settings [id|=\"setting-control\"] {\n\twhite-space: nowrap;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"] {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tpadding: 0.4em;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"]:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled {\n\tbackground-color: #282;\n\tborder-color: #4a4;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:hover {\n\tbackground-color: #4a4;\n\tborder-color: #6c6;\n}\n#ui-dialog-body.settings input[type=\"range\"][id|=\"setting-control\"] {\n\tmax-width: 35vw;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-dialog-body.list a,\n#ui-dialog-body.settings span[id|=\"setting-input\"] {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-dialog-body.saves button[id=\"saves-export\"]:before,\n#ui-dialog-body.saves button[id=\"saves-import\"]:before,\n#ui-dialog-body.saves button[id=\"saves-clear\"]:before,\n#ui-dialog-body.settings button[id|=\"setting-control\"]:after,\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#ui-dialog-body.saves button[id=\"saves-export\"]:before {\n\tcontent: \"\\e829\\00a0\";\n}\n#ui-dialog-body.saves button[id=\"saves-import\"]:before {\n\tcontent: \"\\e82a\\00a0\";\n}\n#ui-dialog-body.saves button[id=\"saves-clear\"]:before {\n\tcontent: \"\\e827\\00a0\";\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"]:after {\n\tcontent: \"\\00a0\\00a0\\e830\";\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:after {\n\tcontent: \"\\00a0\\00a0\\e831\";\n}\n</style>\n<style id=\"style-ui-bar\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-bar.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tPatches to the core styles.\n*/\n#story {\n\tmargin-left: 20em;\n\t-webkit-transition: margin-left 200ms ease-in;\n\t-o-transition: margin-left 200ms ease-in;\n\ttransition: margin-left 200ms ease-in;\n}\n#ui-bar.stowed ~ #story {\n\tmargin-left: 4.5em;\n}\n@media screen and (max-width: 1136px) {\n\t#story {\n\t\tmargin-left: 19em;\n\t}\n\t#ui-bar.stowed ~ #story {\n\t\tmargin-left: 3.5em;\n\t}\n}\n/*\n\tAt very narrow viewport widths, set `#story{margin-left}` equal to the value\n\tof `#ui-bar.stowed~#story{margin-left}`, so that `#ui-bar` will side over top\n\tof `#story` when unstowed, rather than shoving it over.\n*/\n@media screen and (max-width: 768px) {\n\t#story {\n\t\tmargin-left: 3.5em;\n\t}\n}\n\n\n/*\n\tDefault structural styles.\n*/\n#ui-bar {\n\tposition: fixed;\n\tz-index: 50;\n\ttop: 0;\n\tleft: 0;\n\twidth: 17.5em;\n\theight: 100%;\n\tmargin: 0;\n\tpadding: 0;\n\t-webkit-transition: left 200ms ease-in;\n\t-o-transition: left 200ms ease-in;\n\ttransition: left 200ms ease-in;\n}\n#ui-bar.stowed {\n\tleft: -15.5em;\n}\n#ui-bar-tray {\n\tposition: absolute;\n\ttop: 0.2em;\n\tleft: 0;\n\tright: 0;\n}\n#ui-bar-body {\n\theight: 90%; /* fallback for browsers without support for calc() */\n\theight: calc(100% - 2.5em);\n\tmargin: 2.5em 0;\n\tpadding: 0 1.5em;\n}\n#ui-bar.stowed #ui-bar-history,\n#ui-bar.stowed #ui-bar-body {\n\tvisibility: hidden;\n\t-webkit-transition: visibility 200ms step-end;\n\t-o-transition: visibility 200ms step-end;\n\ttransition: visibility 200ms step-end;\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n#ui-bar {\n\tbackground-color: #222;\n\tborder-right: 1px solid #444;\n\ttext-align: center;\n}\n#ui-bar a {\n\ttext-decoration: none;\n}\n#ui-bar hr {\n\tborder-color: #444;\n}\n#ui-bar-toggle,\n#ui-bar-history [id|=\"history\"] {\n\tfont-size: 1.2em;\n\tline-height: inherit;\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n}\n#ui-bar-toggle {\n\tdisplay: block;\n\tposition: absolute;\n\ttop: 0;\n\tright: 0;\n\tborder-right: none;\n\tpadding: 0.3em 0.45em 0.25em;\n}\n#ui-bar.stowed #ui-bar-toggle {\n\tpadding: 0.3em 0.35em 0.25em 0.55em;\n}\n#ui-bar-toggle:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n#ui-bar-history {\n\tmargin: 0 auto;\n}\n#ui-bar-history [id|=\"history\"] {\n\tpadding: 0.2em 0.45em 0.35em;\n}\n#ui-bar-history #history-jumpto {\n\tpadding: 0.2em 0.665em 0.35em;\n}\n#ui-bar-history [id|=\"history\"]:not(:first-child) {\n\tmargin-left: 1.2em;\n}\n#ui-bar-history [id|=\"history\"]:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n#ui-bar-history [id|=\"history\"]:disabled {\n\tcolor: #444;\n\tbackground-color: transparent;\n\tborder-color: #444;\n}\n#ui-bar-body {\n\tline-height: 1.5;\n\toverflow: auto;\n}\n#ui-bar-body > :not(:first-child) {\n\tmargin-top: 2em;\n}\n#story-title {\n\tmargin: 0;\n\tfont-size: 162.5%;\n}\n#story-author {\n\tmargin-top: 2em;\n\tfont-weight: bold;\n}\n#menu ul {\n\tmargin: 1em 0 0;\n\tpadding: 0;\n\tlist-style: none;\n\tborder: 1px solid #444;\n}\n#menu ul:empty {\n\tdisplay: none;\n}\n#menu li {\n\tmargin: 0;\n}\n#menu li:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#menu li a {\n\tdisplay: block;\n\tpadding: 0.25em 0.75em;\n\tborder: 1px solid transparent;\n\tcolor: #eee;\n\ttext-transform: uppercase;\n}\n#menu li a:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-bar-history [id|=\"history\"],\n#ui-bar-toggle,\n#menu a {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-bar-toggle:before,\n#ui-bar-history [id|=\"history\"],\n#menu-core li[id|=\"menu-item\"] a:before {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#ui-bar-toggle:before {\n\tcontent: \"\\e81d\";\n}\n#ui-bar.stowed #ui-bar-toggle:before {\n\tcontent: \"\\e81e\";\n}\n#menu-item-saves a:before {\n\tcontent: \"\\e82b\\00a0\";\n}\n#menu-item-settings a:before {\n\tcontent: \"\\e82d\\00a0\";\n}\n#menu-item-restart a:before {\n\tcontent: \"\\e82c\\00a0\";\n}\n#menu-item-share a:before {\n\tcontent: \"\\e82f\\00a0\";\n}\n</style>\n<style id=\"style-ui-debug\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-debug.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault debug bar styles.\n*/\n#debug-bar {\n\tbackground-color: #222;\n\tborder-left: 1px solid #444;\n\tborder-top: 1px solid #444;\n\tbottom: 0;\n\tmargin: 0;\n\tmax-height: 75%;\n\t/* max-width: 28em;\n\tmin-width: 22em; */\n\tpadding: 0.5em;\n\tposition: fixed;\n\tright: 0;\n\tz-index: 99900;\n}\n#debug-bar > div:not([id]) + div {\n\tmargin-top: 0.5em;\n}\n#debug-bar > div > label {\n\tmargin-right: 0.5em;\n}\n#debug-bar > div > input[type=\"text\"] {\n\tmin-width: 0;\n\twidth: 8em;\n}\n#debug-bar > div > select {\n\twidth: 15em;\n}\n\n#debug-bar-toggle {\n\tcolor: #eee;\n\tbackground-color: #222;\n\tborder: 1px solid #444;\n\theight: 101%; /* fallback for browsers without support for calc() */\n\theight: calc(100% + 1px);\n\tleft: -2em; /* fallback for browsers without support for calc() */\n\tleft: calc(-2em - 1px);\n\tposition: absolute;\n\ttop: -1px;\n\twidth: 2em;\n}\n#debug-bar-toggle:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n\n#debug-bar-hint {\n\tbottom: 0.175em;\n\tfont-size: 4.5em;\n\topacity: 0.33;\n\tpointer-events: none;\n\tposition: fixed;\n\tright: 0.6em;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n\twhite-space: nowrap;\n}\n\n#debug-bar-watch {\n\tbackground-color: #222;\n\tborder-left: 1px solid #444;\n\tborder-top: 1px solid #444;\n\tbottom: 102%; /* fallback for browsers without support for calc() */\n\tbottom: calc(100% + 1px);\n\tfont-size: 0.9em;\n\tleft: -1px;\n\tmax-height: 650%; /* fallback for browsers without support for vh units */\n\tmax-height: 65vh;\n\tposition: absolute;\n\toverflow-x: hidden;\n\toverflow-y: scroll;\n\tright: 0;\n\tz-index: 99800;\n}\n#debug-bar-watch[hidden] {\n\tdisplay: none;\n}\n#debug-bar-watch div {\n\tcolor: #999;\n\tfont-style: italic;\n\tmargin: 1em auto;\n\ttext-align: center;\n}\n#debug-bar-watch table {\n\twidth: 100%;\n}\n#debug-bar-watch tr:nth-child(2n) {\n\tbackground-color: rgba(127, 127, 127, 0.15);\n}\n#debug-bar-watch td {\n\tpadding: 0.2em 0;\n}\n#debug-bar-watch td:first-child + td {\n\tpadding: 0.2em 0.3em 0.2em 0.1em;\n}\n#debug-bar-watch .watch-delete {\n\tbackground-color: transparent;\n\tborder: none;\n\tcolor: #c00;\n}\n#debug-bar-watch-all,\n#debug-bar-watch-none {\n\tmargin-left: 0.5em;\n}\n#debug-bar-watch-toggle,\n#debug-bar-views-toggle {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tmargin-right: 1em;\n\tpadding: 0.4em;\n}\n#debug-bar-watch-toggle:hover,\n#debug-bar-views-toggle:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle,\nhtml[data-debug-view] #debug-bar-views-toggle {\n\tbackground-color: #282;\n\tborder-color: #4a4;\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle:hover,\nhtml[data-debug-view] #debug-bar-views-toggle:hover {\n\tbackground-color: #4a4;\n\tborder-color: #6c6;\n}\n\n#debug-bar-toggle:before,\n#debug-bar-hint:after,\n#debug-bar-watch .watch-delete:before,\n#debug-bar-watch-add:before,\n#debug-bar-watch-all:before,\n#debug-bar-watch-none:before,\n#debug-bar-watch-toggle:after,\n#debug-bar-views-toggle:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#debug-bar-toggle:before {\n\tcontent: \"\\e838\";\n}\n#debug-bar-hint:after {\n\tcontent: \"\\e838\\202f\\e822\";\n}\n#debug-bar-watch .watch-delete:before {\n\tcontent: \"\\e804\";\n}\n#debug-bar-watch-add:before {\n\tcontent: \"\\e805\";\n}\n#debug-bar-watch-all:before {\n\tcontent: \"\\e83a\";\n}\n#debug-bar-watch-none:before {\n\tcontent: \"\\e827\";\n}\n#debug-bar-watch-toggle:after,\n#debug-bar-views-toggle:after {\n\tcontent: \"\\00a0\\00a0\\e830\";\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle:after,\nhtml[data-debug-view] #debug-bar-views-toggle:after {\n\tcontent: \"\\00a0\\00a0\\e831\";\n}\n\n\n/*\n\tDefault debug view styles.\n*/\nhtml[data-debug-view] .debug {\n\tpadding: 0.25em;\n\tbackground-color: #234; /* #541, #151 */\n}\nhtml[data-debug-view] .debug[title] {\n\tcursor: help;\n}\nhtml[data-debug-view] .debug.block {\n\tdisplay: inline-block;\n\tvertical-align: middle;\n}\nhtml[data-debug-view] .debug.invalid {\n\ttext-decoration: line-through;\n}\nhtml[data-debug-view] .debug.hidden,\nhtml[data-debug-view] .debug.hidden .debug {\n\tbackground-color: #555;\n}\nhtml:not([data-debug-view]) .debug.hidden {\n\tdisplay: none;\n}\n\nhtml[data-debug-view] .debug[data-name][data-type]:before,\nhtml[data-debug-view] .debug[data-name][data-type].nonvoid:after {\n\tbackground-color: rgba(0,0,0,0.25);\n\tfont-family: monospace, monospace;\n\twhite-space: pre;\n}\nhtml[data-debug-view] .debug[data-name][data-type]:before {\n\tcontent: attr(data-name);\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"macro\"]:before {\n\tcontent: \"<<\" attr(data-name) \">>\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"macro\"].nonvoid:after {\n\tcontent: \"<</\" attr(data-name) \">>\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"html\"]:before {\n\tcontent: \"<\" attr(data-name) \">\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"html\"].nonvoid:after {\n\tcontent: \"</\" attr(data-name) \">\";\n}\nhtml[data-debug-view] .debug[data-name][data-type]:not(:empty):before {\n\tmargin-right: 0.25em;\n}\nhtml[data-debug-view] .debug[data-name][data-type].nonvoid:not(:empty):after {\n\tmargin-left: 0.25em;\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"special\"],\nhtml[data-debug-view] .debug[data-name][data-type|=\"special\"]:before {\n\tdisplay: block;\n}\n</style>\n</head>\n<body>\n\t<div id=\"init-screen\">\n\t\t<div id=\"init-no-js\"><noscript>JavaScript is required. Please enable it to continue.</noscript></div>\n\t\t<div id=\"init-lacking\">Your browser lacks required capabilities. Please upgrade it or switch to another to continue.</div>\n\t\t<div id=\"init-loading\"><div>Loading&hellip;</div></div>\n\t</div>\n\t{{STORY_DATA}}\n\t<script id=\"script-sugarcube\" type=\"text/javascript\">\n\t/*! SugarCube JS */\n\tif(document.documentElement.getAttribute(\"data-init\")===\"loading\"){window.TWINE1=false;\nwindow.DEBUG=true;\n(function (window, document, jQuery, undefined) {\n\"use strict\";\n\n/***********************************************************************************************************************\n\n\tlib/alert.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tTODO: This regular expression should be elsewhere.\n\n\tError prologs by engine/browser: (ca. 2018)\n\t\tChrome, Opera, & Vivaldi → `Uncaught \\w*Error: …`\n\t\tEdge & IE                → `…`\n\t\tFirefox                  → `Error: …`\n\t\tOpera (Presto)           → `Uncaught exception: \\w*(?:Error|Exception): …`\n\t\tSafari (ca. v5.1)        → `\\w*(?:Error|_ERR): …`\n*/\nvar errorPrologRegExp = /^(?:(?:uncaught\\s+(?:exception:\\s+)?)?\\w*(?:error|exception|_err):\\s+)+/i; // eslint-disable-line no-unused-vars, no-var\n\nvar Alert = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tError Functions.\n\t*******************************************************************************************************************/\n\tfunction _alertMesg(type, where, what, error) {\n\t\tconst isFatal = type === 'fatal';\n\t\tlet mesg = `Apologies! ${isFatal ? 'A fatal' : 'An'} error has occurred.`;\n\n\t\tif (isFatal) {\n\t\t\tmesg += ' Aborting.';\n\t\t}\n\t\telse {\n\t\t\tmesg += ' You may be able to continue, but some parts may not work properly.';\n\t\t}\n\n\t\tif (where != null || what != null) { // lazy equality for null\n\t\t\tmesg += '\\n\\nError';\n\n\t\t\tif (where != null) { // lazy equality for null\n\t\t\t\tmesg += ` [${where}]`;\n\t\t\t}\n\n\t\t\tif (what != null) { // lazy equality for null\n\t\t\t\tmesg += `: ${what.replace(errorPrologRegExp, '')}.`;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tmesg += ': unknown error.';\n\t\t\t}\n\t\t}\n\n\t\tif (typeof error === 'object' && error !== null && error.stack) {\n\t\t\tmesg += `\\n\\nStack Trace:\\n${error.stack}`;\n\t\t}\n\n\t\twindow.alert(mesg); // eslint-disable-line no-alert\n\t}\n\n\tfunction alertError(where, what, error) {\n\t\t_alertMesg(null, where, what, error);\n\t}\n\n\tfunction alertFatal(where, what, error) {\n\t\t_alertMesg('fatal', where, what, error);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tError Event.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSet up a global error handler for uncaught exceptions.\n\t*/\n\t(origOnError => {\n\t\twindow.onerror = function (what, source, lineNum, colNum, error) {\n\t\t\t// Uncaught exceptions during play may be recoverable/ignorable.\n\t\t\tif (document.readyState === 'complete') {\n\t\t\t\talertError(null, what, error);\n\t\t\t}\n\n\t\t\t// Uncaught exceptions during startup should be fatal.\n\t\t\telse {\n\t\t\t\talertFatal(null, what, error);\n\t\t\t\twindow.onerror = origOnError;\n\n\t\t\t\tif (typeof window.onerror === 'function') {\n\t\t\t\t\twindow.onerror.apply(this, arguments);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t})(window.onerror);\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\terror : { value : alertError },\n\t\tfatal : { value : alertFatal }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/patterns.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tTODO: Move all markup patterns into here.\n*/\n\nvar Patterns = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tPatterns.\n\t*******************************************************************************************************************/\n\t/*\n\t\tWhitespace patterns.\n\n\t\tSpace class (equivalent to `\\s`):\n\t\t\t[\\u0020\\f\\n\\r\\t\\v\\u00a0\\u1680\\u180e\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000\\ufeff]\n\t\tSpace class, sans line terminators:\n\t\t\t[\\u0020\\f\\t\\v\\u00a0\\u1680\\u180e\\u2000-\\u200a\\u202f\\u205f\\u3000\\ufeff]\n\t\tLine Terminator class:\n\t\t\t[\\n\\r\\u2028\\u2029]\n\t*/\n\tconst space = (() => {\n\t\t/*\n\t\t\tSome browsers still supported by SugarCube have faulty space classes (`\\s`).\n\t\t\tWe check for that lossage here and, if necessary, build our own class from\n\t\t\tthe component pieces.\n\t\t*/\n\t\tconst wsMap = new Map([\n\t\t\t['\\u0020', '\\\\u0020'],\n\t\t\t['\\f', '\\\\f'],\n\t\t\t['\\n', '\\\\n'],\n\t\t\t['\\r', '\\\\r'],\n\t\t\t['\\t', '\\\\t'],\n\t\t\t['\\v', '\\\\v'],\n\t\t\t['\\u00a0', '\\\\u00a0'],\n\t\t\t['\\u1680', '\\\\u1680'],\n\t\t\t['\\u180e', '\\\\u180e'],\n\t\t\t['\\u2000', '\\\\u2000'],\n\t\t\t['\\u2001', '\\\\u2001'],\n\t\t\t['\\u2002', '\\\\u2002'],\n\t\t\t['\\u2003', '\\\\u2003'],\n\t\t\t['\\u2004', '\\\\u2004'],\n\t\t\t['\\u2005', '\\\\u2005'],\n\t\t\t['\\u2006', '\\\\u2006'],\n\t\t\t['\\u2007', '\\\\u2007'],\n\t\t\t['\\u2008', '\\\\u2008'],\n\t\t\t['\\u2009', '\\\\u2009'],\n\t\t\t['\\u200a', '\\\\u200a'],\n\t\t\t['\\u2028', '\\\\u2028'],\n\t\t\t['\\u2029', '\\\\u2029'],\n\t\t\t['\\u202f', '\\\\u202f'],\n\t\t\t['\\u205f', '\\\\u205f'],\n\t\t\t['\\u3000', '\\\\u3000'],\n\t\t\t['\\ufeff', '\\\\ufeff']\n\t\t]);\n\t\tconst wsRe = /^\\s$/;\n\t\tlet missing = '';\n\n\t\twsMap.forEach((pat, char) => {\n\t\t\tif (!wsRe.test(char)) {\n\t\t\t\tmissing += pat;\n\t\t\t}\n\t\t});\n\n\t\treturn missing ? `[\\\\s${missing}]` : '\\\\s';\n\t})();\n\tconst spaceNoTerminator = '[\\\\u0020\\\\f\\\\t\\\\v\\\\u00a0\\\\u1680\\\\u180e\\\\u2000-\\\\u200a\\\\u202f\\\\u205f\\\\u3000\\\\ufeff]';\n\tconst lineTerminator    = '[\\\\n\\\\r\\\\u2028\\\\u2029]';\n\tconst notSpace          = space === '\\\\s' ? '\\\\S' : space.replace(/^\\[/, '[^');\n\n\t/*\n\t\tCharacter patterns.\n\t*/\n\tconst anyChar = `(?:.|${lineTerminator})`;\n\n\t/*\n\t\tLetter patterns.\n\n\t\tFIXME:\n\t\t\t1. The existing set, which is a TiddlyWiki holdover, should probably\n\t\t\t   encompass a significantly greater range of BMP code points.\n\t\t\t2. Should we include the surrogate pair code units (\\uD800-\\uDBFF &\n\t\t\t   \\uDC00-\\uDFFF) to handle non-BMP code points?  Further, should we\n\t\t\t   simply be checking for the code units themselves or checking for\n\t\t\t   properly mated pairs?\n\t*/\n\tconst anyLetter       = '[0-9A-Z_a-z\\\\-\\\\u00c0-\\\\u00d6\\\\u00d8-\\\\u00f6\\\\u00f8-\\\\u00ff\\\\u0150\\\\u0170\\\\u0151\\\\u0171]';\n\tconst anyLetterStrict = anyLetter.replace('\\\\-', ''); // anyLetter sans hyphen\n\n\t/*\n\t\tIdentifier patterns.\n\n\t\tNOTE: Since JavaScript's RegExp syntax does not support Unicode character\n\t\tclasses, the correct regular expression to match a valid identifier name,\n\t\twithin the scope of our needs, would be on the order of approximately 5–6\n\t\tor 11–16 KiB, depending on how the pattern was built.  That being the case,\n\t\tfor the moment we restrict valid TwineScript identifiers to US-ASCII.\n\n\t\tFIXME: Fix this to, at least, approximate the correct range.\n\t*/\n\tconst identifierFirstChar = '[$A-Z_a-z]';\n\tconst identifierNextChar  = '[$0-9A-Z_a-z]';\n\tconst identifier          = `${identifierFirstChar}${identifierNextChar}*`;\n\n\t// Variable patterns.\n\tconst variableSigil = '[$_]';\n\tconst variable      = variableSigil + identifier;\n\n\t// Macro name pattern.\n\tconst macroName = '[A-Za-z][\\\\w-]*|[=-]';\n\n\t// Template name pattern.\n\tconst templateName = '[A-Za-z][\\\\w-]*';\n\n\t// CSS ID or class sigil pattern.\n\tconst cssIdOrClassSigil = '[#.]';\n\n\t// CSS image transclusion template pattern.\n\t//\n\t// NOTE: The alignment syntax isn't supported, but removing it might break uses\n\t// of the template in the wild, so we leave it alone for now.\n\tconst cssImage = '\\\\[[<>]?[Ii][Mm][Gg]\\\\[(?:\\\\s|\\\\S)*?\\\\]\\\\]+';\n\n\t// Inline CSS pattern.\n\tconst inlineCss = (() => {\n\t\t/* legacy */\n\t\tconst twStyle   = `(${anyLetter}+)\\\\(([^\\\\)\\\\|\\\\n]+)\\\\):`;\n\t\t/* /legacy */\n\t\tconst cssStyle  = `${spaceNoTerminator}*(${anyLetter}+)${spaceNoTerminator}*:([^;\\\\|\\\\n]+);`;\n\t\tconst idOrClass = `${spaceNoTerminator}*((?:${cssIdOrClassSigil}${anyLetter}+${spaceNoTerminator}*)+);`;\n\n\t\t// [1,2] = style(value):\n\t\t// [3,4] = style:value;\n\t\t// [5]   = #id.className;\n\t\treturn `${twStyle}|${cssStyle}|${idOrClass}`;\n\t})();\n\n\t// URL pattern.\n\tconst url = '(?:file|https?|mailto|ftp|javascript|irc|news|data):[^\\\\s\\'\"]+';\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze({\n\t\tspace,\n\t\tspaceNoTerminator,\n\t\tlineTerminator,\n\t\tnotSpace,\n\t\tanyChar,\n\t\tanyLetter,\n\t\tanyLetterStrict,\n\t\tidentifierFirstChar,\n\t\tidentifierNextChar,\n\t\tidentifier,\n\t\tvariableSigil,\n\t\tvariable,\n\t\tmacroName,\n\t\ttemplateName,\n\t\tcssIdOrClassSigil,\n\t\tcssImage,\n\t\tinlineCss,\n\t\turl\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/extensions.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns */\n\n/*\n\tJavaScript Polyfills.\n\n\tNOTE: The ES5 and ES6 polyfills come from the vendored `es5-shim.js` and `es6-shim.js` libraries.\n*/\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tTrims whitespace from either the start or end of the given string.\n\t*/\n\tconst _trimString = (() => {\n\t\t// Whitespace regular expressions.\n\t\tconst startWSRe = new RegExp(`^${Patterns.space}${Patterns.space}*`);\n\t\tconst endWSRe   = new RegExp(`${Patterns.space}${Patterns.space}*$`);\n\n\t\tfunction trimString(str, where) {\n\t\t\tconst val = String(str);\n\n\t\t\tif (!val) {\n\t\t\t\treturn val;\n\t\t\t}\n\n\t\t\tswitch (where) {\n\t\t\tcase 'start':\n\t\t\t\treturn startWSRe.test(val) ? val.replace(startWSRe, '') : val;\n\n\t\t\tcase 'end':\n\t\t\t\treturn endWSRe.test(val) ? val.replace(endWSRe, '') : val;\n\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`_trimString called with incorrect where parameter value: \"${where}\"`);\n\t\t\t}\n\t\t}\n\n\t\treturn trimString;\n\t})();\n\n\t/*\n\t\tGenerates a pad string based upon the given string and length.\n\t*/\n\tfunction _createPadString(length, padding) {\n\t\tconst targetLength = Number.parseInt(length, 10) || 0;\n\n\t\tif (targetLength < 1) {\n\t\t\treturn '';\n\t\t}\n\n\t\tlet padString = typeof padding === 'undefined' ? '' : String(padding);\n\n\t\tif (padString === '') {\n\t\t\tpadString = ' ';\n\t\t}\n\n\t\twhile (padString.length < targetLength) {\n\t\t\tconst curPadLength    = padString.length;\n\t\t\tconst remainingLength = targetLength - curPadLength;\n\n\t\t\tpadString += curPadLength > remainingLength\n\t\t\t\t? padString.slice(0, remainingLength)\n\t\t\t\t: padString;\n\t\t}\n\n\t\tif (padString.length > targetLength) {\n\t\t\tpadString = padString.slice(0, targetLength);\n\t\t}\n\n\t\treturn padString;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPolyfills.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[ES2019] Returns a new array consisting of the source array with all sub-array elements\n\t\tconcatenated into it recursively up to the given depth.\n\t*/\n\tif (!Array.prototype.flat) {\n\t\tObject.defineProperty(Array.prototype, 'flat', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\t\t\tvalue        : (() => {\n\t\t\t\tfunction flat(/* depth */) {\n\t\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\t\tthrow new TypeError('Array.prototype.flat called on null or undefined');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst depth = arguments.length === 0 ? 1 : Number(arguments[0]) || 0;\n\n\t\t\t\t\tif (depth < 1) {\n\t\t\t\t\t\treturn Array.prototype.slice.call(this);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn Array.prototype.reduce.call(\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\t(acc, cur) => {\n\t\t\t\t\t\t\tif (cur instanceof Array) {\n\t\t\t\t\t\t\t\t// acc.push.apply(acc, flat.call(cur, depth - 1));\n\t\t\t\t\t\t\t\tacc.push(...flat.call(cur, depth - 1));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tacc.push(cur);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn acc;\n\t\t\t\t\t\t},\n\t\t\t\t\t\t[]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn flat;\n\t\t\t})()\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a new array consisting of the result of calling the given mapping function\n\t\ton every element in the source array and then concatenating all sub-array elements into it\n\t\trecursively up to a depth of `1`.  Identical to calling `<Array>.map(fn).flat()`.\n\t*/\n\tif (!Array.prototype.flatMap) {\n\t\tObject.defineProperty(Array.prototype, 'flatMap', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(/* callback [, thisArg] */) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Array.prototype.flatMap called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.map.apply(this, arguments).flat();\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2016] Returns whether the given element was found within the array.\n\t*/\n\tif (!Array.prototype.includes) {\n\t\tObject.defineProperty(Array.prototype, 'includes', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Array.prototype.includes called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tif (arguments.length === 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst length = this.length >>> 0;\n\n\t\t\t\tif (length === 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst needle = arguments[0];\n\t\t\t\tlet i = Number(arguments[1]) || 0;\n\n\t\t\t\tif (i < 0) {\n\t\t\t\t\ti = Math.max(0, length + i);\n\t\t\t\t}\n\n\t\t\t\tfor (/* empty */; i < length; ++i) {\n\t\t\t\t\tconst value = this[i];\n\n\t\t\t\t\tif (value === needle || value !== value && needle !== needle) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a new array consisting of the given object's own enumerable property/value\n\t\tpairs as `[key, value]` arrays.\n\t*/\n\tif (!Object.entries) {\n\t\tObject.defineProperty(Object, 'entries', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (typeof obj !== 'object' || obj === null) {\n\t\t\t\t\tthrow new TypeError('Object.entries object parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\treturn Object.keys(obj).map(key => [key, obj[key]]);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a new generic object consisting of the given list's key/value pairs.\n\t*/\n\tif (!Object.fromEntries) {\n\t\tObject.defineProperty(Object, 'fromEntries', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(iter) {\n\t\t\t\treturn Array.from(iter).reduce(\n\t\t\t\t\t(acc, pair) => {\n\t\t\t\t\t\tif (Object(pair) !== pair) {\n\t\t\t\t\t\t\tthrow new TypeError('Object.fromEntries iterable parameter must yield objects');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (pair[0] in acc) {\n\t\t\t\t\t\t\tObject.defineProperty(acc, pair[0], {\n\t\t\t\t\t\t\t\tconfigurable : true,\n\t\t\t\t\t\t\t\tenumerable   : true,\n\t\t\t\t\t\t\t\twritable     : true,\n\t\t\t\t\t\t\t\tvalue        : pair[1]\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tacc[pair[0]] = pair[1]; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{}\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns all own property descriptors of the given object.\n\t*/\n\tif (!Object.getOwnPropertyDescriptors) {\n\t\tObject.defineProperty(Object, 'getOwnPropertyDescriptors', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (obj == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Object.getOwnPropertyDescriptors object parameter is null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst O = Object(obj);\n\n\t\t\t\treturn Reflect.ownKeys(O).reduce(\n\t\t\t\t\t(acc, key) => {\n\t\t\t\t\t\tconst desc = Object.getOwnPropertyDescriptor(O, key);\n\n\t\t\t\t\t\tif (typeof desc !== 'undefined') {\n\t\t\t\t\t\t\tif (key in acc) {\n\t\t\t\t\t\t\t\tObject.defineProperty(acc, key, {\n\t\t\t\t\t\t\t\t\tconfigurable : true,\n\t\t\t\t\t\t\t\t\tenumerable   : true,\n\t\t\t\t\t\t\t\t\twritable     : true,\n\t\t\t\t\t\t\t\t\tvalue        : desc\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tacc[key] = desc; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{}\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a new array consisting of the given object's own enumerable property values.\n\t*/\n\tif (!Object.values) {\n\t\tObject.defineProperty(Object, 'values', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (typeof obj !== 'object' || obj === null) {\n\t\t\t\t\tthrow new TypeError('Object.values object parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\treturn Object.keys(obj).map(key => obj[key]);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a string based on concatenating the given padding, repeated as necessary,\n\t\tto the start of the string so that the given length is reached.\n\n\t\tNOTE: This pads based upon Unicode code units, rather than code points.\n\t*/\n\tif (!String.prototype.padStart) {\n\t\tObject.defineProperty(String.prototype, 'padStart', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(length, padding) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.padStart called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst baseString   = String(this);\n\t\t\t\tconst baseLength   = baseString.length;\n\t\t\t\tconst targetLength = Number.parseInt(length, 10);\n\n\t\t\t\tif (targetLength <= baseLength) {\n\t\t\t\t\treturn baseString;\n\t\t\t\t}\n\n\t\t\t\treturn _createPadString(targetLength - baseLength, padding) + baseString;\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a string based on concatenating the given padding, repeated as necessary,\n\t\tto the end of the string so that the given length is reached.\n\n\t\tNOTE: This pads based upon Unicode code units, rather than code points.\n\t*/\n\tif (!String.prototype.padEnd) {\n\t\tObject.defineProperty(String.prototype, 'padEnd', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(length, padding) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.padEnd called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst baseString   = String(this);\n\t\t\t\tconst baseLength   = baseString.length;\n\t\t\t\tconst targetLength = Number.parseInt(length, 10);\n\n\t\t\t\tif (targetLength <= baseLength) {\n\t\t\t\t\treturn baseString;\n\t\t\t\t}\n\n\t\t\t\treturn baseString + _createPadString(targetLength - baseLength, padding);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a string with all whitespace removed from the start of the string.\n\t*/\n\tif (!String.prototype.trimStart) {\n\t\tObject.defineProperty(String.prototype, 'trimStart', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimStart called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'start');\n\t\t\t}\n\t\t});\n\t}\n\n\tif (!String.prototype.trimLeft) {\n\t\tObject.defineProperty(String.prototype, 'trimLeft', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimLeft called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'start');\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a string with all whitespace removed from the end of the string.\n\t*/\n\tif (!String.prototype.trimEnd) {\n\t\tObject.defineProperty(String.prototype, 'trimEnd', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimEnd called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'end');\n\t\t\t}\n\t\t});\n\t}\n\n\tif (!String.prototype.trimRight) {\n\t\tObject.defineProperty(String.prototype, 'trimRight', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimRight called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'end');\n\t\t\t}\n\t\t});\n\t}\n})();\n\n\n/*\n\tJavaScript Extensions.\n*/\n(() => {\n\t'use strict';\n\n\tconst _nativeMathRandom = Math.random;\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a pseudo-random whole number (integer) within the given bounds.\n\t*/\n\tfunction _random(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('_random called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = arguments[0];\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = arguments[0];\n\t\t\tmax = arguments[1];\n\t\t\tbreak;\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn Math.floor(_nativeMathRandom() * (max - min + 1)) + min;\n\t}\n\n\t/*\n\t\tReturns a randomly selected index within the given length and bounds.\n\t\tBounds may be negative.\n\t*/\n\tfunction _randomIndex(length, boundsArgs) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (boundsArgs.length) {\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = length - 1;\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tmin = 0;\n\t\t\tmax = Math.trunc(boundsArgs[1]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Math.trunc(boundsArgs[1]);\n\t\t\tmax = Math.trunc(boundsArgs[2]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (Number.isNaN(min)) {\n\t\t\tmin = 0;\n\t\t}\n\t\telse if (!Number.isFinite(min) || min >= length) {\n\t\t\tmin = length - 1;\n\t\t}\n\t\telse if (min < 0) {\n\t\t\tmin = length + min;\n\n\t\t\tif (min < 0) {\n\t\t\t\tmin = 0;\n\t\t\t}\n\t\t}\n\n\t\tif (Number.isNaN(max)) {\n\t\t\tmax = 0;\n\t\t}\n\t\telse if (!Number.isFinite(max) || max >= length) {\n\t\t\tmax = length - 1;\n\t\t}\n\t\telse if (max < 0) {\n\t\t\tmax = length + max;\n\n\t\t\tif (max < 0) {\n\t\t\t\tmax = length - 1;\n\t\t\t}\n\t\t}\n\n\t\treturn _random(min, max);\n\t}\n\n\t/*\n\t\tReturns an object (`{ char, start, end }`) containing the Unicode character at\n\t\tposition `pos`, its starting position, and its ending position—surrogate pairs\n\t\tare properly handled.  If `pos` is out-of-bounds, returns an object containing\n\t\tthe empty string and start/end positions of `-1`.\n\n\t\tThis function is necessary because JavaScript strings are sequences of UTF-16\n\t\tcode units, so surrogate pairs are exposed and thus must be handled.  While the\n\t\tES6/2015 standard does improve the situation somewhat, it does not alleviate\n\t\tthe need for this function.\n\n\t\tNOTE: Will throw exceptions on invalid surrogate pairs.\n\n\t\tIDEA: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt\n\t*/\n\tfunction _getCodePointStartAndEnd(str, pos) {\n\t\tconst code = str.charCodeAt(pos);\n\n\t\t// Given position was out-of-bounds.\n\t\tif (Number.isNaN(code)) {\n\t\t\treturn { char : '', start : -1, end : -1 };\n\t\t}\n\n\t\t// Code unit is not a UTF-16 surrogate.\n\t\tif (code < 0xD800 || code > 0xDFFF) {\n\t\t\treturn {\n\t\t\t\tchar  : str.charAt(pos),\n\t\t\t\tstart : pos,\n\t\t\t\tend   : pos\n\t\t\t};\n\t\t}\n\n\t\t// Code unit is a high surrogate (D800–DBFF).\n\t\tif (code >= 0xD800 && code <= 0xDBFF) {\n\t\t\tconst nextPos = pos + 1;\n\n\t\t\t// End of string.\n\t\t\tif (nextPos >= str.length) {\n\t\t\t\tthrow new Error('high surrogate without trailing low surrogate');\n\t\t\t}\n\n\t\t\tconst nextCode = str.charCodeAt(nextPos);\n\n\t\t\t// Next code unit is not a low surrogate (DC00–DFFF).\n\t\t\tif (nextCode < 0xDC00 || nextCode > 0xDFFF) {\n\t\t\t\tthrow new Error('high surrogate without trailing low surrogate');\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tchar  : str.charAt(pos) + str.charAt(nextPos),\n\t\t\t\tstart : pos,\n\t\t\t\tend   : nextPos\n\t\t\t};\n\t\t}\n\n\t\t// Code unit is a low surrogate (DC00–DFFF) in the first position.\n\t\tif (pos === 0) {\n\t\t\tthrow new Error('low surrogate without leading high surrogate');\n\t\t}\n\n\t\tconst prevPos  = pos - 1;\n\t\tconst prevCode = str.charCodeAt(prevPos);\n\n\t\t// Previous code unit is not a high surrogate (D800–DBFF).\n\t\tif (prevCode < 0xD800 || prevCode > 0xDBFF) {\n\t\t\tthrow new Error('low surrogate without leading high surrogate');\n\t\t}\n\n\t\treturn {\n\t\t\tchar  : str.charAt(prevPos) + str.charAt(pos),\n\t\t\tstart : prevPos,\n\t\t\tend   : pos\n\t\t};\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, General.\n\t*******************************************************************************************************************/\n\t/*\n\t\tRandomly selects an element from the given array, or array-like object, and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array, 'random', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(array /* DEPRECATED: [, [min ,] max] */) {\n\t\t\tif (\n\t\t\t\t   typeof array !== 'object'\n\t\t\t\t|| array === null\n\t\t\t\t|| !Object.prototype.hasOwnProperty.call(array, 'length')\n\t\t\t) {\n\t\t\t\tthrow new TypeError('Array.random array parameter must be an array or array-lke object');\n\t\t\t}\n\n\t\t\tconst length = array.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, Array.prototype.slice.call(arguments, 1));\n\n\t\t\treturn array[index];\n\t\t}\n\t});\n\n\t/*\n\t\tConcatenates one or more unique elements to the end of the base array\n\t\tand returns the result as a new array.  Elements which are arrays will\n\t\tbe merged—i.e. their elements will be concatenated, rather than the\n\t\tarray itself.\n\t*/\n\tObject.defineProperty(Array.prototype, 'concatUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.concatUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst result = Array.from(this);\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tconst items   = Array.prototype.reduce.call(arguments, (prev, cur) => prev.concat(cur), []);\n\t\t\tconst addSize = items.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst push    = Array.prototype.push;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = items[i];\n\n\t\t\t\tif (indexOf.call(result, value) === -1) {\n\t\t\t\t\tpush.call(result, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number of times the given element was found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'count', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex ] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.count called on null or undefined');\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst needle  = arguments[0];\n\t\t\tlet pos   = Number(arguments[1]) || 0;\n\t\t\tlet count = 0;\n\n\t\t\twhile ((pos = indexOf.call(this, needle, pos)) !== -1) {\n\t\t\t\t++count;\n\t\t\t\t++pos;\n\t\t\t}\n\n\t\t\treturn count;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the given elements from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'delete', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.delete called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst needles       = Array.prototype.concat.apply([], arguments);\n\t\t\tconst needlesLength = needles.length;\n\t\t\tconst indices       = [];\n\n\t\t\tfor (let i = 0; i < length; ++i) {\n\t\t\t\tconst value = this[i];\n\n\t\t\t\tfor (let j = 0; j < needlesLength; ++j) {\n\t\t\t\t\tconst needle = needles[j];\n\n\t\t\t\t\tif (value === needle || value !== value && needle !== needle) {\n\t\t\t\t\t\tindices.push(i);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst result = [];\n\n\t\t\t// Copy the elements (in original order).\n\t\t\tfor (let i = 0, iend = indices.length; i < iend; ++i) {\n\t\t\t\tresult[i] = this[indices[i]];\n\t\t\t}\n\n\t\t\tconst splice = Array.prototype.splice;\n\n\t\t\t// Delete the elements (in reverse order).\n\t\t\tfor (let i = indices.length - 1; i >= 0; --i) {\n\t\t\t\tsplice.call(this, indices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the elements at the given indices from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'deleteAt', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* indices */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.deleteAt called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst splice     = Array.prototype.splice;\n\t\t\tconst cpyIndices = [\n\t\t\t\t...(new Set(\n\t\t\t\t\tArray.prototype.concat.apply([], arguments)\n\t\t\t\t\t\t// Map negative indices to their positive counterparts,\n\t\t\t\t\t\t// so the Set can properly filter out duplicates.\n\t\t\t\t\t\t.map(x => x < 0 ? Math.max(0, length + x) : x)\n\t\t\t\t)).values()\n\t\t\t];\n\t\t\tconst delIndices = [...cpyIndices].sort((a, b) => b - a);\n\t\t\tconst result     = [];\n\n\t\t\t// Copy the elements (in originally specified order).\n\t\t\tfor (let i = 0, iend = cpyIndices.length; i < iend; ++i) {\n\t\t\t\tresult[i] = this[cpyIndices[i]];\n\t\t\t}\n\n\t\t\t// Delete the elements (in descending numeric order).\n\t\t\tfor (let i = 0, iend = delIndices.length; i < iend; ++i) {\n\t\t\t\tsplice.call(this, delIndices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the elements that pass the test implemented\n\t\tby the given predicate function from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'deleteWith', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(predicate, thisArg) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.deleteWith called on null or undefined');\n\t\t\t}\n\t\t\tif (typeof predicate !== 'function') {\n\t\t\t\tthrow new Error('Array.prototype.deleteWith predicate parameter must be a function');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst splice  = Array.prototype.splice;\n\t\t\tconst indices = [];\n\t\t\tconst result  = [];\n\n\t\t\t// Copy the elements (in original order).\n\t\t\tfor (let i = 0; i < length; ++i) {\n\t\t\t\tif (predicate.call(thisArg, this[i], i, this)) {\n\t\t\t\t\tresult.push(this[i]);\n\t\t\t\t\tindices.push(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Delete the elements (in reverse order).\n\t\t\tfor (let i = indices.length - 1; i >= 0; --i) {\n\t\t\t\tsplice.call(this, indices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the first element from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'first', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.first called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn this[0];\n\t\t}\n\t});\n\n\t/*\n\t\tReturns whether all of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'includesAll', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.includesAll called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 1) {\n\t\t\t\tif (Array.isArray(arguments[0])) {\n\t\t\t\t\treturn Array.prototype.includesAll.apply(this, arguments[0]);\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = arguments.length; i < iend; ++i) {\n\t\t\t\tif (\n\t\t\t\t\t!Array.prototype.some.call(this, function (val) {\n\t\t\t\t\t\treturn val === this.val || val !== val && this.val !== this.val;\n\t\t\t\t\t}, { val : arguments[i] })\n\t\t\t\t) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns whether any of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'includesAny', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.includesAny called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 1) {\n\t\t\t\tif (Array.isArray(arguments[0])) {\n\t\t\t\t\treturn Array.prototype.includesAny.apply(this, arguments[0]);\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = arguments.length; i < iend; ++i) {\n\t\t\t\tif (\n\t\t\t\t\tArray.prototype.some.call(this, function (val) {\n\t\t\t\t\t\treturn val === this.val || val !== val && this.val !== this.val;\n\t\t\t\t\t}, { val : arguments[i] })\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the last element from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'last', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.last called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn this[length - 1];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly removes an element from the base array and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pluck', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* DEPRECATED: [min ,] max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pluck called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, [...arguments]);\n\n\t\t\treturn Array.prototype.splice.call(this, index, 1)[0];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly removes the given number of unique elements from the base array\n\t\tand returns the removed elements as a new array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pluckMany', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(wantSize) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pluckMany called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tlet want = Math.trunc(wantSize);\n\n\t\t\tif (!Number.isInteger(want)) {\n\t\t\t\tthrow new Error('Array.prototype.pluckMany want parameter must be an integer');\n\t\t\t}\n\n\t\t\tif (want < 1) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif (want > length) {\n\t\t\t\twant = length;\n\t\t\t}\n\n\t\t\tconst splice = Array.prototype.splice;\n\t\t\tconst result = [];\n\t\t\tlet max = length - 1;\n\n\t\t\tdo {\n\t\t\t\tresult.push(splice.call(this, _random(0, max--), 1)[0]);\n\t\t\t} while (result.length < want);\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tAppends one or more unique elements to the end of the base array and\n\t\treturns its new length.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pushUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pushUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst addSize = arguments.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn this.length >>> 0;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst push    = Array.prototype.push;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = arguments[i];\n\n\t\t\t\tif (indexOf.call(this, value) === -1) {\n\t\t\t\t\tpush.call(this, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.length >>> 0;\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly selects an element from the base array and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array.prototype, 'random', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* DEPRECATED: [min ,] max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.random called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, [...arguments]);\n\n\t\t\treturn this[index];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly selects the given number of unique elements from the base array\n\t\tand returns the selected elements as a new array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'randomMany', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(wantSize) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.randomMany called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tlet want = Math.trunc(wantSize);\n\n\t\t\tif (!Number.isInteger(want)) {\n\t\t\t\tthrow new Error('Array.prototype.randomMany want parameter must be an integer');\n\t\t\t}\n\n\t\t\tif (want < 1) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif (want > length) {\n\t\t\t\twant = length;\n\t\t\t}\n\n\t\t\tconst picked = new Map();\n\t\t\tconst result = [];\n\t\t\tconst max    = length - 1;\n\n\t\t\tdo {\n\t\t\t\tlet i;\n\t\t\t\tdo {\n\t\t\t\t\ti = _random(0, max);\n\t\t\t\t} while (picked.has(i));\n\t\t\t\tpicked.set(i, true);\n\t\t\t\tresult.push(this[i]);\n\t\t\t} while (result.length < want);\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly shuffles the array and returns it.\n\t*/\n\tObject.defineProperty(Array.prototype, 'shuffle', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.shuffle called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tfor (let i = length - 1; i > 0; --i) {\n\t\t\t\tconst j = Math.floor(_nativeMathRandom() * (i + 1));\n\n\t\t\t\tif (i === j) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// [this[i], this[j]] = [this[j], this[i]];\n\t\t\t\tconst swap = this[i];\n\t\t\t\tthis[i] = this[j];\n\t\t\t\tthis[j] = swap;\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\t});\n\n\t/*\n\t\tPrepends one or more unique elements to the beginning of the base array\n\t\tand returns its new length.\n\t*/\n\tObject.defineProperty(Array.prototype, 'unshiftUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.unshiftUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst addSize = arguments.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn this.length >>> 0;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst unshift = Array.prototype.unshift;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = arguments[i];\n\n\t\t\t\tif (indexOf.call(this, value) === -1) {\n\t\t\t\t\tunshift.call(this, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.length >>> 0;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a bound function that supplies the given arguments to the base\n\t\tfunction, followed by the arguments are supplied to the bound function,\n\t\twhenever it is called.\n\t*/\n\tObject.defineProperty(Function.prototype, 'partial', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Function.prototype.partial called on null or undefined');\n\t\t\t}\n\n\t\t\tconst slice = Array.prototype.slice;\n\t\t\tconst fn    = this;\n\t\t\tconst bound = slice.call(arguments, 0);\n\n\t\t\treturn function () {\n\t\t\t\tconst applied = [];\n\t\t\t\tlet argc = 0;\n\n\t\t\t\tfor (let i = 0; i < bound.length; ++i) {\n\t\t\t\t\tapplied.push(bound[i] === undefined ? arguments[argc++] : bound[i]);\n\t\t\t\t}\n\n\t\t\t\treturn fn.apply(this, applied.concat(slice.call(arguments, argc)));\n\t\t\t};\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the given numerical clamped to the specified bounds.\n\t*/\n\tObject.defineProperty(Math, 'clamp', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(num, min, max) {\n\t\t\tconst value = Number(num);\n\t\t\treturn Number.isNaN(value) ? NaN : value.clamp(min, max);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a decimal number eased from 0 to 1.\n\n\t\tNOTE: The magnitude of the returned value decreases if num < 0.5 or increases if num > 0.5.\n\t*/\n\tObject.defineProperty(Math, 'easeInOut', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(num) {\n\t\t\treturn 1 - (Math.cos(Number(num) * Math.PI) + 1) / 2;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number clamped to the specified bounds.\n\t*/\n\tObject.defineProperty(Number.prototype, 'clamp', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* min, max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Number.prototype.clamp called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length !== 2) {\n\t\t\t\tthrow new Error('Number.prototype.clamp called with an incorrect number of parameters');\n\t\t\t}\n\n\t\t\tlet min = Number(arguments[0]);\n\t\t\tlet max = Number(arguments[1]);\n\n\t\t\tif (min > max) {\n\t\t\t\t[min, max] = [max, min];\n\t\t\t}\n\n\t\t\treturn Math.min(Math.max(this, min), max);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the given string with all RegExp metacharacters escaped.\n\t*/\n\tif (!RegExp.escape) {\n\t\t(() => {\n\t\t\tconst _regExpMetaCharsRe    = /[\\\\^$*+?.()|[\\]{}]/g;\n\t\t\tconst _hasRegExpMetaCharsRe = new RegExp(_regExpMetaCharsRe.source); // to drop the global flag\n\n\t\t\tObject.defineProperty(RegExp, 'escape', {\n\t\t\t\tconfigurable : true,\n\t\t\t\twritable     : true,\n\n\t\t\t\tvalue(str) {\n\t\t\t\t\tconst val = String(str);\n\t\t\t\t\treturn val && _hasRegExpMetaCharsRe.test(val)\n\t\t\t\t\t\t? val.replace(_regExpMetaCharsRe, '\\\\$&')\n\t\t\t\t\t\t: val;\n\t\t\t\t}\n\t\t\t});\n\t\t})();\n\t}\n\n\t/*\n\t\tReturns a formatted string, after replacing each format item in the given\n\t\tformat string with the text equivalent of the corresponding argument's value.\n\t*/\n\t(() => {\n\t\tconst _formatRegExp    = /{(\\d+)(?:,([+-]?\\d+))?}/g;\n\t\tconst _hasFormatRegExp = new RegExp(_formatRegExp.source); // to drop the global flag\n\n\t\tObject.defineProperty(String, 'format', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(format) {\n\t\t\t\tfunction padString(str, align, pad) {\n\t\t\t\t\tif (!align) {\n\t\t\t\t\t\treturn str;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst plen = Math.abs(align) - str.length;\n\n\t\t\t\t\tif (plen < 1) {\n\t\t\t\t\t\treturn str;\n\t\t\t\t\t}\n\n\t\t\t\t\t// const padding = Array(plen + 1).join(pad);\n\t\t\t\t\tconst padding = String(pad).repeat(plen);\n\t\t\t\t\treturn align < 0 ? str + padding : padding + str;\n\t\t\t\t}\n\n\t\t\t\tif (arguments.length < 2) {\n\t\t\t\t\treturn arguments.length === 0 ? '' : format;\n\t\t\t\t}\n\n\t\t\t\tconst args = arguments.length === 2 && Array.isArray(arguments[1])\n\t\t\t\t\t? [...arguments[1]]\n\t\t\t\t\t: Array.prototype.slice.call(arguments, 1);\n\n\t\t\t\tif (args.length === 0) {\n\t\t\t\t\treturn format;\n\t\t\t\t}\n\n\t\t\t\tif (!_hasFormatRegExp.test(format)) {\n\t\t\t\t\treturn format;\n\t\t\t\t}\n\n\t\t\t\t// Possibly required by some old buggy browsers.\n\t\t\t\t_formatRegExp.lastIndex = 0;\n\n\t\t\t\treturn format.replace(_formatRegExp, (match, index, align) => {\n\t\t\t\t\tlet retval = args[index];\n\n\t\t\t\t\tif (retval == null) { // lazy equality for null\n\t\t\t\t\t\treturn '';\n\t\t\t\t\t}\n\n\t\t\t\t\twhile (typeof retval === 'function') {\n\t\t\t\t\t\tretval = retval();\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (typeof retval) {\n\t\t\t\t\tcase 'string': /* no-op */ break;\n\t\t\t\t\tcase 'object': retval = JSON.stringify(retval); break;\n\t\t\t\t\tdefault:       retval = String(retval); break;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn padString(retval, !align ? 0 : Number.parseInt(align, 10), ' ');\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t})();\n\n\t/*\n\t\tReturns whether the given string was found within the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'contains', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.contains called on null or undefined');\n\t\t\t}\n\n\t\t\treturn String.prototype.indexOf.apply(this, arguments) !== -1;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number of times the given substring was found within the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'count', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex ] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.count called on null or undefined');\n\t\t\t}\n\n\t\t\tconst needle = String(arguments[0] || '');\n\n\t\t\tif (needle === '') {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tconst indexOf = String.prototype.indexOf;\n\t\t\tconst step    = needle.length;\n\t\t\tlet pos     = Number(arguments[1]) || 0;\n\t\t\tlet count   = 0;\n\n\t\t\twhile ((pos = indexOf.call(this, needle, pos)) !== -1) {\n\t\t\t\t++count;\n\t\t\t\tpos += step;\n\t\t\t}\n\n\t\t\treturn count;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the first Unicode code point from the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'first', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.first called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn char;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the last Unicode code point from the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'last', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.last called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the last code point—may be one or two code units—and its end position.\n\t\t\tconst { char } = _getCodePointStartAndEnd(str, str.length - 1);\n\n\t\t\treturn char;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with `delCount` characters replaced with\n\t\t`replacement`, starting at `startAt`.\n\t*/\n\tObject.defineProperty(String.prototype, 'splice', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(startAt, delCount, replacement) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.splice called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tlet start = Number(startAt);\n\n\t\t\tif (!Number.isSafeInteger(start)) {\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t\telse if (start < 0) {\n\t\t\t\tstart += length;\n\n\t\t\t\tif (start < 0) {\n\t\t\t\t\tstart = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (start > length) {\n\t\t\t\tstart = length;\n\t\t\t}\n\n\t\t\tlet count = Number(delCount);\n\n\t\t\tif (!Number.isSafeInteger(count) || count < 0) {\n\t\t\t\tcount = 0;\n\t\t\t}\n\n\t\t\tlet res = this.slice(0, start);\n\n\t\t\tif (typeof replacement !== 'undefined') {\n\t\t\t\tres += replacement;\n\t\t\t}\n\n\t\t\tif (start + count < length) {\n\t\t\t\tres += this.slice(start + count);\n\t\t\t}\n\n\t\t\treturn res;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns an array of strings, split from the string, or an empty array if the\n\t\tstring is empty.\n\t*/\n\tObject.defineProperty(String.prototype, 'splitOrEmpty', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* [ separator [, limit ]] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.splitOrEmpty called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tif (String(this) === '') {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\treturn String.prototype.split.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with the first Unicode code point uppercased,\n\t\taccording to any locale-specific rules.\n\t*/\n\tObject.defineProperty(String.prototype, 'toLocaleUpperFirst', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.toLocaleUpperFirst called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char, end } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn end === -1 ? '' : char.toLocaleUpperCase() + str.slice(end + 1);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with the first Unicode code point uppercased.\n\t*/\n\tObject.defineProperty(String.prototype, 'toUpperFirst', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.toUpperFirst called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char, end } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn end === -1 ? '' : char.toUpperCase() + str.slice(end + 1);\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, JSON.\n\t*******************************************************************************************************************/\n\t/*\n\t\tDefine `toJSON()` methods on each prototype we wish to support.\n\t*/\n\tObject.defineProperty(Date.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:date)', this.toISOString()];\n\t\t}\n\t});\n\tObject.defineProperty(Function.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\t/*\n\t\t\t\tThe enclosing parenthesis here are necessary to force the function expression code\n\t\t\t\tstring, returned by `this.toString()`, to be evaluated as an expression during\n\t\t\t\trevival.  Without them, the function expression, which is likely nameless, will be\n\t\t\t\tevaluated as a function definition—which will throw a syntax error exception, since\n\t\t\t\tfunction definitions must have a name.\n\t\t\t*/\n\t\t\treturn ['(revive:eval)', `(${this.toString()})`];\n\t\t}\n\t});\n\tObject.defineProperty(Map.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:map)', [...this]];\n\t\t}\n\t});\n\tObject.defineProperty(RegExp.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:eval)', this.toString()];\n\t\t}\n\t});\n\tObject.defineProperty(Set.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:set)', [...this]];\n\t\t}\n\t});\n\n\t/*\n\t\tUtility method to allow users to easily wrap their code in the revive wrapper.\n\t*/\n\tObject.defineProperty(JSON, 'reviveWrapper', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(code, data) {\n\t\t\tif (typeof code !== 'string') {\n\t\t\t\tthrow new TypeError('JSON.reviveWrapper code parameter must be a string');\n\t\t\t}\n\n\t\t\treturn ['(revive:eval)', [code, data]];\n\t\t}\n\t});\n\n\t/*\n\t\tBackup the original `JSON.parse()` and replace it with a revive wrapper aware version.\n\t*/\n\tObject.defineProperty(JSON, '_real_parse', {\n\t\tvalue : JSON.parse\n\t});\n\tObject.defineProperty(JSON, 'parse', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(text, reviver) {\n\t\t\treturn JSON._real_parse(text, (key, val) => {\n\t\t\t\tlet value = val;\n\n\t\t\t\t/*\n\t\t\t\t\tAttempt to revive wrapped values.\n\t\t\t\t*/\n\t\t\t\tif (Array.isArray(value) && value.length === 2) {\n\t\t\t\t\tswitch (value[0]) {\n\t\t\t\t\tcase '(revive:set)':\n\t\t\t\t\t\tvalue = new Set(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:map)':\n\t\t\t\t\t\tvalue = new Map(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:date)':\n\t\t\t\t\t\tvalue = new Date(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:eval)':\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t/* eslint-disable no-eval */\n\t\t\t\t\t\t\t// For post-v2.9.0 `JSON.reviveWrapper()`.\n\t\t\t\t\t\t\tif (Array.isArray(value[1])) {\n\t\t\t\t\t\t\t\tconst $ReviveData$ = value[1][1]; // eslint-disable-line no-unused-vars\n\t\t\t\t\t\t\t\tvalue = eval(value[1][0]);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// For regular expressions, functions, and pre-v2.9.0 `JSON.reviveWrapper()`.\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tvalue = eval(value[1]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/* eslint-enable no-eval */\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* legacy */\n\t\t\t\telse if (typeof value === 'string' && value.slice(0, 10) === '@@revive@@') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvalue = eval(value.slice(10)); // eslint-disable-line no-eval\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t}\n\t\t\t\t/* /legacy */\n\n\t\t\t\t/*\n\t\t\t\t\tCall the custom reviver, if specified.\n\t\t\t\t*/\n\t\t\t\tif (typeof reviver === 'function') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvalue = reviver(key, value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t}\n\n\t\t\t\treturn value;\n\t\t\t});\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, Deprecated.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Returns whether the given element was found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'contains', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.contains called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns whether all of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'containsAll', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.containsAll called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includesAll.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns whether any of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'containsAny', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.containsAny called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includesAny.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns a new array consisting of the flattened source array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'flatten', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.flatten called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.flat.call(this, Infinity);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns an array of link titles, parsed from the string.\n\n\t\tNOTE: Unused in SugarCube, only included for compatibility.\n\t*/\n\tObject.defineProperty(String.prototype, 'readBracketedList', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.readBracketedList called on null or undefined');\n\t\t\t}\n\n\t\t\t// RegExp groups: Double-square-bracket quoted | Unquoted.\n\t\t\tconst re    = new RegExp('(?:\\\\[\\\\[((?:\\\\s|\\\\S)*?)\\\\]\\\\])|([^\"\\'\\\\s]\\\\S*)', 'gm');\n\t\t\tconst names = [];\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this)) !== null) {\n\t\t\t\tif (match[1]) { // double-square-bracket quoted\n\t\t\t\t\tnames.push(match[1]);\n\t\t\t\t}\n\t\t\t\telse if (match[2]) { // unquoted\n\t\t\t\t\tnames.push(match[2]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn names;\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/browser.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar Browser = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/* eslint-disable max-len */\n\tconst userAgent = navigator.userAgent.toLowerCase();\n\n\tconst winPhone = userAgent.includes('windows phone');\n\tconst isMobile = Object.freeze({\n\t\tAndroid    : !winPhone && userAgent.includes('android'),\n\t\tBlackBerry : /blackberry|bb10/.test(userAgent),\n\t\tiOS        : !winPhone && /ip(?:hone|ad|od)/.test(userAgent),\n\t\tOpera      : !winPhone && (typeof window.operamini === 'object' || userAgent.includes('opera mini')),\n\t\tWindows    : winPhone || /iemobile|wpdesktop/.test(userAgent),\n\n\t\tany() {\n\t\t\treturn isMobile.Android || isMobile.BlackBerry || isMobile.iOS || isMobile.Opera || isMobile.Windows;\n\t\t}\n\t});\n\n\tconst isGecko = !isMobile.Windows && !/khtml|trident|edge/.test(userAgent) && userAgent.includes('gecko');\n\n\tconst isIE      = !userAgent.includes('opera') && /msie|trident/.test(userAgent);\n\tconst ieVersion = isIE\n\t\t? (() => {\n\t\t\tconst ver = /(?:msie\\s+|rv:)(\\d+\\.\\d)/.exec(userAgent);\n\t\t\treturn ver ? Number(ver[1]) : 0;\n\t\t})()\n\t\t: null;\n\n\t// opera <= 12: \"opera/9.80 (windows nt 6.1; wow64) presto/2.12.388 version/12.16\"\n\t// opera >= 15: \"mozilla/5.0 (windows nt 6.1; wow64) applewebkit/537.36 (khtml, like gecko) chrome/28.0.1500.52 safari/537.36 opr/15.0.1147.130\"\n\tconst isOpera      = userAgent.includes('opera') || userAgent.includes(' opr/');\n\tconst operaVersion = isOpera\n\t\t? (() => {\n\t\t\tconst re  = new RegExp(`${/khtml|chrome/.test(userAgent) ? 'opr' : 'version'}\\\\/(\\\\d+\\\\.\\\\d+)`);\n\t\t\tconst ver = re.exec(userAgent);\n\t\t\treturn ver ? Number(ver[1]) : 0;\n\t\t})()\n\t\t: null;\n\n\tconst isVivaldi = userAgent.includes('vivaldi');\n\t/* eslint-enable max-len */\n\n\t// Module Exports.\n\treturn Object.freeze({\n\t\tuserAgent,\n\t\tisMobile,\n\t\tisGecko,\n\t\tisIE,\n\t\tieVersion,\n\t\tisOpera,\n\t\toperaVersion,\n\t\tisVivaldi\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/has.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser */\n\nvar Has = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tNOTE: The aggressive try/catch feature tests are necessitated by implementation\n\t\tbugs in various browsers.\n\t*/\n\n\t// Is the `HTMLAudioElement` API available?\n\tconst hasAudioElement = (() => {\n\t\ttry {\n\t\t\treturn typeof document.createElement('audio').canPlayType === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `File` API available?\n\tconst hasFile = (() => {\n\t\ttry {\n\t\t\treturn 'Blob' in window &&\n\t\t\t\t'File' in window &&\n\t\t\t\t'FileList' in window &&\n\t\t\t\t'FileReader' in window &&\n\t\t\t\t!Browser.isMobile.any() &&\n\t\t\t\t(!Browser.isOpera || Browser.operaVersion >= 15);\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `geolocation` API available?\n\tconst hasGeolocation = (() => {\n\t\ttry {\n\t\t\treturn 'geolocation' in navigator &&\n\t\t\t\ttypeof navigator.geolocation.getCurrentPosition === 'function' &&\n\t\t\t\ttypeof navigator.geolocation.watchPosition === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `MutationObserver` API available?\n\tconst hasMutationObserver = (() => {\n\t\ttry {\n\t\t\treturn 'MutationObserver' in window &&\n\t\t\t\ttypeof window.MutationObserver === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `performance` API available?\n\tconst hasPerformance = (() => {\n\t\ttry {\n\t\t\treturn 'performance' in window &&\n\t\t\t\ttypeof window.performance.now === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the platform a touch device?\n\tconst hasTouch = (() => {\n\t\ttry {\n\t\t\treturn 'ontouchstart' in window ||\n\t\t\t\t!!window.DocumentTouch &&\n\t\t\t\tdocument instanceof window.DocumentTouch ||\n\t\t\t\t!!navigator.maxTouchPoints ||\n\t\t\t\t!!navigator.msMaxTouchPoints;\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the transition end event available and by what name?\n\tconst hasTransitionEndEvent = (() => {\n\t\ttry {\n\t\t\tconst teMap = new Map([\n\t\t\t\t['transition',       'transitionend'],\n\t\t\t\t['MSTransition',     'msTransitionEnd'],\n\t\t\t\t['WebkitTransition', 'webkitTransitionEnd'],\n\t\t\t\t['MozTransition',    'transitionend']\n\t\t\t]);\n\t\t\tconst teKeys = [...teMap.keys()];\n\t\t\tconst el     = document.createElement('div');\n\n\t\t\tfor (let i = 0; i < teKeys.length; ++i) {\n\t\t\t\tif (el.style[teKeys[i]] !== undefined) {\n\t\t\t\t\treturn teMap.get(teKeys[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Module Exports.\n\treturn Object.freeze({\n\t\taudio              : hasAudioElement,\n\t\tfileAPI            : hasFile,\n\t\tgeolocation        : hasGeolocation,\n\t\tmutationObserver   : hasMutationObserver,\n\t\tperformance        : hasPerformance,\n\t\ttouch              : hasTouch,\n\t\ttransitionEndEvent : hasTransitionEndEvent\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/visibility.js\n\n\tCopyright © 2018–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar Visibility = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tThere are two versions of the Page Visibility API: First Edition and, the current,\n\t\tSecond Edition (i.e. \"Level 2\").  First Edition is mentioned here only because some\n\t\tolder browsers implement it, rather than the current specification.\n\n\t\tSEE:\n\t\t\tSecond Edition : https://www.w3.org/TR/page-visibility/\n\t\t\tFirst Edition  : https://www.w3.org/TR/2013/REC-page-visibility-20130514/\n\n\t\tNOTE: Generally, all supported browsers change the visibility state when either switching tabs\n\t\twithin the browser or minimizing the browser window.  Exceptions are noted below:\n\t\t\t* IE 9 doesn't support either version of the Page Visibility API.\n\t\t\t* Opera 12 (Presto) doesn't change the visibility state when the browser is minimized.\n\t*/\n\n\t// Vendor properties object.\n\tconst vendor = (() => {\n\t\ttry {\n\t\t\treturn Object.freeze([\n\t\t\t\t// Specification.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'hidden',          // boolean; historical in 2nd edition\n\t\t\t\t\tstateProperty  : 'visibilityState', // string, values: 'hidden', 'visible'; 1st edition had more values\n\t\t\t\t\tchangeEvent    : 'visibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `webkit` prefixed: old Blink & WebKit.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'webkitHidden',\n\t\t\t\t\tstateProperty  : 'webkitVisibilityState',\n\t\t\t\t\tchangeEvent    : 'webkitvisibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `moz` prefixed: old Gecko, maybe Seamonkey.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'mozHidden',\n\t\t\t\t\tstateProperty  : 'mozVisibilityState',\n\t\t\t\t\tchangeEvent    : 'mozvisibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `ms` prefixed: IE 10.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'msHidden',\n\t\t\t\t\tstateProperty  : 'msVisibilityState',\n\t\t\t\t\tchangeEvent    : 'msvisibilitychange'\n\t\t\t\t}\n\t\t\t].find(vnd => vnd.hiddenProperty in document));\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn undefined;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tAPI Functions.\n\t*******************************************************************************/\n\n\tfunction getVendor() {\n\t\treturn vendor;\n\t}\n\n\tfunction getVisibility() {\n\t\treturn vendor && document[vendor.stateProperty] || 'visible';\n\t}\n\n\tfunction isEnabled() {\n\t\treturn Boolean(vendor);\n\t}\n\n\tfunction isHidden() {\n\t\t// return Boolean(vendor && document[vendor.stateProperty] === 'hidden');\n\t\treturn Boolean(vendor && document[vendor.hiddenProperty]); // NOTE: Historical, but probably better for 1st edition.\n\t}\n\n\n\t/*******************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Functions.\n\t\tvendor    : { get : getVendor },\n\t\tstate     : { get : getVisibility },\n\t\tisEnabled : { value : isEnabled },\n\t\tisHidden  : { value : isHidden },\n\n\t\t// Properties.\n\t\thiddenProperty : { value : vendor && vendor.hiddenProperty },\n\t\tstateProperty  : { value : vendor && vendor.stateProperty },\n\t\tchangeEvent    : { value : vendor && vendor.changeEvent }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/fullscreen.js\n\n\tCopyright © 2018–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser */\n\nvar Fullscreen = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tSEE:\n\t\t\thttps://fullscreen.spec.whatwg.org\n\t\t\thttps://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API\n\t*/\n\n\t// Vendor properties object.\n\tconst vendor = (() => {\n\t\ttry {\n\t\t\treturn Object.freeze([\n\t\t\t\t// Specification.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'fullscreenEnabled',\n\t\t\t\t\telement     : 'fullscreenElement',\n\t\t\t\t\trequestFn   : 'requestFullscreen',\n\t\t\t\t\texitFn      : 'exitFullscreen',\n\t\t\t\t\tchangeEvent : 'fullscreenchange', // prop: onfullscreenchange\n\t\t\t\t\terrorEvent  : 'fullscreenerror'   // prop: onfullscreenerror\n\t\t\t\t},\n\n\t\t\t\t// `webkit` prefixed: old Blink, WebKit, & Edge.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'webkitFullscreenEnabled',\n\t\t\t\t\telement     : 'webkitFullscreenElement',\n\t\t\t\t\trequestFn   : 'webkitRequestFullscreen',\n\t\t\t\t\texitFn      : 'webkitExitFullscreen',\n\t\t\t\t\tchangeEvent : 'webkitfullscreenchange',\n\t\t\t\t\terrorEvent  : 'webkitfullscreenerror'\n\t\t\t\t},\n\n\t\t\t\t// `moz` prefixed: old Gecko, maybe Seamonkey.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'mozFullScreenEnabled',\n\t\t\t\t\telement     : 'mozFullScreenElement',\n\t\t\t\t\trequestFn   : 'mozRequestFullScreen',\n\t\t\t\t\texitFn      : 'mozCancelFullScreen',\n\t\t\t\t\tchangeEvent : 'mozfullscreenchange',\n\t\t\t\t\terrorEvent  : 'mozfullscreenerror'\n\t\t\t\t},\n\n\t\t\t\t// `ms` prefixed: IE 11.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'msFullscreenEnabled',\n\t\t\t\t\telement     : 'msFullscreenElement',\n\t\t\t\t\trequestFn   : 'msRequestFullscreen',\n\t\t\t\t\texitFn      : 'msExitFullscreen',\n\t\t\t\t\tchangeEvent : 'MSFullscreenChange',\n\t\t\t\t\terrorEvent  : 'MSFullscreenError'\n\t\t\t\t}\n\t\t\t].find(vnd => vnd.isEnabled in document));\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn undefined;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tFeature Detection Functions.\n\t*******************************************************************************/\n\n\t// Return whether the request and exit fullscreen methods return a `Promise`.\n\t//\n\t// NOTE: The initial result is cached for future calls.\n\tconst _returnsPromise = (function () {\n\t\t// Cache of whether the request and exit methods return a `Promise`.\n\t\tlet _hasPromise = null;\n\n\t\tfunction _returnsPromise() {\n\t\t\tif (_hasPromise !== null) {\n\t\t\t\treturn _hasPromise;\n\t\t\t}\n\n\t\t\t_hasPromise = false;\n\n\t\t\tif (vendor) {\n\t\t\t\ttry {\n\t\t\t\t\tconst value = document.exitFullscreen();\n\n\t\t\t\t\t// Silence \"Uncaught (in promise)\" console errors from Blink.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: Swallowing errors is generally bad, but in this case we know there's\n\t\t\t\t\t// going to be an error regardless, since we shouldn't be in fullscreen yet,\n\t\t\t\t\t// and we don't actually care about the error, since we just want the return\n\t\t\t\t\t// value, so we consign it to the bit bucket.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: We don't ensure that the return value is not `undefined` here because\n\t\t\t\t\t// having the attempted call to `<Promise>.catch()` on an `undefined` value throw\n\t\t\t\t\t// is acceptable, since it will be caught and `false` eventually returned.\n\t\t\t\t\tvalue.catch(() => { /* no-op */ });\n\n\t\t\t\t\t_hasPromise = value instanceof Promise;\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t}\n\n\t\t\treturn _hasPromise;\n\t\t}\n\n\t\treturn _returnsPromise;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************/\n\n\tfunction _selectElement(requestedEl) {\n\t\tlet selectedEl = requestedEl || document.documentElement;\n\n\t\t// Document element scrolling workaround for older browsers.\n\t\tif (\n\t\t\t   selectedEl === document.documentElement\n\t\t\t&& (\n\t\t\t\t   vendor.requestFn === 'msRequestFullscreen'   // IE 11\n\t\t\t\t|| Browser.isOpera && Browser.operaVersion < 15 // Opera 12 (Presto)\n\t\t\t)\n\t\t) {\n\t\t\tselectedEl = document.body;\n\t\t}\n\n\t\treturn selectedEl;\n\t}\n\n\n\t/*******************************************************************************\n\t\tAPI Functions.\n\t*******************************************************************************/\n\n\tfunction getVendor() {\n\t\treturn vendor;\n\t}\n\n\tfunction getElement() {\n\t\treturn (vendor || null) && document[vendor.element];\n\t}\n\n\tfunction isEnabled() {\n\t\treturn Boolean(vendor && document[vendor.isEnabled]);\n\t}\n\n\tfunction isFullscreen() {\n\t\treturn Boolean(vendor && document[vendor.element]);\n\t}\n\n\tfunction requestFullscreen(options, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn Promise.reject(new Error('fullscreen not supported'));\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (typeof element[vendor.requestFn] !== 'function') {\n\t\t\treturn Promise.reject(new Error('fullscreen not supported'));\n\t\t}\n\t\tif (isFullscreen()) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tif (_returnsPromise()) {\n\t\t\treturn element[vendor.requestFn](options);\n\t\t}\n\t\telse { // eslint-disable-line no-else-return\n\t\t\tconst namespace = '.Fullscreen_requestFullscreen';\n\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tjQuery(element)\n\t\t\t\t\t.off(namespace)\n\t\t\t\t\t.one(`${vendor.errorEvent}${namespace} ${vendor.changeEvent}${namespace}`, ev => {\n\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\tif (ev.type === vendor.errorEvent) {\n\t\t\t\t\t\t\treject(new Error('unknown fullscreen request error'));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\telement[vendor.requestFn](options);\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction exitFullscreen() {\n\t\tif (!vendor || typeof document[vendor.exitFn] !== 'function') {\n\t\t\treturn Promise.reject(new TypeError('fullscreen not supported'));\n\t\t}\n\t\tif (!isFullscreen()) {\n\t\t\treturn Promise.reject(new TypeError('fullscreen mode not active'));\n\t\t}\n\n\t\tif (_returnsPromise()) {\n\t\t\treturn document[vendor.exitFn]();\n\t\t}\n\t\telse { // eslint-disable-line no-else-return\n\t\t\tconst namespace = '.Fullscreen_exitFullscreen';\n\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tjQuery(document)\n\t\t\t\t\t.off(namespace)\n\t\t\t\t\t.one(`${vendor.errorEvent}${namespace} ${vendor.changeEvent}${namespace}`, ev => {\n\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\tif (ev.type === vendor.errorEvent) {\n\t\t\t\t\t\t\treject(new Error('unknown fullscreen exit error'));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tdocument[vendor.exitFn]();\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction toggleFullscreen(options, requestedEl) {\n\t\treturn isFullscreen() ? exitFullscreen() : requestFullscreen(options, requestedEl);\n\t}\n\n\tfunction onChange(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\t$(element).on(vendor.changeEvent, handlerFn);\n\t}\n\n\tfunction offChange(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (handlerFn) {\n\t\t\t$(element).off(vendor.changeEvent, handlerFn);\n\t\t}\n\t\telse {\n\t\t\t$(element).off(vendor.changeEvent);\n\t\t}\n\t}\n\n\tfunction onError(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\t$(element).on(vendor.errorEvent, handlerFn);\n\t}\n\n\tfunction offError(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (handlerFn) {\n\t\t\t$(element).off(vendor.errorEvent, handlerFn);\n\t\t}\n\t\telse {\n\t\t\t$(element).off(vendor.errorEvent);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tvendor       : { get : getVendor },\n\t\telement      : { get : getElement },\n\t\tisEnabled    : { value : isEnabled },\n\t\tisFullscreen : { value : isFullscreen },\n\t\trequest      : { value : requestFullscreen },\n\t\texit         : { value : exitFullscreen },\n\t\ttoggle       : { value : toggleFullscreen },\n\t\tonChange     : { value : onChange },\n\t\toffChange    : { value : offChange },\n\t\tonError      : { value : onError },\n\t\toffError     : { value : offError }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/helpers.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, L10n, State, Story, Util, Wikifier */\n\nvar { // eslint-disable-line no-var\n\t/* eslint-disable no-unused-vars */\n\tclone,\n\tconvertBreaks,\n\tsafeActiveElement,\n\tsetDisplayTitle,\n\tsetPageElement,\n\tthrowError,\n\ttoStringOrDefault\n\t/* eslint-enable no-unused-vars */\n} = (() => {\n\t'use strict';\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _getTextContent(source) {\n\t\tconst copy = source.cloneNode(true);\n\t\tconst frag = document.createDocumentFragment();\n\t\tlet node;\n\n\t\twhile ((node = copy.firstChild) !== null) {\n\t\t\t// Insert spaces before various elements.\n\t\t\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tswitch (node.nodeName.toUpperCase()) {\n\t\t\t\tcase 'BR':\n\t\t\t\tcase 'DIV':\n\t\t\t\tcase 'P':\n\t\t\t\t\tfrag.appendChild(document.createTextNode(' '));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfrag.appendChild(node);\n\t\t}\n\n\t\treturn frag.textContent;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tHelper Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a deep copy of the given object.\n\n\t\tNOTE:\n\t\t\t1. `clone()` does not clone functions, however, since function definitions\n\t\t\t   are immutable, the only issues are with expando properties and scope.\n\t\t\t   The former really should not be done.  The latter is problematic either\n\t\t\t   way—damned if you do, damned if you don't.\n\t\t\t2. `clone()` does not maintain referential relationships—e.g. multiple\n\t\t\t   references to the same object will, post-cloning, refer to different\n\t\t\t   equivalent objects; i.e. each reference will receive its own clone\n\t\t\t   of the original object.\n\t*/\n\tfunction clone(orig) {\n\t\t/*\n\t\t\tImmediately return the primitives and functions.\n\t\t*/\n\t\tif (typeof orig !== 'object' || orig === null) {\n\t\t\treturn orig;\n\t\t}\n\n\t\t/*\n\t\t\tUnbox instances of the primitive exemplar objects.\n\t\t*/\n\t\tif (orig instanceof String) {\n\t\t\treturn String(orig);\n\t\t}\n\t\tif (orig instanceof Number) {\n\t\t\treturn Number(orig);\n\t\t}\n\t\tif (orig instanceof Boolean) {\n\t\t\treturn Boolean(orig);\n\t\t}\n\n\t\t/*\n\t\t\tHonor native clone methods.\n\t\t*/\n\t\tif (typeof orig.clone === 'function') {\n\t\t\treturn orig.clone(true);\n\t\t}\n\t\tif (orig.nodeType && typeof orig.cloneNode === 'function') {\n\t\t\treturn orig.cloneNode(true);\n\t\t}\n\n\t\t/*\n\t\t\tCreate a copy of the original object.\n\n\t\t\tNOTE: Each non-generic object that we wish to support must be\n\t\t\texplicitly handled below.\n\t\t*/\n\t\tlet copy;\n\n\t\t// Handle instances of the core supported object types.\n\t\tif (orig instanceof Array) {\n\t\t\tcopy = new Array(orig.length);\n\t\t}\n\t\telse if (orig instanceof Date) {\n\t\t\tcopy = new Date(orig.getTime());\n\t\t}\n\t\telse if (orig instanceof Map) {\n\t\t\tcopy = new Map();\n\t\t\torig.forEach((val, key) => copy.set(key, clone(val)));\n\t\t}\n\t\telse if (orig instanceof RegExp) {\n\t\t\tcopy = new RegExp(orig);\n\t\t}\n\t\telse if (orig instanceof Set) {\n\t\t\tcopy = new Set();\n\t\t\torig.forEach(val => copy.add(clone(val)));\n\t\t}\n\n\t\t// Handle instances of unknown or generic objects.\n\t\telse {\n\t\t\t// We try to ensure that the returned copy has the same prototype as\n\t\t\t// the original, but this will probably produce less than satisfactory\n\t\t\t// results on non-generics.\n\t\t\tcopy = Object.create(Object.getPrototypeOf(orig));\n\t\t}\n\n\t\t/*\n\t\t\tDuplicate the original object's own enumerable properties, which will\n\t\t\tinclude expando properties on non-generic objects.\n\n\t\t\tNOTE: This preserves neither symbol properties nor ES5 property attributes.\n\t\t\tNeither does the delta coding or serialization code, however, so it's not\n\t\t\treally an issue at the moment.\n\t\t*/\n\t\tObject.keys(orig).forEach(name => copy[name] = clone(orig[name]));\n\n\t\treturn copy;\n\t}\n\n\t/*\n\t\tConverts <br> elements to <p> elements within the given node tree.\n\t*/\n\tfunction convertBreaks(source) {\n\t\tconst output = document.createDocumentFragment();\n\t\tlet para = document.createElement('p');\n\t\tlet node;\n\n\t\twhile ((node = source.firstChild) !== null) {\n\t\t\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tconst tagName = node.nodeName.toUpperCase();\n\n\t\t\t\tswitch (tagName) {\n\t\t\t\tcase 'BR':\n\t\t\t\t\tif (\n\t\t\t\t\t\t   node.nextSibling !== null\n\t\t\t\t\t\t&& node.nextSibling.nodeType === Node.ELEMENT_NODE\n\t\t\t\t\t\t&& node.nextSibling.nodeName.toUpperCase() === 'BR'\n\t\t\t\t\t) {\n\t\t\t\t\t\tsource.removeChild(node.nextSibling);\n\t\t\t\t\t\tsource.removeChild(node);\n\t\t\t\t\t\toutput.appendChild(para);\n\t\t\t\t\t\tpara = document.createElement('p');\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\telse if (!para.hasChildNodes()) {\n\t\t\t\t\t\tsource.removeChild(node);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'ADDRESS':\n\t\t\t\tcase 'ARTICLE':\n\t\t\t\tcase 'ASIDE':\n\t\t\t\tcase 'BLOCKQUOTE':\n\t\t\t\tcase 'CENTER':\n\t\t\t\tcase 'DIV':\n\t\t\t\tcase 'DL':\n\t\t\t\tcase 'FIGURE':\n\t\t\t\tcase 'FOOTER':\n\t\t\t\tcase 'FORM':\n\t\t\t\tcase 'H1':\n\t\t\t\tcase 'H2':\n\t\t\t\tcase 'H3':\n\t\t\t\tcase 'H4':\n\t\t\t\tcase 'H5':\n\t\t\t\tcase 'H6':\n\t\t\t\tcase 'HEADER':\n\t\t\t\tcase 'HR':\n\t\t\t\tcase 'MAIN':\n\t\t\t\tcase 'NAV':\n\t\t\t\tcase 'OL':\n\t\t\t\tcase 'P':\n\t\t\t\tcase 'PRE':\n\t\t\t\tcase 'SECTION':\n\t\t\t\tcase 'TABLE':\n\t\t\t\tcase 'UL':\n\t\t\t\t\tif (para.hasChildNodes()) {\n\t\t\t\t\t\toutput.appendChild(para);\n\t\t\t\t\t\tpara = document.createElement('p');\n\t\t\t\t\t}\n\n\t\t\t\t\toutput.appendChild(node);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpara.appendChild(node);\n\t\t}\n\n\t\tif (para.hasChildNodes()) {\n\t\t\toutput.appendChild(para);\n\t\t}\n\n\t\tsource.appendChild(output);\n\t}\n\n\t/*\n\t\tReturns `document.activeElement` or `null`.\n\t*/\n\tfunction safeActiveElement() {\n\t\t/*\n\t\t\tIE9 contains a bug where trying to access the active element of an iframe's\n\t\t\tparent document (i.e. `window.parent.document.activeElement`) will throw an\n\t\t\texception, so we must allow for an exception to be thrown.\n\n\t\t\tWe could simply return `undefined` here, but since the API's default behavior\n\t\t\tshould be to return `document.body` or `null` when there is no selection, we\n\t\t\tchoose to return `null` in all non-element cases (i.e. whether it returns\n\t\t\t`null` or throws an exception).  Just a bit of normalization.\n\t\t*/\n\t\ttry {\n\t\t\treturn document.activeElement || null;\n\t\t}\n\t\tcatch (ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/*\n\t\tSets the display title.\n\t*/\n\tfunction setDisplayTitle(title) {\n\t\tif (typeof title !== 'string') {\n\t\t\tthrow new TypeError(`story display title must be a string (received: ${Util.getType(title)})`);\n\t\t}\n\n\t\tconst render = document.createDocumentFragment();\n\t\tnew Wikifier(render, title);\n\n\t\tconst text = _getTextContent(render).trim();\n\n\t\t// if (text === '') {\n\t\t// \tthrow new Error('story display title must not render to an empty string or consist solely of whitespace');\n\t\t// }\n\n\t\tdocument.title = Config.passages.displayTitles && State.passage !== '' && State.passage !== Config.passages.start\n\t\t\t? `${State.passage} | ${text}`\n\t\t\t: text;\n\n\t\tconst storyTitle = document.getElementById('story-title');\n\n\t\tif (storyTitle !== null) {\n\t\t\tjQuery(storyTitle).empty().append(render);\n\t\t}\n\t}\n\n\t/*\n\t\tWikifies a passage into a DOM element corresponding to the passed ID and returns the element.\n\t*/\n\tfunction setPageElement(idOrElement, titles, defaultText) {\n\t\tconst el = typeof idOrElement === 'object'\n\t\t\t? idOrElement\n\t\t\t: document.getElementById(idOrElement);\n\n\t\tif (el == null) { // lazy equality for null\n\t\t\treturn null;\n\t\t}\n\n\t\tconst ids = Array.isArray(titles) ? titles : [titles];\n\n\t\tjQuery(el).empty();\n\n\t\tfor (let i = 0, iend = ids.length; i < iend; ++i) {\n\t\t\tif (Story.has(ids[i])) {\n\t\t\t\tnew Wikifier(el, Story.get(ids[i]).processText().trim());\n\t\t\t\treturn el;\n\t\t\t}\n\t\t}\n\n\t\tif (defaultText != null) { // lazy equality for null\n\t\t\tconst text = String(defaultText).trim();\n\n\t\t\tif (text !== '') {\n\t\t\t\tnew Wikifier(el, text);\n\t\t\t}\n\t\t}\n\n\t\treturn el;\n\t}\n\n\t/*\n\t\tAppends an error view to the passed DOM element.\n\t*/\n\tfunction throwError(place, message, source, stack) {\n\t\tconst $wrapper = jQuery(document.createElement('div'));\n\t\tconst $toggle  = jQuery(document.createElement('button'));\n\t\tconst $source  = jQuery(document.createElement('pre'));\n\t\tconst mesg     = `${L10n.get('errorTitle')}: ${message || 'unknown error'}`;\n\n\t\t$toggle\n\t\t\t.addClass('error-toggle')\n\t\t\t.ariaClick({\n\t\t\t\tlabel : L10n.get('errorToggle')\n\t\t\t}, () => {\n\t\t\t\tif ($toggle.hasClass('enabled')) {\n\t\t\t\t\t$toggle.removeClass('enabled');\n\t\t\t\t\t$source.attr({\n\t\t\t\t\t\t'aria-hidden' : true,\n\t\t\t\t\t\thidden        : 'hidden'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$toggle.addClass('enabled');\n\t\t\t\t\t$source.removeAttr('aria-hidden hidden');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.appendTo($wrapper);\n\t\tjQuery(document.createElement('span'))\n\t\t\t.addClass('error')\n\t\t\t.text(mesg)\n\t\t\t.appendTo($wrapper);\n\t\tjQuery(document.createElement('code'))\n\t\t\t.text(source)\n\t\t\t.appendTo($source);\n\t\t$source\n\t\t\t.addClass('error-source')\n\t\t\t.attr({\n\t\t\t\t'aria-hidden' : true,\n\t\t\t\thidden        : 'hidden'\n\t\t\t})\n\t\t\t.appendTo($wrapper);\n\t\tif (stack) {\n\t\t\tconst lines = stack.split('\\n');\n\t\t\tfor (const ll of lines) {\n\t\t\t\tconst div = document.createElement('div');\n\t\t\t\tdiv.append(ll.replace(/file:.*\\//, '<path>/'));\n\t\t\t\t$source.append(div);\n\t\t\t}\n\t\t}\n\t\t$wrapper\n\t\t\t.addClass('error-view')\n\t\t\t.appendTo(place);\n\n\t\tconsole.warn(`${mesg}\\n\\t${source.replace(/\\n/g, '\\n\\t')}`);\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tReturns the simple string representation of the passed value or, if there is none,\n\t\tthe passed default value.\n\t*/\n\tfunction toStringOrDefault(value, defValue) {\n\t\tconst tSOD = toStringOrDefault;\n\n\t\tswitch (typeof value) {\n\t\tcase 'number':\n\t\t\t// TODO: Perhaps NaN should be printed instead?\n\t\t\tif (Number.isNaN(value)) {\n\t\t\t\treturn defValue;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\tif (value === null) {\n\t\t\t\treturn defValue;\n\t\t\t}\n\t\t\telse if (Array.isArray(value)) {\n\t\t\t\treturn value.map(val => tSOD(val, defValue)).join(', ');\n\t\t\t}\n\t\t\telse if (value instanceof Set) {\n\t\t\t\treturn [...value].map(val => tSOD(val, defValue)).join(', ');\n\t\t\t}\n\t\t\telse if (value instanceof Map) {\n\t\t\t\tconst result = [...value].map(([key, val]) => `${tSOD(key, defValue)} \\u2192 ${tSOD(val, defValue)}`);\n\t\t\t\treturn `{\\u202F${result.join(', ')}\\u202F}`;\n\t\t\t}\n\t\t\telse if (value instanceof Date) {\n\t\t\t\treturn value.toLocaleString();\n\t\t\t}\n\t\t\telse if (typeof value.toString === 'function') {\n\t\t\t\treturn value.toString();\n\t\t\t}\n\t\t\treturn Object.prototype.toString.call(value);\n\n\t\tcase 'function':\n\t\tcase 'undefined':\n\t\t\treturn defValue;\n\t\t}\n\n\t\treturn String(value);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tclone             : { value : clone },\n\t\tconvertBreaks     : { value : convertBreaks },\n\t\tsafeActiveElement : { value : safeActiveElement },\n\t\tsetDisplayTitle   : { value : setDisplayTitle },\n\t\tsetPageElement    : { value : setPageElement },\n\t\tthrowError        : { value : throwError },\n\t\ttoStringOrDefault : { value : toStringOrDefault }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/jquery-plugins.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Wikifier, errorPrologRegExp, safeActiveElement */\n\n/*\n\tWAI-ARIA methods plugin.\n\n\t`<jQuery>.ariaClick([options,] handler)`\n\t    Makes the target element(s) WAI-ARIA compatible clickables.\n\n\t`<jQuery>.ariaDisabled(state)`\n\t    Changes the disabled state of the target WAI-ARIA-compatible clickable element(s).\n\n\t`<jQuery>.ariaIsDisabled()`\n\t    Checks the disabled status of the target WAI-ARIA-compatible clickable element(s).\n*/\n(() => {\n\t'use strict';\n\n\t/*\n\t\tEvent handler & utility functions.\n\n\t\tNOTE: Do not replace the anonymous functions herein with arrow functions.\n\t*/\n\tfunction onKeypressFn(ev) {\n\t\t// 13 is Enter/Return, 32 is Space.\n\t\tif (ev.which === 13 || ev.which === 32) {\n\t\t\tev.preventDefault();\n\n\t\t\t// To allow delegation, attempt to trigger the event on `document.activeElement`,\n\t\t\t// if possible, elsewise on `this`.\n\t\t\tjQuery(safeActiveElement() || this).trigger('click');\n\t\t}\n\t}\n\n\tfunction onClickFnWrapper(fn) {\n\t\treturn function () {\n\t\t\tconst $this = jQuery(this);\n\n\t\t\tconst dataPassage = $this.attr('data-passage');\n\t\t\tconst initialDataPassage = window && window.SugarCube && window.SugarCube.State && window.SugarCube.State.passage;\n\t\t\tconst savedYOffset = window.pageYOffset;\n\n\t\t\t// Toggle \"aria-pressed\" status, if the attribute exists.\n\t\t\tif ($this.is('[aria-pressed]')) {\n\t\t\t\t$this.attr('aria-pressed', $this.attr('aria-pressed') === 'true' ? 'false' : 'true');\n\t\t\t}\n\n\t\t\t// Call the true handler.\n\t\t\tfn.apply(this, arguments);\n\n\t\t\tconst doJump = function(){ window.scrollTo(0, savedYOffset); }\n\t\t\tif ( dataPassage && (window.lastDataPassageLink === dataPassage || initialDataPassage === dataPassage))\n\t\t\t\tdoJump();\n\t\t\twindow.lastDataPassageLink = dataPassage;\n\t\t};\n\t}\n\n\tfunction oneClickFnWrapper(fn) {\n\t\treturn onClickFnWrapper(function () {\n\t\t\t// Remove both event handlers (keypress & click) and the other components.\n\t\t\tjQuery(this)\n\t\t\t\t.off('.aria-clickable')\n\t\t\t\t.removeAttr('tabindex aria-controls aria-pressed')\n\t\t\t\t.not('a,button')\n\t\t\t\t.removeAttr('role')\n\t\t\t\t.end()\n\t\t\t\t.filter('button')\n\t\t\t\t.prop('disabled', true);\n\n\t\t\t// Call the true handler.\n\t\t\tfn.apply(this, arguments);\n\t\t});\n\t}\n\n\tjQuery.fn.extend({\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaClick()` method.\n\t\t*/\n\t\tariaClick(options, handler) {\n\t\t\t// Bail out if there are no target element(s) or parameters.\n\t\t\tif (this.length === 0 || arguments.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tlet opts = options;\n\t\t\tlet fn   = handler;\n\n\t\t\tif (fn == null) { // lazy equality for null\n\t\t\t\tfn   = opts;\n\t\t\t\topts = undefined;\n\t\t\t}\n\n\t\t\topts = jQuery.extend({\n\t\t\t\tnamespace : undefined,\n\t\t\t\tone       : false,\n\t\t\t\tselector  : undefined,\n\t\t\t\tdata      : undefined,\n\t\t\t\tcontrols  : undefined,\n\t\t\t\tpressed   : undefined,\n\t\t\t\tlabel     : undefined\n\t\t\t}, opts);\n\n\t\t\tif (typeof opts.namespace !== 'string') {\n\t\t\t\topts.namespace = '';\n\t\t\t}\n\t\t\telse if (opts.namespace[0] !== '.') {\n\t\t\t\topts.namespace = `.${opts.namespace}`;\n\t\t\t}\n\n\t\t\tif (typeof opts.pressed === 'boolean') {\n\t\t\t\topts.pressed = opts.pressed ? 'true' : 'false';\n\t\t\t}\n\n\t\t\t// Set `type` to `button` to suppress \"submit\" semantics, for <button> elements.\n\t\t\tthis.filter('button').prop('type', 'button');\n\n\t\t\t// Set `role` to `button`, for non-<a>/-<button> elements.\n\t\t\tthis.not('a,button').attr('role', 'button');\n\n\t\t\t// Set `tabindex` to `0` to make them focusable (unnecessary on <button> elements, but it doesn't hurt).\n\t\t\tthis.attr('tabindex', 0);\n\n\t\t\t// Set `aria-controls`.\n\t\t\tif (opts.controls != null) { // lazy equality for null\n\t\t\t\tthis.attr('aria-controls', opts.controls);\n\t\t\t}\n\n\t\t\t// Set `aria-pressed`.\n\t\t\tif (opts.pressed != null) { // lazy equality for null\n\t\t\t\tthis.attr('aria-pressed', opts.pressed);\n\t\t\t}\n\n\t\t\t// Set `aria-label` and `title`.\n\t\t\tif (opts.label != null) { // lazy equality for null\n\t\t\t\tthis.attr({\n\t\t\t\t\t'aria-label' : opts.label,\n\t\t\t\t\ttitle        : opts.label\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Set the keypress handlers, for non-<button> elements.\n\t\t\t// NOTE: For the single-use case, the click handler will also remove this handler.\n\t\t\tthis.not('button').on(\n\t\t\t\t`keypress.aria-clickable${opts.namespace}`,\n\t\t\t\topts.selector,\n\t\t\t\tonKeypressFn\n\t\t\t);\n\n\t\t\t// Set the click handlers.\n\t\t\t// NOTE: To ensure both handlers are properly removed, `one()` must not be used here.\n\t\t\tthis.on(\n\t\t\t\t`click.aria-clickable${opts.namespace}`,\n\t\t\t\topts.selector,\n\t\t\t\topts.data,\n\t\t\t\topts.one ? oneClickFnWrapper(fn) : onClickFnWrapper(fn)\n\t\t\t);\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaDisabled()` method.\n\t\t*/\n\t\tariaDisabled(disable) {\n\t\t\t// Bail out if there are no target element(s) or parameters.\n\t\t\tif (this.length === 0 || arguments.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tNOTE: We use `<jQuery>.each()` callbacks to invoke the `<Element>.setAttribute()`\n\t\t\t\tmethods in the following because the `<jQuery>.attr()` method does not allow you\n\t\t\t\tto set a content attribute without a value, which is recommended for boolean\n\t\t\t\tcontent attributes by the HTML specification.\n\t\t\t*/\n\n\t\t\tconst $nonDisableable = this.not('button,fieldset,input,menuitem,optgroup,option,select,textarea');\n\t\t\tconst $disableable    = this.filter('button,fieldset,input,menuitem,optgroup,option,select,textarea');\n\n\t\t\tif (disable) {\n\t\t\t\t// Add boolean content attribute `disabled` and set non-boolean content attribute\n\t\t\t\t// `aria-disabled` to `'true'`, for non-disableable elements.\n\t\t\t\t$nonDisableable.each(function () {\n\t\t\t\t\tthis.setAttribute('disabled', '');\n\t\t\t\t\tthis.setAttribute('aria-disabled', 'true');\n\t\t\t\t});\n\n\t\t\t\t// Set IDL attribute `disabled` to `true` and set non-boolean content attribute\n\t\t\t\t// `aria-disabled` to `'true'`, for disableable elements.\n\t\t\t\t$disableable.each(function () {\n\t\t\t\t\tthis.disabled = true;\n\t\t\t\t\tthis.setAttribute('aria-disabled', 'true');\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Remove content attributes `disabled` and `aria-disabled`, for non-disableable elements.\n\t\t\t\t$nonDisableable.each(function () {\n\t\t\t\t\tthis.removeAttribute('disabled');\n\t\t\t\t\tthis.removeAttribute('aria-disabled');\n\t\t\t\t});\n\n\t\t\t\t// Set IDL attribute `disabled` to `false` and remove content attribute `aria-disabled`,\n\t\t\t\t// for disableable elements.\n\t\t\t\t$disableable.each(function () {\n\t\t\t\t\tthis.disabled = false;\n\t\t\t\t\tthis.removeAttribute('aria-disabled');\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaIsDisabled()` method.\n\t\t*/\n\t\tariaIsDisabled() {\n\t\t\t// Check content attribute `disabled`.\n\t\t\t//\n\t\t\t// NOTE: We simply check the `disabled` content attribute for all elements\n\t\t\t// since we have to check it for non-disableable elements and it may also\n\t\t\t// be used for disableable elements since their `disabled` IDL attribute\n\t\t\t// is required to reflect the status of their `disabled` content attribute,\n\t\t\t// and vice versa, by the HTML specification.\n\t\t\t// return this.toArray().some(el => el.hasAttribute('disabled'));\n\t\t\treturn this.is('[disabled]');\n\t\t}\n\t});\n})();\n\n/*\n\tWikifier methods plugin.\n\n\t`jQuery.wikiWithOptions(options, sources…)`\n\t    Wikifies the given content source(s), as directed by the given options.\n\n\t`jQuery.wiki(sources…)`\n\t    Wikifies the given content source(s).\n\n\t`<jQuery>.wikiWithOptions(options, sources…)`\n\t    Wikifies the given content source(s) and appends the result to the target\n\t    element(s), as directed by the given options.\n\n\t`<jQuery>.wiki(sources…)`\n\t    Wikifies the given content source(s) and appends the result to the target\n\t    element(s).\n*/\n(() => {\n\t'use strict';\n\n\tjQuery.extend({\n\t\t/*\n\t\t\tExtend jQuery's static methods with a `wikiWithOptions()` method.\n\t\t*/\n\t\twikiWithOptions(options, ...sources) {\n\t\t\t// Bail out, if there are no content sources.\n\t\t\tif (sources.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Wikify the content sources into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tsources.forEach(content => new Wikifier(frag, content, options));\n\n\t\t\t// Gather the text of any error elements within the fragment…\n\t\t\tconst errors = [...frag.querySelectorAll('.error')]\n\t\t\t\t.map(errEl => errEl.textContent.replace(errorPrologRegExp, ''));\n\n\t\t\t// …and throw an exception, if there were any errors.\n\t\t\tif (errors.length > 0) {\n\t\t\t\tthrow new Error(errors.join('; '));\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's static methods with a `wiki()` method.\n\t\t*/\n\t\twiki(...sources) {\n\t\t\tthis.wikiWithOptions(undefined, ...sources);\n\t\t}\n\t});\n\n\tjQuery.fn.extend({\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with a `wikiWithOptions()` method.\n\t\t*/\n\t\twikiWithOptions(options, ...sources) {\n\t\t\t// Bail out if there are no target element(s) or content sources.\n\t\t\tif (this.length === 0 || sources.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t// Wikify the content sources into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tsources.forEach(content => new Wikifier(frag, content, options));\n\n\t\t\t// Append the fragment to the target element(s).\n\t\t\tthis.append(frag);\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with a `wiki()` method.\n\t\t*/\n\t\twiki(...sources) {\n\t\t\treturn this.wikiWithOptions(undefined, ...sources);\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/util.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Has, Scripting */\n\nvar Util = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tType Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the value yielded by `typeof` (for primitives), the `@@toStringTag`\n\t\tinternal property (for objects), and `'null'` for `null`.\n\n\t\tNOTE: In ≤ES5, returns the value of the `[[Class]]` internal slot for objects.\n\t*/\n\tfunction utilGetType(obj) {\n\t\tif (obj === null) { return 'null'; }\n\n\t\tconst baseType = typeof obj;\n\t\treturn baseType === 'object'\n\t\t\t? Object.prototype.toString.call(obj).slice(8, -1)\n\t\t\t: baseType;\n\t}\n\n\t/*\n\t\tReturns whether the passed value is a boolean or one of the strings \"true\"\n\t\tor \"false\".\n\t*/\n\tfunction utilIsBoolean(obj) {\n\t\treturn typeof obj === 'boolean' || typeof obj === 'string' && (obj === 'true' || obj === 'false');\n\t}\n\n\t/*\n\t\tReturns whether the passed value is iterable.\n\t*/\n\tfunction utilIsIterable(obj) {\n\t\treturn obj != null && typeof obj[Symbol.iterator] === 'function'; // lazy equality for null\n\t}\n\n\t/*\n\t\tReturns whether the passed value is a finite number or a numeric string which\n\t\tyields a finite number when parsed.\n\t*/\n\tfunction utilIsNumeric(obj) {\n\t\tlet num;\n\n\t\tswitch (typeof obj) {\n\t\tcase 'number':\n\t\t\tnum = obj;\n\t\t\tbreak;\n\n\t\tcase 'string':\n\t\t\tnum = Number(obj);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !Number.isNaN(num) && Number.isFinite(num);\n\t}\n\n\t/*\n\t\tReturns whether the passed values pass a SameValueZero comparison.\n\n\t\tSEE: http://ecma-international.org/ecma-262/8.0/#sec-samevaluezero\n\t*/\n\tfunction utilSameValueZero(a, b) {\n\t\t/*\n\t\t\tNOTE: This comparison could also be implemented thus:\n\n\t\t\t\t```\n\t\t\t\ta === b ||\n\t\t\t\ttypeof a === 'number' && typeof b === 'number' &&\n\t\t\t\tNumber.isNaN(a) && Number.isNaN(b)\n\t\t\t\t```\n\n\t\t\tThat's needlessly verbose, however, as `NaN` is the only value in\n\t\t\tthe language which is not reflexive.\n\t\t*/\n\t\treturn a === b || a !== a && b !== b;\n\t}\n\n\t/*\n\t\tReturns a pseudo-enumeration created from the given Array, Map, Set, or generic object.\n\t*/\n\tfunction utilToEnum(obj) {\n\t\tconst pEnum = Object.create(null);\n\n\t\tif (obj instanceof Array) {\n\t\t\tobj.forEach((val, i) => pEnum[String(val)] = i);\n\t\t}\n\t\telse if (obj instanceof Set) {\n\t\t\t// NOTE: Use `<Array>.forEach()` here rather than `<Set>.forEach()`\n\t\t\t// as the latter does not provide the indices we require.\n\t\t\tArray.from(obj).forEach((val, i) => pEnum[String(val)] = i);\n\t\t}\n\t\telse if (obj instanceof Map) {\n\t\t\tobj.forEach((val, key) => pEnum[String(key)] = val);\n\t\t}\n\t\telse if (\n\t\t\t   typeof obj === 'object'\n\t\t\t&& obj !== null\n\t\t\t&& Object.getPrototypeOf(obj) === Object.prototype\n\t\t) {\n\t\t\tObject.assign(pEnum, obj);\n\t\t}\n\t\telse {\n\t\t\tthrow new TypeError('Util.toEnum obj parameter must be an Array, Map, Set, or generic object');\n\t\t}\n\n\t\treturn Object.freeze(pEnum);\n\t}\n\n\t/*\n\t\tReturns the value of the `@@toStringTag` property of the given object.\n\n\t\tNOTE: In ≤ES5, returns the value of the `[[Class]]` internal slot.\n\t*/\n\tfunction utilToStringTag(obj) {\n\t\treturn Object.prototype.toString.call(obj).slice(8, -1);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tString Encoding Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a trimmed and encoded slug of the passed string that should be safe\n\t\tfor use as a DOM ID or class name.\n\n\t\tNOTE: The range of illegal characters consists of: C0 controls, space, exclamation,\n\t\tdouble quote, number, dollar, percent, ampersand, single quote, left paren, right\n\t\tparen, asterisk, plus, comma, hyphen, period, forward slash, colon, semi-colon,\n\t\tless-than, equals, greater-than, question, at, left bracket, backslash, right\n\t\tbracket, caret, backquote/grave, left brace, pipe/vertical-bar, right brace, tilde,\n\t\tdelete, C1 controls.\n\t*/\n\tconst _illegalSlugCharsRe = /[\\x00-\\x20!-/:-@[-^`{-\\x9f]+/g; // eslint-disable-line no-control-regex\n\t/* legacy */\n\tconst _isInvalidSlugRe = /^-*$/; // Matches the empty string or one comprised solely of hyphens.\n\t/* /legacy */\n\n\tfunction utilSlugify(str) {\n\t\tconst base = String(str).trim();\n\n\t\t/* legacy */\n\t\tconst _legacy = base\n\t\t\t.replace(/[^\\w\\s\\u2013\\u2014-]+/g, '')\n\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-')\n\t\t\t.toLocaleLowerCase();\n\n\t\tif (!_isInvalidSlugRe.test(_legacy)) {\n\t\t\treturn _legacy;\n\t\t}\n\t\t/* /legacy */\n\n\t\treturn base\n\t\t\t.replace(_illegalSlugCharsRe, '')\n\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-');\n\n\t\t// For v3.\n\t\t// return base.replace(_illegalSlugCharsRe, '-');\n\t}\n\n\t/*\n\t\tReturns an entity encoded version of the passed string.\n\n\t\tNOTE: Only escapes the five primary special characters and the backquote.\n\t*/\n\tconst _htmlCharsRe    = /[&<>\"'`]/g;\n\tconst _hasHtmlCharsRe = new RegExp(_htmlCharsRe.source); // to drop the global flag\n\tconst _htmlCharsMap   = Object.freeze({\n\t\t'&' : '&amp;',\n\t\t'<' : '&lt;',\n\t\t'>' : '&gt;',\n\t\t'\"' : '&quot;',\n\t\t\"'\" : '&#39;',\n\t\t'`' : '&#96;'\n\t});\n\n\tfunction utilEscape(str) {\n\t\tif (str == null) { // lazy equality for null\n\t\t\treturn '';\n\t\t}\n\n\t\tconst val = String(str);\n\t\treturn val && _hasHtmlCharsRe.test(val)\n\t\t\t? val.replace(_htmlCharsRe, ch => _htmlCharsMap[ch])\n\t\t\t: val;\n\t}\n\n\t/*\n\t\tReturns a decoded version of the passed entity encoded string.\n\n\t\tNOTE: The extended replacement set here, in contrast to `utilEscape()`,\n\t\tis required due to observed stupidity from various sources.\n\t*/\n\tconst _escapedHtmlRe    = /&(?:amp|#38|#x26|lt|#60|#x3c|gt|#62|#x3e|quot|#34|#x22|apos|#39|#x27|#96|#x60);/gi;\n\tconst _hasEscapedHtmlRe = new RegExp(_escapedHtmlRe.source, 'i'); // to drop the global flag\n\tconst _escapedHtmlMap   = Object.freeze({\n\t\t'&amp;'  : '&', // ampersand (HTML character entity, XML predefined entity)\n\t\t'&#38;'  : '&', // ampersand (decimal numeric character reference)\n\t\t'&#x26;' : '&', // ampersand (hexadecimal numeric character reference)\n\t\t'&lt;'   : '<', // less-than (HTML character entity, XML predefined entity)\n\t\t'&#60;'  : '<', // less-than (decimal numeric character reference)\n\t\t'&#x3c;' : '<', // less-than (hexadecimal numeric character reference)\n\t\t'&gt;'   : '>', // greater-than (HTML character entity, XML predefined entity)\n\t\t'&#62;'  : '>', // greater-than (decimal numeric character reference)\n\t\t'&#x3e;' : '>', // greater-than (hexadecimal numeric character reference)\n\t\t'&quot;' : '\"', // double quote (HTML character entity, XML predefined entity)\n\t\t'&#34;'  : '\"', // double quote (decimal numeric character reference)\n\t\t'&#x22;' : '\"', // double quote (hexadecimal numeric character reference)\n\t\t'&apos;' : \"'\", // apostrophe (XML predefined entity)\n\t\t'&#39;'  : \"'\", // apostrophe (decimal numeric character reference)\n\t\t'&#x27;' : \"'\", // apostrophe (hexadecimal numeric character reference)\n\t\t'&#96;'  : '`', // backquote (decimal numeric character reference)\n\t\t'&#x60;' : '`'  // backquote (hexadecimal numeric character reference)\n\t});\n\n\tfunction utilUnescape(str) {\n\t\tif (str == null) { // lazy equality for null\n\t\t\treturn '';\n\t\t}\n\n\t\tconst val = String(str);\n\t\treturn val && _hasEscapedHtmlRe.test(val)\n\t\t\t? val.replace(_escapedHtmlRe, entity => _escapedHtmlMap[entity.toLowerCase()])\n\t\t\t: val;\n\t}\n\n\t/*\n\t\tReturns an object (`{ char, start, end }`) containing the Unicode character at\n\t\tposition `pos`, its starting position, and its ending position—surrogate pairs\n\t\tare properly handled.  If `pos` is out-of-bounds, returns an object containing\n\t\tthe empty string and start/end positions of `-1`.\n\n\t\tThis function is necessary because JavaScript strings are sequences of UTF-16\n\t\tcode units, so surrogate pairs are exposed and thus must be handled.  While the\n\t\tES6/2015 standard does improve the situation somewhat, it does not alleviate\n\t\tthe need for this function.\n\n\t\tNOTE: Returns the individual code units of invalid surrogate pairs as-is.\n\n\t\tIDEA: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt\n\t*/\n\tfunction utilCharAndPosAt(text, position) {\n\t\tconst str  = String(text);\n\t\tconst pos  = Math.trunc(position);\n\t\tconst code = str.charCodeAt(pos);\n\n\t\t// Given position was out-of-bounds.\n\t\tif (Number.isNaN(code)) {\n\t\t\treturn { char : '', start : -1, end : -1 };\n\t\t}\n\n\t\tconst retval = {\n\t\t\tchar  : str.charAt(pos),\n\t\t\tstart : pos,\n\t\t\tend   : pos\n\t\t};\n\n\t\t// Code unit is not a UTF-16 surrogate.\n\t\tif (code < 0xD800 || code > 0xDFFF) {\n\t\t\treturn retval;\n\t\t}\n\n\t\t// Code unit is a high surrogate (D800–DBFF).\n\t\tif (code >= 0xD800 && code <= 0xDBFF) {\n\t\t\tconst nextPos = pos + 1;\n\n\t\t\t// End of string.\n\t\t\tif (nextPos >= str.length) {\n\t\t\t\treturn retval;\n\t\t\t}\n\n\t\t\tconst nextCode = str.charCodeAt(nextPos);\n\n\t\t\t// Next code unit is not a low surrogate (DC00–DFFF).\n\t\t\tif (nextCode < 0xDC00 || nextCode > 0xDFFF) {\n\t\t\t\treturn retval;\n\t\t\t}\n\n\t\t\tretval.char = retval.char + str.charAt(nextPos);\n\t\t\tretval.end = nextPos;\n\t\t\treturn retval;\n\t\t}\n\n\t\t// Code unit is a low surrogate (DC00–DFFF) in the first position.\n\t\tif (pos === 0) {\n\t\t\treturn retval;\n\t\t}\n\n\t\tconst prevPos  = pos - 1;\n\t\tconst prevCode = str.charCodeAt(prevPos);\n\n\t\t// Previous code unit is not a high surrogate (D800–DBFF).\n\t\tif (prevCode < 0xD800 || prevCode > 0xDBFF) {\n\t\t\treturn retval;\n\t\t}\n\n\t\tretval.char = str.charAt(prevPos) + retval.char;\n\t\tretval.start = prevPos;\n\t\treturn retval;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTime Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the number of milliseconds elapsed since a reference epoch.\n\n\t\tNOTE: Use the Performance API, if available, elsewise use Date as a\n\t\tfailover.  The Performance API is preferred for its monotonic clock—\n\t\tmeaning, it's not subject to the vagaries of timezone changes and leap\n\t\tperiods, as is Date.\n\t*/\n\tconst _nowSource = Has.performance ? performance : Date;\n\n\tfunction utilNow() {\n\t\treturn _nowSource.now();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tConversion Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the number of miliseconds represented by the passed CSS time string.\n\t*/\n\tconst _cssTimeRe = /^([+-]?(?:\\d*\\.)?\\d+)([Mm]?[Ss])$/;\n\n\tfunction utilFromCssTime(cssTime) {\n\t\tconst match = _cssTimeRe.exec(String(cssTime));\n\n\t\tif (match === null) {\n\t\t\tthrow new SyntaxError(`invalid time value syntax: \"${cssTime}\"`);\n\t\t}\n\n\t\tlet msec = Number(match[1]);\n\n\t\tif (match[2].length === 1) {\n\t\t\tmsec *= 1000;\n\t\t}\n\n\t\tif (Number.isNaN(msec) || !Number.isFinite(msec)) {\n\t\t\tthrow new RangeError(`invalid time value: \"${cssTime}\"`);\n\t\t}\n\n\t\treturn msec;\n\t}\n\n\t/*\n\t\tReturns the CSS time string represented by the passed number of milliseconds.\n\t*/\n\tfunction utilToCssTime(msec) {\n\t\tif (typeof msec !== 'number' || Number.isNaN(msec) || !Number.isFinite(msec)) {\n\t\t\tlet what;\n\n\t\t\tswitch (typeof msec) {\n\t\t\tcase 'string':\n\t\t\t\twhat = `\"${msec}\"`;\n\t\t\t\tbreak;\n\n\t\t\tcase 'number':\n\t\t\t\twhat = String(msec);\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\twhat = utilToStringTag(msec);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tthrow new Error(`invalid milliseconds: ${what}`);\n\t\t}\n\n\t\treturn `${msec}ms`;\n\t}\n\n\t/*\n\t\tReturns the DOM property name represented by the passed CSS property name.\n\t*/\n\tfunction utilFromCssProperty(cssName) {\n\t\tif (!cssName.includes('-')) {\n\t\t\tswitch (cssName) {\n\t\t\tcase 'bgcolor': return 'backgroundColor';\n\t\t\tcase 'float':   return 'cssFloat';\n\t\t\tdefault:        return cssName;\n\t\t\t}\n\t\t}\n\n\t\t// Strip the leading hyphen from the `-ms-` vendor prefix, so it stays lowercased.\n\t\tconst normalized = cssName.slice(0, 4) === '-ms-' ? cssName.slice(1) : cssName;\n\n\t\treturn normalized\n\t\t\t.split('-')\n\t\t\t.map((part, i) => i === 0 ? part : part.toUpperFirst())\n\t\t\t.join('');\n\t}\n\n\t/*\n\t\tReturns an object containing the component properties parsed from the passed URL.\n\t*/\n\tfunction utilParseUrl(url) {\n\t\tconst el       = document.createElement('a');\n\t\tconst queryObj = Object.create(null);\n\n\t\t// Let the `<a>` element parse the URL.\n\t\tel.href = url;\n\n\t\t// Populate the `queryObj` object with the query string attributes.\n\t\tif (el.search) {\n\t\t\tel.search\n\t\t\t\t.replace(/^\\?/, '')\n\t\t\t\t.splitOrEmpty(/(?:&(?:amp;)?|;)/)\n\t\t\t\t.forEach(query => {\n\t\t\t\t\tconst [key, value] = query.split('=');\n\t\t\t\t\tqueryObj[key] = value;\n\t\t\t\t});\n\t\t}\n\n\t\t/*\n\t\t\tCaveats by browser:\n\t\t\t\tEdge and Internet Explorer (≥8) do not support authentication\n\t\t\t\tinformation within a URL at all and will throw a security exception\n\t\t\t\ton *any* property access if it's included.\n\n\t\t\t\tInternet Explorer does not include the leading forward slash on\n\t\t\t\t`pathname` when required.\n\n\t\t\t\tOpera (Presto) strips the authentication information from `href`\n\t\t\t\tand does not supply `username` or `password`.\n\n\t\t\t\tSafari (ca. v5.1.x) does not supply `username` or `password` and\n\t\t\t\tpeforms URI decoding on `pathname`.\n\t\t*/\n\n\t\t// Patch for IE not including the leading slash on `pathname` when required.\n\t\tconst pathname = el.host && el.pathname[0] !== '/' ? `/${el.pathname}` : el.pathname;\n\n\t\treturn {\n\t\t\t// The full URL that was originally parsed.\n\t\t\thref : el.href,\n\n\t\t\t// The request protocol, lowercased.\n\t\t\tprotocol : el.protocol,\n\n\t\t\t// // The full authentication information.\n\t\t\t// auth : el.username || el.password // eslint-disable-line no-nested-ternary\n\t\t\t// \t? `${el.username}:${el.password}`\n\t\t\t// \t: typeof el.username === 'string' ? '' : undefined,\n\t\t\t//\n\t\t\t// // The username portion of the auth info.\n\t\t\t// username : el.username,\n\t\t\t//\n\t\t\t// // The password portion of the auth info.\n\t\t\t// password : el.password,\n\n\t\t\t// The full host information, including port number, lowercased.\n\t\t\thost : el.host,\n\n\t\t\t// The hostname portion of the host info, lowercased.\n\t\t\thostname : el.hostname,\n\n\t\t\t// The port number portion of the host info.\n\t\t\tport : el.port,\n\n\t\t\t// The full path information, including query info.\n\t\t\tpath : `${pathname}${el.search}`,\n\n\t\t\t// The pathname portion of the path info.\n\t\t\tpathname,\n\n\t\t\t// The query string portion of the path info, including the leading question mark.\n\t\t\tquery  : el.search,\n\t\t\tsearch : el.search,\n\n\t\t\t// The attributes portion of the query string, parsed into an object.\n\t\t\tqueries  : queryObj,\n\t\t\tsearches : queryObj,\n\n\t\t\t// The fragment string, including the leading hash/pound sign.\n\t\t\thash : el.hash\n\t\t};\n\t}\n\n\t/*\n\t\tReturns a new exception based on the given exception.\n\n\t\tNOTE: Mostly useful for making a standard JavaScript exception type copy\n\t\tof a host exception type—e.g. `DOMException` → `Error`.\n\t*/\n\tfunction utilNewExceptionFrom(original, exceptionType, override) {\n\t\tif (typeof original !== 'object' || original === null) {\n\t\t\tthrow new Error('Util.newExceptionFrom original parameter must be an object');\n\t\t}\n\t\tif (typeof exceptionType !== 'function') {\n\t\t\tthrow new Error('Util.newExceptionFrom exceptionType parameter must be an error type constructor');\n\t\t}\n\n\t\tconst ex = new exceptionType(original.message); // eslint-disable-line new-cap\n\n\t\tif (typeof original.name !== 'undefined') {\n\t\t\tex.name = original.name;\n\t\t}\n\t\tif (typeof original.code !== 'undefined') {\n\t\t\tex.code = original.code;\n\t\t}\n\t\tif (typeof original.columnNumber !== 'undefined') {\n\t\t\tex.columnNumber = original.columnNumber;\n\t\t}\n\t\tif (typeof original.description !== 'undefined') {\n\t\t\tex.description = original.description;\n\t\t}\n\t\tif (typeof original.fileName !== 'undefined') {\n\t\t\tex.fileName = original.fileName;\n\t\t}\n\t\tif (typeof original.lineNumber !== 'undefined') {\n\t\t\tex.lineNumber = original.lineNumber;\n\t\t}\n\t\tif (typeof original.number !== 'undefined') {\n\t\t\tex.number = original.number;\n\t\t}\n\t\tif (typeof original.stack !== 'undefined') {\n\t\t\tex.stack = original.stack;\n\t\t}\n\n\t\tconst overrideType = typeof override;\n\n\t\tif (overrideType !== 'undefined') {\n\t\t\tif (overrideType === 'object' && override !== null) {\n\t\t\t\tObject.assign(ex, override);\n\t\t\t}\n\t\t\telse if (overrideType === 'string') {\n\t\t\t\tex.message = override;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('Util.newExceptionFrom override parameter must be an object or string');\n\t\t\t}\n\t\t}\n\n\t\treturn ex;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tType Functions.\n\t\t*/\n\t\tgetType       : { value : utilGetType },\n\t\tisBoolean     : { value : utilIsBoolean },\n\t\tisIterable    : { value : utilIsIterable },\n\t\tisNumeric     : { value : utilIsNumeric },\n\t\tsameValueZero : { value : utilSameValueZero },\n\t\ttoEnum        : { value : utilToEnum },\n\t\ttoStringTag   : { value : utilToStringTag },\n\n\t\t/*\n\t\t\tString Encoding Functions.\n\t\t*/\n\t\tslugify      : { value : utilSlugify },\n\t\tescape       : { value : utilEscape },\n\t\tunescape     : { value : utilUnescape },\n\t\tcharAndPosAt : { value : utilCharAndPosAt },\n\n\t\t/*\n\t\t\tConversion Functions.\n\t\t*/\n\t\tfromCssTime      : { value : utilFromCssTime },\n\t\ttoCssTime        : { value : utilToCssTime },\n\t\tfromCssProperty  : { value : utilFromCssProperty },\n\t\tparseUrl         : { value : utilParseUrl },\n\t\tnewExceptionFrom : { value : utilNewExceptionFrom },\n\n\t\t/*\n\t\t\tTime Functions.\n\t\t*/\n\t\tnow : { value : utilNow },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\trandom         : { value : Math.random },\n\t\tentityEncode   : { value : utilEscape },\n\t\tentityDecode   : { value : utilUnescape },\n\t\tevalExpression : { value : (...args) => Scripting.evalJavaScript(...args) }, // SEE: `markup/scripting.js`.\n\t\tevalStatements : { value : (...args) => Scripting.evalJavaScript(...args) }  // SEE: `markup/scripting.js`.\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/simplestore.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar SimpleStore = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// In-order list of database adapters.\n\tconst _adapters = [];\n\n\t// The initialized adapter.\n\tlet _initialized = null;\n\n\n\t/*******************************************************************************************************************\n\t\tSimpleStore Functions.\n\t*******************************************************************************************************************/\n\tfunction storeCreate(storageId, persistent) {\n\t\tif (_initialized) {\n\t\t\treturn _initialized.create(storageId, persistent);\n\t\t}\n\n\t\t// Return the first adapter which successfully initializes, elsewise throw an exception.\n\t\tfor (let i = 0; i < _adapters.length; ++i) {\n\t\t\tif (_adapters[i].init(storageId, persistent)) {\n\t\t\t\t_initialized = _adapters[i];\n\t\t\t\treturn _initialized.create(storageId, persistent);\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error('no valid storage adapters found');\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tAdapters List.\n\n\t\t\tTODO: This should probably have a getter, rather than being exported directly.\n\t\t*/\n\t\tadapters : { value : _adapters },\n\n\t\t/*\n\t\t\tCore Functions.\n\t\t*/\n\t\tcreate : { value : storeCreate }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/FCHost.Storage.js\n\n\tCopyright © 2013–2019 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_FCHostStorageAdapter Class.\n        Note that FCHost is only intended for a single document, so we ignore both prefixing and storageID\n\t*******************************************************************************************************************/\n\tclass _FCHostStorageAdapter {\n\t\tconstructor(persistent) {\n\t\t\tlet engine = null;\n\t\t\tlet name   = null;\n\n\t\t\tif (persistent) {\n\t\t\t\tengine = window.FCHostPersistent;\n\t\t\t\tname   = 'FCHostPersistent';\n\t\t\t}\n\t\t\telse {\n\t\t\t    engine = window.FCHostSession;\n\t\t\t\tname   = 'FCHostSession';\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_engine : {\n\t\t\t\t\tvalue : engine\n\t\t\t\t},\n                \n\t\t\t\tname : {\n\t\t\t\t\tvalue : name\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\treturn this._engine.size();\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\treturn this._engine.size();\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\treturn this._engine.keys();\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn this._engine.has(key);\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = this._engine.get(key);\n\n\t\t\treturn value == null ? null : _FCHostStorageAdapter._deserialize(value); // lazy equality for null\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.set(key, _FCHostStorageAdapter._serialize(value));\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.remove(key);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tthis._engine.clear();\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn JSON.stringify(obj);\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse(str);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit() {\n\t\t// FCHost feature test.\n\t\tfunction hasFCHostStorage() {\n\t\t\ttry {\n\t\t\t    if (typeof window.FCHostPersistent !== 'undefined')\n\t\t\t        return true;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn false;\n\t\t}\n\n\t\t_ok = hasFCHostStorage();\n\t\t\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _FCHostStorageAdapter(persistent);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/webstorage.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_WebStorageAdapter Class.\n\t*******************************************************************************************************************/\n\tclass _WebStorageAdapter {\n\t\tconstructor(storageId, persistent) {\n\t\t\tconst prefix = `${storageId}.`;\n\t\t\tlet engine = null;\n\t\t\tlet name   = null;\n\n\t\t\tif (persistent) {\n\t\t\t\tengine = window.localStorage;\n\t\t\t\tname   = 'localStorage';\n\t\t\t}\n\t\t\telse {\n\t\t\t\tengine = window.sessionStorage;\n\t\t\t\tname   = 'sessionStorage';\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_engine : {\n\t\t\t\t\tvalue : engine\n\t\t\t\t},\n\n\t\t\t\t_prefix : {\n\t\t\t\t\tvalue : prefix\n\t\t\t\t},\n\n\t\t\t\t_prefixRe : {\n\t\t\t\t\tvalue : new RegExp(`^${RegExp.escape(prefix)}`)\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : name\n\t\t\t\t},\n\n\t\t\t\tid : {\n\t\t\t\t\tvalue : storageId\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\t/*\n\t\t\t\tNOTE: DO NOT do something like `return this._engine.length;` here,\n\t\t\t\tas that will return the length of the entire store, rather than\n\t\t\t\tjust our prefixed keys.\n\t\t\t*/\n\t\t\treturn this.keys().length;\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\t/*\n\t\t\t\tNOTE: DO NOT do something like `return this._engine.length;` here,\n\t\t\t\tas that will return the length of the entire store, rather than\n\t\t\t\tjust our prefixed keys.\n\t\t\t*/\n\t\t\treturn this.keys().length;\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\tconst keys = [];\n\n\t\t\tfor (let i = 0; i < this._engine.length; ++i) {\n\t\t\t\tconst key = this._engine.key(i);\n\n\t\t\t\tif (this._prefixRe.test(key)) {\n\t\t\t\t\tkeys.push(key.replace(this._prefixRe, ''));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn keys;\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// // FIXME: This method should probably check for the key, rather than comparing its value.\n\t\t\t// return this._engine.getItem(this._prefix + key) != null; // lazy equality for null\n\n\t\t\treturn this._engine.hasOwnProperty(this._prefix + key);\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = this._engine.getItem(this._prefix + key);\n\n\t\t\treturn value == null ? null : _WebStorageAdapter._deserialize(value); // lazy equality for null\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tthis._engine.setItem(this._prefix + key, _WebStorageAdapter._serialize(value));\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t/*\n\t\t\t\t\tIf the exception is a quota exceeded error, massage it into something\n\t\t\t\t\ta bit nicer for the player.\n\n\t\t\t\t\tNOTE: Ideally, we could simply do something like checking `ex.code`, but\n\t\t\t\t\tit's a non-standard property and not supported in all browsers.  Thus,\n\t\t\t\t\twe have to resort to pattern matching the name and message—the latter being\n\t\t\t\t\trequired by Opera (Presto).  I hate the parties responsible for this snafu\n\t\t\t\t\tso much.\n\t\t\t\t*/\n\t\t\t\tif (/quota.?(?:exceeded|reached)/i.test(ex.name + ex.message)) {\n\t\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `${this.name} quota exceeded`);\n\t\t\t\t}\n\n\t\t\t\tthrow ex;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.removeItem(this._prefix + key);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tconst keys = this.keys();\n\n\t\t\tfor (let i = 0, iend = keys.length; i < iend; ++i) {\n\t\t\t\tif (DEBUG) { console.log('\\tdeleting key:', keys[i]); }\n\n\t\t\t\tthis.delete(keys[i]);\n\t\t\t}\n\n\t\t\t// return this.keys().forEach(key => {\n\t\t\t// \tif (DEBUG) { console.log('\\tdeleting key:', key); }\n\t\t\t//\n\t\t\t// \tthis.delete(key);\n\t\t\t// });\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn JSON.stringify(obj);\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse((!str || str[0] == \"{\") ? str : LZString.decompressFromUTF16(str));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit() {\n\t\t// Web Storage feature test.\n\t\tfunction hasWebStorage(storeId) {\n\t\t\ttry {\n\t\t\t\tconst store = window[storeId];\n\t\t\t\tconst tid   = `_sc_${String(Date.now())}`;\n\t\t\t\tstore.setItem(tid, tid);\n\t\t\t\tconst result = store.getItem(tid) === tid;\n\t\t\t\tstore.removeItem(tid);\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn false;\n\t\t}\n\n\t\t/*\n\t\t\tJust to be safe, we feature test for both `localStorage` and `sessionStorage`,\n\t\t\tas you never know what browser implementation bugs you're going to run into.\n\t\t*/\n\t\t_ok = hasWebStorage('localStorage') && hasWebStorage('sessionStorage');\n\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _WebStorageAdapter(storageId, persistent);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/cookie.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Expiry constants.\n\tconst _MAX_EXPIRY = 'Tue, 19 Jan 2038 03:14:07 GMT'; // (new Date((Math.pow(2, 31) - 1) * 1000)).toUTCString()\n\tconst _MIN_EXPIRY = 'Thu, 01 Jan 1970 00:00:00 GMT'; // (new Date(0)).toUTCString()\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_CookieAdapter Class.\n\t*******************************************************************************************************************/\n\tclass _CookieAdapter {\n\t\tconstructor(storageId, persistent) {\n\t\t\tconst prefix = `${storageId}${persistent ? '!' : '*'}.`;\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_prefix : {\n\t\t\t\t\tvalue : prefix\n\t\t\t\t},\n\n\t\t\t\t_prefixRe : {\n\t\t\t\t\tvalue : new RegExp(`^${RegExp.escape(prefix)}`)\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : 'cookie'\n\t\t\t\t},\n\n\t\t\t\tid : {\n\t\t\t\t\tvalue : storageId\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\treturn this.keys().length;\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\treturn this.keys().length;\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\tif (document.cookie === '') {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst cookies = document.cookie.split(/;\\s*/);\n\t\t\tconst keys    = [];\n\n\t\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\t\tif (this._prefixRe.test(key)) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\t\tnot a serialized empty string, so we should omit such pairs.\n\t\t\t\t\t*/\n\t\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\t\tif (value !== '') {\n\t\t\t\t\t\tkeys.push(key.replace(this._prefixRe, ''));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn keys;\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn _CookieAdapter._getCookie(this._prefix + key) !== null;\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = _CookieAdapter._getCookie(this._prefix + key);\n\n\t\t\treturn value === null ? null : _CookieAdapter._deserialize(value);\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\tthis._prefix + key,\n\t\t\t\t\t_CookieAdapter._serialize(value),\n\n\t\t\t\t\t// An undefined expiry denotes a session cookie.\n\t\t\t\t\tthis.persistent ? _MAX_EXPIRY : undefined\n\t\t\t\t);\n\n\t\t\t\tif (!this.has(key)) {\n\t\t\t\t\tthrow new Error('unknown validation error during set');\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t// Massage the cookie exception into something a bit nicer for the player.\n\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `cookie error: ${ex.message}`);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\t/*\n\t\t\t\tAttempting to delete a cookie implies setting it, so we test for its existence\n\t\t\t\tbeforehand, to avoid creating it in the event that it does not already exist.\n\t\t\t*/\n\t\t\tif (typeof key !== 'string' || !key || !this.has(key)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\tthis._prefix + key,\n\n\t\t\t\t\t// Use `undefined` as the value.\n\t\t\t\t\tundefined,\n\n\t\t\t\t\t// Use the epoch as the expiry.\n\t\t\t\t\t_MIN_EXPIRY\n\t\t\t\t);\n\n\t\t\t\tif (this.has(key)) {\n\t\t\t\t\tthrow new Error('unknown validation error during delete');\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t// Massage the cookie exception into something a bit nicer for the player.\n\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `cookie error: ${ex.message}`);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tconst keys = this.keys();\n\n\t\t\tfor (let i = 0, iend = keys.length; i < iend; ++i) {\n\t\t\t\tif (DEBUG) { console.log('\\tdeleting key:', keys[i]); }\n\n\t\t\t\tthis.delete(keys[i]);\n\t\t\t}\n\n\t\t\t// this.keys().forEach(key => {\n\t\t\t// \tif (DEBUG) { console.log('\\tdeleting key:', key); }\n\t\t\t//\n\t\t\t// \tthis.delete(key);\n\t\t\t// });\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _getCookie(prefixedKey) {\n\t\t\tif (!prefixedKey || document.cookie === '') {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst cookies = document.cookie.split(/;\\s*/);\n\n\t\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\t\tif (prefixedKey === key) {\n\t\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\t\tnot a serialized empty string, so we should yield `null` for such pairs.\n\t\t\t\t\t*/\n\t\t\t\t\treturn value || null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tstatic _setCookie(prefixedKey, value, expiry) {\n\t\t\tif (!prefixedKey) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet payload = `${encodeURIComponent(prefixedKey)}=`;\n\n\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\tpayload += encodeURIComponent(value);\n\t\t\t}\n\n\t\t\tif (expiry != null) { // lazy equality for null\n\t\t\t\tpayload += `; expires=${expiry}`;\n\t\t\t}\n\n\t\t\tpayload += '; path=/';\n\t\t\tdocument.cookie = payload;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn LZString.compressToBase64(JSON.stringify(obj));\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse(LZString.decompressFromBase64(str));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit(\n\t\t// Only used for stores updates.\n\t\tstorageId\n\t) {\n\t\t// Cookie feature test.\n\t\ttry {\n\t\t\tconst tid = `_sc_${String(Date.now())}`;\n\n\t\t\t// We only test a session cookie as that should suffice.\n\t\t\t_CookieAdapter._setCookie(tid, _CookieAdapter._serialize(tid), undefined);\n\t\t\t_ok = _CookieAdapter._deserialize(_CookieAdapter._getCookie(tid)) === tid;\n\t\t\t_CookieAdapter._setCookie(tid, undefined, _MIN_EXPIRY);\n\t\t}\n\t\tcatch (ex) {\n\t\t\t_ok = false;\n\t\t}\n\n\t\t/* legacy */\n\t\t// Attempt to update the cookie stores, if necessary.  This should happen only during initialization.\n\t\tif (_ok) {\n\t\t\t_updateCookieStores(storageId);\n\t\t}\n\t\t/* /legacy */\n\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _CookieAdapter(storageId, persistent);\n\t}\n\n\t/* legacy */\n\t// Updates old non-segmented cookie stores into segmented stores.\n\tfunction _updateCookieStores(storageId) {\n\t\tif (document.cookie === '') {\n\t\t\treturn;\n\t\t}\n\n\t\tconst oldPrefix     = `${storageId}.`;\n\t\tconst oldPrefixRe   = new RegExp(`^${RegExp.escape(oldPrefix)}`);\n\t\tconst persistPrefix = `${storageId}!.`;\n\t\tconst sessionPrefix = `${storageId}*.`;\n\t\tconst sessionTestRe = /\\.(?:state|rcWarn)$/;\n\t\tconst cookies       = document.cookie.split(/;\\s*/);\n\n\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\tif (oldPrefixRe.test(key)) {\n\t\t\t\t/*\n\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\tnot a serialized empty string, so we should skip processing such pairs.\n\t\t\t\t*/\n\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\tif (value !== '') {\n\t\t\t\t\tconst persist = !sessionTestRe.test(key);\n\n\t\t\t\t\t// Delete the old k/v pair.\n\t\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t_MIN_EXPIRY\n\t\t\t\t\t);\n\n\t\t\t\t\t// Set the new k/v pair.\n\t\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\t\tkey.replace(oldPrefixRe, () => persist ? persistPrefix : sessionPrefix),\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tpersist ? _MAX_EXPIRY : undefined\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t/* /legacy */\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/debugview.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tTODO: Make this use jQuery throughout.\n*/\nvar DebugView = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tDebugView Class.\n\t*******************************************************************************************************************/\n\tclass DebugView {\n\t\tconstructor(parent, type, name, title) {\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tparent : {\n\t\t\t\t\tvalue : parent\n\t\t\t\t},\n\n\t\t\t\tview : {\n\t\t\t\t\tvalue : document.createElement('span')\n\t\t\t\t},\n\n\t\t\t\tbreak : {\n\t\t\t\t\tvalue : document.createElement('wbr')\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Set up the wrapper (`<span>`) element.\n\t\t\tjQuery(this.view)\n\t\t\t\t.attr({\n\t\t\t\t\ttitle,\n\t\t\t\t\t'aria-label' : title,\n\t\t\t\t\t'data-type'  : type != null ? type : '', // lazy equality for null\n\t\t\t\t\t'data-name'  : name != null ? name : ''  // lazy equality for null\n\t\t\t\t})\n\t\t\t\t.addClass('debug');\n\n\t\t\t// Set up the word break (`<wbr>`) element.\n\t\t\tjQuery(this.break).addClass('debug hidden');\n\n\t\t\t// Add the wrapper (`<span>`) and word break (`<wbr>`) elements to the `parent` element.\n\t\t\tthis.parent.appendChild(this.view);\n\t\t\tthis.parent.appendChild(this.break);\n\t\t}\n\n\t\tget output() {\n\t\t\treturn this.view;\n\t\t}\n\n\t\tget type() {\n\t\t\treturn this.view.getAttribute('data-type');\n\t\t}\n\t\tset type(type) {\n\t\t\tthis.view.setAttribute('data-type', type != null ? type : ''); // lazy equality for null\n\t\t}\n\n\t\tget name() {\n\t\t\treturn this.view.getAttribute('data-name');\n\t\t}\n\t\tset name(name) {\n\t\t\tthis.view.setAttribute('data-name', name != null ? name : ''); // lazy equality for null\n\t\t}\n\n\t\tget title() {\n\t\t\treturn this.view.title;\n\t\t}\n\t\tset title(title) {\n\t\t\tthis.view.title = title;\n\t\t}\n\n\t\tappend(el) {\n\t\t\tjQuery(this.view).append(el);\n\t\t\treturn this;\n\t\t}\n\n\t\tmodes(options) {\n\t\t\tif (options == null) { // lazy equality for null\n\t\t\t\tconst current = {};\n\n\t\t\t\tthis.view.className.splitOrEmpty(/\\s+/).forEach(name => {\n\t\t\t\t\tif (name !== 'debug') {\n\t\t\t\t\t\tcurrent[name] = true;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\treturn current;\n\t\t\t}\n\t\t\telse if (typeof options === 'object') {\n\t\t\t\tObject.keys(options).forEach(function (name) {\n\t\t\t\t\tthis[options[name] ? 'addClass' : 'removeClass'](name);\n\t\t\t\t}, jQuery(this.view));\n\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tthrow new Error('DebugView.prototype.modes options parameter must be an object or null/undefined');\n\t\t}\n\n\t\tremove() {\n\t\t\tconst $view = jQuery(this.view);\n\n\t\t\tif (this.view.hasChildNodes()) {\n\t\t\t\t$view.contents().appendTo(this.parent);\n\t\t\t}\n\n\t\t\t$view.remove();\n\t\t\tjQuery(this.break).remove();\n\t\t}\n\n\t\tstatic isEnabled() {\n\t\t\treturn jQuery(document.documentElement).attr('data-debug-view') === 'enabled';\n\t\t}\n\n\t\tstatic enable() {\n\t\t\tjQuery(document.documentElement).attr('data-debug-view', 'enabled');\n\t\t\tjQuery.event.trigger(':debugviewupdate');\n\t\t}\n\n\t\tstatic disable() {\n\t\t\tjQuery(document.documentElement).removeAttr('data-debug-view');\n\t\t\tjQuery.event.trigger(':debugviewupdate');\n\t\t}\n\n\t\tstatic toggle() {\n\t\t\tif (jQuery(document.documentElement).attr('data-debug-view') === 'enabled') {\n\t\t\t\tDebugView.disable();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tDebugView.enable();\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn DebugView;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/prngwrapper.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar PRNGWrapper = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tPRNGWrapper Class.\n\t*******************************************************************************************************************/\n\tclass PRNGWrapper {\n\t\tconstructor(seed, useEntropy) {\n\t\t\t/* eslint-disable new-cap */\n\t\t\tObject.defineProperties(this, new Math.seedrandom(seed, useEntropy, (prng, seed) => ({\n\t\t\t\t_prng : {\n\t\t\t\t\tvalue : prng\n\t\t\t\t},\n\n\t\t\t\tseed : {\n\t\t\t\t\t/*\n\t\t\t\t\t\tTODO: Make this non-writable.\n\t\t\t\t\t*/\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : seed\n\t\t\t\t},\n\n\t\t\t\tpull : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\trandom : {\n\t\t\t\t\tvalue() {\n\t\t\t\t\t\t++this.pull;\n\t\t\t\t\t\treturn this._prng();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})));\n\t\t\t/* eslint-enable new-cap */\n\t\t}\n\n\t\tstatic marshal(prng) {\n\t\t\tif (!prng || !prng.hasOwnProperty('seed') || !prng.hasOwnProperty('pull')) {\n\t\t\t\tthrow new Error('PRNG is missing required data');\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tseed : prng.seed,\n\t\t\t\tpull : prng.pull\n\t\t\t};\n\t\t}\n\n\t\tstatic unmarshal(prngObj) {\n\t\t\tif (!prngObj || !prngObj.hasOwnProperty('seed') || !prngObj.hasOwnProperty('pull')) {\n\t\t\t\tthrow new Error('PRNG object is missing required data');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tCreate a new PRNG using the original seed and pull values from it until it\n\t\t\t\thas reached the original pull count.\n\t\t\t*/\n\t\t\tconst prng = new PRNGWrapper(prngObj.seed, false);\n\n\t\t\tfor (let i = prngObj.pull; i > 0; --i) {\n\t\t\t\tprng.random();\n\t\t\t}\n\n\t\t\treturn prng;\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn PRNGWrapper;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/stylewrapper.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns, Story, Wikifier */\n\nvar StyleWrapper = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tconst _imageMarkupRe    = new RegExp(Patterns.cssImage, 'g');\n\tconst _hasImageMarkupRe = new RegExp(Patterns.cssImage);\n\n\n\t/*******************************************************************************************************************\n\t\tStyleWrapper Class.\n\t*******************************************************************************************************************/\n\tclass StyleWrapper {\n\t\tconstructor(style) {\n\t\t\tif (style == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('StyleWrapper style parameter must be an HTMLStyleElement object');\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tstyle : {\n\t\t\t\t\tvalue : style\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tisEmpty() {\n\t\t\t// This should work in all supported browsers.\n\t\t\treturn this.style.cssRules.length === 0;\n\t\t}\n\n\t\tset(rawCss) {\n\t\t\tthis.clear();\n\t\t\tthis.add(rawCss);\n\t\t}\n\n\t\tadd(rawCss) {\n\t\t\tlet css = rawCss;\n\n\t\t\t// Check for wiki image transclusion.\n\t\t\tif (_hasImageMarkupRe.test(css)) {\n\t\t\t\t/*\n\t\t\t\t\tThe JavaScript specifications, since at least ES3, say that `<String>.replace()`\n\t\t\t\t\tshould reset a global-flagged regular expression's `lastIndex` property to `0`\n\t\t\t\t\tupon invocation.  Buggy browser versions exist, however, which do not reset\n\t\t\t\t\t`lastIndex`, so we should do so manually to support those browsers.\n\n\t\t\t\t\tNOTE: I do not think this is actually necessary, since `_imageMarkupRe` is\n\t\t\t\t\tscoped to this module—meaning users should not be able to access it.  That\n\t\t\t\t\tbeing the case, and since we search to exhaustion which should also cause\n\t\t\t\t\t`lastIndex` to be reset, there should never be an instance where we invoke\n\t\t\t\t\t`css.replace()` and `_imageMarkupRe.lastIndex` is not already `0`.  Still,\n\t\t\t\t\tconsidering the other bug, better safe than sorry.\n\t\t\t\t*/\n\t\t\t\t_imageMarkupRe.lastIndex = 0;\n\n\t\t\t\tcss = css.replace(_imageMarkupRe, wikiImage => {\n\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\tsource     : wikiImage,\n\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t});\n\n\t\t\t\t\tif (markup.hasOwnProperty('error') || markup.pos < wikiImage.length) {\n\t\t\t\t\t\treturn wikiImage;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet source = markup.source;\n\n\t\t\t\t\t// Handle image passage transclusion.\n\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\tsource = passage.text.trim();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tThe source may be URI- or Base64-encoded, so we cannot use `encodeURIComponent()`\n\t\t\t\t\t\there.  Instead, we simply encode any double quotes, since the URI will be\n\t\t\t\t\t\tdelimited by them.\n\t\t\t\t\t*/\n\t\t\t\t\treturn `url(\"${source.replace(/\"/g, '%22')}\")`;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// For IE ≤ 10.\n\t\t\tif (this.style.styleSheet) {\n\t\t\t\tthis.style.styleSheet.cssText += css;\n\t\t\t}\n\n\t\t\t// For all other browsers (incl. IE ≥ 11).\n\t\t\telse {\n\t\t\t\tthis.style.appendChild(document.createTextNode(css));\n\t\t\t}\n\t\t}\n\n\t\tclear() {\n\t\t\t// For IE ≤10.\n\t\t\tif (this.style.styleSheet) {\n\t\t\t\tthis.style.styleSheet.cssText = '';\n\t\t\t}\n\n\t\t\t// For all other browsers (incl. IE ≥11).\n\t\t\telse {\n\t\t\t\tjQuery(this.style).empty();\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn StyleWrapper;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/diff.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util, clone */\n\nvar Diff = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tDiff Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tDiff operations object (pseudo-enumeration).\n\t*/\n\tconst Op = Util.toEnum({\n\t\tDelete      : 0,\n\t\tSpliceArray : 1,\n\t\tCopy        : 2,\n\t\tCopyDate    : 3\n\t});\n\n\t/*\n\t\tReturns a difference object generated from comparing the the orig and dest objects.\n\t*/\n\tfunction diff(orig, dest) /* diff object */ {\n\t\tconst objToString = Object.prototype.toString;\n\t\tconst origIsArray = orig instanceof Array;\n\t\tconst keys        = []\n\t\t\t.concat(Object.keys(orig), Object.keys(dest))\n\t\t\t.sort()\n\t\t\t.filter((val, i, arr) => i === 0 || arr[i - 1] !== val);\n\t\tconst diffed      = {};\n\t\tlet aOpRef;\n\n\t\tconst keyIsAOpRef = key => key === aOpRef;\n\n\t\t/* eslint-disable max-depth */\n\t\tfor (let i = 0, klen = keys.length; i < klen; ++i) {\n\t\t\tconst key   = keys[i];\n\t\t\tconst origP = orig[key];\n\t\t\tconst destP = dest[key];\n\n\t\t\tif (orig.hasOwnProperty(key)) {\n\t\t\t\t// Key exists in both.\n\t\t\t\tif (dest.hasOwnProperty(key)) {\n\t\t\t\t\t// Values are exactly the same, so do nothing.\n\t\t\t\t\tif (origP === destP) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Values are of the same basic type.\n\t\t\t\t\tif (typeof origP === typeof destP) { // eslint-disable-line valid-typeof\n\t\t\t\t\t\t// Values are functions.\n\t\t\t\t\t\tif (typeof origP === 'function') {\n\t\t\t\t\t\t\t/* diffed[key] = [Op.Copy, destP]; */\n\t\t\t\t\t\t\tif (origP.toString() !== destP.toString()) {\n\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, destP];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Values are primitives.\n\t\t\t\t\t\telse if (typeof origP !== 'object' || origP === null) {\n\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, destP];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Values are objects.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst origPType = objToString.call(origP);\n\t\t\t\t\t\t\tconst destPType = objToString.call(destP);\n\n\t\t\t\t\t\t\t// Values are objects of the same reported type.\n\t\t\t\t\t\t\tif (origPType === destPType) {\n\t\t\t\t\t\t\t\t// Various special cases to handle supported non-generic objects.\n\t\t\t\t\t\t\t\tif (origP instanceof Date) {\n\t\t\t\t\t\t\t\t\tif (Number(origP) !== Number(destP)) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof Map) {\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof RegExp) {\n\t\t\t\t\t\t\t\t\tif (origP.toString() !== destP.toString()) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof Set) {\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Unknown non-generic objects (custom or unsupported natives).\n\t\t\t\t\t\t\t\telse if (origPType !== '[object Object]') {\n\t\t\t\t\t\t\t\t\t// We cannot know how to process these objects,\n\t\t\t\t\t\t\t\t\t// so we simply accept them as-is.\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Generic objects.\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tconst recurse = diff(origP, destP);\n\n\t\t\t\t\t\t\t\t\tif (recurse !== null) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = recurse;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Values are objects of different reported types.\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Values are of different types.\n\t\t\t\t\telse {\n\t\t\t\t\t\tdiffed[key] = [\n\t\t\t\t\t\t\tOp.Copy,\n\t\t\t\t\t\t\ttypeof destP !== 'object' || destP === null ? destP : clone(destP)\n\t\t\t\t\t\t];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Key only exists in orig.\n\t\t\t\telse {\n\t\t\t\t\tif (origIsArray && Util.isNumeric(key)) {\n\t\t\t\t\t\tconst nKey = Number(key);\n\n\t\t\t\t\t\tif (!aOpRef) {\n\t\t\t\t\t\t\taOpRef = '';\n\n\t\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\t\taOpRef += '~';\n\t\t\t\t\t\t\t} while (keys.some(keyIsAOpRef));\n\n\t\t\t\t\t\t\tdiffed[aOpRef] = [Op.SpliceArray, nKey, nKey];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (nKey < diffed[aOpRef][1]) {\n\t\t\t\t\t\t\tdiffed[aOpRef][1] = nKey;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (nKey > diffed[aOpRef][2]) {\n\t\t\t\t\t\t\tdiffed[aOpRef][2] = nKey;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdiffed[key] = Op.Delete;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Key only exists in dest.\n\t\t\telse {\n\t\t\t\tdiffed[key] = [\n\t\t\t\t\tOp.Copy,\n\t\t\t\t\ttypeof destP !== 'object' || destP === null ? destP : clone(destP)\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\t\t/* eslint-enable max-depth */\n\n\t\treturn Object.keys(diffed).length > 0 ? diffed : null;\n\t}\n\n\t/*\n\t\tReturns the object resulting from updating the orig object with the diffed object.\n\t*/\n\tfunction patch(orig, diffed) /* patched object */ {\n\t\tconst keys    = Object.keys(diffed || {});\n\t\tconst patched = clone(orig);\n\n\t\tfor (let i = 0, klen = keys.length; i < klen; ++i) {\n\t\t\tconst key     = keys[i];\n\t\t\tconst diffedP = diffed[key];\n\n\t\t\tif (diffedP === Op.Delete) {\n\t\t\t\tdelete patched[key];\n\t\t\t}\n\t\t\telse if (diffedP instanceof Array) {\n\t\t\t\tswitch (diffedP[0]) {\n\t\t\t\tcase Op.SpliceArray:\n\t\t\t\t\tpatched.splice(diffedP[1], 1 + (diffedP[2] - diffedP[1]));\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase Op.Copy:\n\t\t\t\t\tpatched[key] = clone(diffedP[1]);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase Op.CopyDate:\n\t\t\t\t\tpatched[key] = new Date(diffedP[1]);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tpatched[key] = patch(patched[key], diffedP);\n\t\t\t}\n\t\t}\n\n\t\treturn patched;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tOp    : { value : Op },\n\t\tdiff  : { value : diff },\n\t\tpatch : { value : patch }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tl10n/l10n.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global l10nStrings, strings */\n\nvar L10n = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Replacement pattern regular expressions.\n\tconst _patternRe    = /\\{\\w+\\}/g;\n\tconst _hasPatternRe = new RegExp(_patternRe.source); // to drop the global flag\n\n\n\t/*******************************************************************************************************************\n\t\tLocalization Functions.\n\t*******************************************************************************************************************/\n\tfunction l10nInit() {\n\t\t/* legacy */\n\t\t_mapStringsToL10nStrings();\n\t\t/* /legacy */\n\t}\n\n\t/*******************************************************************************************************************\n\t\tLocalized String Functions.\n\t*******************************************************************************************************************/\n\tfunction l10nGet(ids, overrides) {\n\t\tif (!ids) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst id = (idList => {\n\t\t\tlet selectedId;\n\t\t\tidList.some(id => {\n\t\t\t\tif (l10nStrings.hasOwnProperty(id)) {\n\t\t\t\t\tselectedId = id;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\treturn selectedId;\n\t\t})(Array.isArray(ids) ? ids : [ids]);\n\n\t\tif (!id) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst maxIterations = 50;\n\t\tlet processed = l10nStrings[id];\n\t\tlet iteration = 0;\n\n\t\twhile (_hasPatternRe.test(processed)) {\n\t\t\tif (++iteration > maxIterations) {\n\t\t\t\tthrow new Error('L10n.get exceeded maximum replacement iterations, probable infinite loop');\n\t\t\t}\n\n\t\t\t// Possibly required by some old buggy browsers.\n\t\t\t_patternRe.lastIndex = 0;\n\n\t\t\tprocessed = processed.replace(_patternRe, pat => {\n\t\t\t\tconst subId = pat.slice(1, -1);\n\n\t\t\t\tif (overrides && overrides.hasOwnProperty(subId)) {\n\t\t\t\t\treturn overrides[subId];\n\t\t\t\t}\n\t\t\t\telse if (l10nStrings.hasOwnProperty(subId)) {\n\t\t\t\t\treturn l10nStrings[subId];\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treturn processed;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tLegacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tAttempt to map legacy `strings` object properties to the `l10nStrings` object.\n\t*/\n\tfunction _mapStringsToL10nStrings() {\n\t\tif (strings && Object.keys(strings).length > 0) {\n\t\t\tObject.keys(l10nStrings).forEach(id => {\n\t\t\t\ttry {\n\t\t\t\t\tlet value;\n\n\t\t\t\t\tswitch (id) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tGeneral.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'identity': value = strings.identity; break;\n\t\t\t\t\tcase 'aborting': value = strings.aborting; break;\n\t\t\t\t\tcase 'cancel':   value = strings.cancel; break;\n\t\t\t\t\tcase 'close':    value = strings.close; break;\n\t\t\t\t\tcase 'ok':       value = strings.ok; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tErrors.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'errorTitle':              value = strings.errors.title; break;\n\t\t\t\t\tcase 'errorNonexistentPassage': value = strings.errors.nonexistentPassage; break;\n\t\t\t\t\tcase 'errorSaveMissingData':    value = strings.errors.saveMissingData; break;\n\t\t\t\t\tcase 'errorSaveIdMismatch':     value = strings.errors.saveIdMismatch; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tWarnings.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'warningDegraded': value = strings.warnings.degraded; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tDebug View.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'debugViewTitle':  value = strings.debugView.title; break;\n\t\t\t\t\tcase 'debugViewToggle': value = strings.debugView.toggle; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tUI bar.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'uiBarToggle':   value = strings.uiBar.toggle; break;\n\t\t\t\t\tcase 'uiBarBackward': value = strings.uiBar.backward; break;\n\t\t\t\t\tcase 'uiBarForward':  value = strings.uiBar.forward; break;\n\t\t\t\t\tcase 'uiBarJumpto':   value = strings.uiBar.jumpto; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tJump To.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'jumptoTitle':       value = strings.jumpto.title; break;\n\t\t\t\t\tcase 'jumptoTurn':        value = strings.jumpto.turn; break;\n\t\t\t\t\tcase 'jumptoUnavailable': value = strings.jumpto.unavailable; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tSaves.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'savesTitle':       value = strings.saves.title; break;\n\t\t\t\t\tcase 'savesDisallowed':  value = strings.saves.disallowed; break;\n\t\t\t\t\tcase 'savesIncapable':   value = strings.saves.incapable; break;\n\t\t\t\t\tcase 'savesLabelAuto':   value = strings.saves.labelAuto; break;\n\t\t\t\t\tcase 'savesLabelDelete': value = strings.saves.labelDelete; break;\n\t\t\t\t\tcase 'savesLabelExport': value = strings.saves.labelExport; break;\n\t\t\t\t\tcase 'savesLabelImport': value = strings.saves.labelImport; break;\n\t\t\t\t\tcase 'savesLabelLoad':   value = strings.saves.labelLoad; break;\n\t\t\t\t\tcase 'savesLabelClear':  value = strings.saves.labelClear; break;\n\t\t\t\t\tcase 'savesLabelSave':   value = strings.saves.labelSave; break;\n\t\t\t\t\tcase 'savesLabelSlot':   value = strings.saves.labelSlot; break;\n\t\t\t\t\tcase 'savesUnavailable': value = strings.saves.unavailable; break;\n\t\t\t\t\tcase 'savesUnknownDate': value = strings.saves.unknownDate; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tSettings.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'settingsTitle': value = strings.settings.title; break;\n\t\t\t\t\tcase 'settingsOff':   value = strings.settings.off; break;\n\t\t\t\t\tcase 'settingsOn':    value = strings.settings.on; break;\n\t\t\t\t\tcase 'settingsReset': value = strings.settings.reset; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tRestart.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'restartTitle':  value = strings.restart.title; break;\n\t\t\t\t\tcase 'restartPrompt': value = strings.restart.prompt; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tShare.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'shareTitle': value = strings.share.title; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAlert.\n\t\t\t\t\t*/\n\t\t\t\t\t/* none */\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAutoload.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'autoloadTitle':  value = strings.autoload.title; break;\n\t\t\t\t\tcase 'autoloadCancel': value = strings.autoload.cancel; break;\n\t\t\t\t\tcase 'autoloadOk':     value = strings.autoload.ok; break;\n\t\t\t\t\tcase 'autoloadPrompt': value = strings.autoload.prompt; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tMacros.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'macroBackText':   value = strings.macros.back.text; break;\n\t\t\t\t\tcase 'macroReturnText': value = strings.macros.return.text; break;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (value) {\n\t\t\t\t\t\tl10nStrings[id] = value.replace(/%\\w+%/g, pat => `{${pat.slice(1, -1)}}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t});\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tLocalization Functions.\n\t\t*/\n\t\tinit : { value : l10nInit },\n\n\t\t/*\n\t\t\tLocalized String Functions.\n\t\t*/\n\t\tget : { value : l10nGet }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tl10n/legacy.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\t[DEPRECATED] The `strings` object is deprecated and should no longer be used.\n\tAll new or updated translations should be based upon the `l10nStrings` object\n\t(see: `l10n/strings.js`).\n\n\tLegacy/existing uses of the `strings` object will be mapped to the `l10nStrings`\n\tobject after user script evaluation.\n*/\nvar strings = { // eslint-disable-line no-unused-vars, no-var\n\terrors    : {},\n\twarnings  : {},\n\tdebugView : {},\n\tuiBar     : {},\n\tjumpto    : {},\n\tsaves     : {},\n\tsettings  : {},\n\trestart   : {},\n\tshare     : {},\n\tautoload  : {},\n\tmacros    : {\n\t\tback   : {},\n\t\treturn : {}\n\t}\n};\n\n/***********************************************************************************************************************\n\n\tl10n/strings.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* eslint-disable max-len, prefer-template */\n\n/*\n\tATTENTION TRANSLATORS\n\n\tPlease use the `locale/l10n-template.js` file, from the root of the repository,\n\tas the template for your translation rather than this file.\n\n\tSEE: https://github.com/tmedwards/sugarcube-2/tree/develop/locale\n*/\nvar l10nStrings = { // eslint-disable-line no-unused-vars, no-var\n\t/*\n\t\tGeneral.\n\t*/\n\tidentity : 'game',\n\taborting : 'Aborting',\n\tcancel   : 'Cancel',\n\tclose    : 'Close',\n\tok       : 'OK',\n\n\t/*\n\t\tErrors.\n\t*/\n\terrorTitle              : 'Error',\n\terrorToggle             : 'Toggle the error view',\n\terrorNonexistentPassage : 'the passage \"{passage}\" does not exist', // NOTE: `passage` is supplied locally\n\terrorSaveMissingData    : 'save is missing required data. Either the loaded file is not a save or the save has become corrupted',\n\terrorSaveIdMismatch     : 'save is from the wrong {identity}',\n\n\t/*\n\t\tWarnings.\n\t*/\n\t_warningIntroLacking  : 'Your browser either lacks or has disabled',\n\t_warningOutroDegraded : ', so this {identity} is running in a degraded mode. You may be able to continue, however, some parts may not work properly.',\n\twarningNoWebStorage   : '{_warningIntroLacking} the Web Storage API{_warningOutroDegraded}',\n\twarningDegraded       : '{_warningIntroLacking} some of the capabilities required by this {identity}{_warningOutroDegraded}',\n\n\t/*\n\t\tDebug bar.\n\t*/\n\tdebugBarToggle      : 'Toggle the debug bar',\n\tdebugBarNoWatches   : '\\u2014 no watches set \\u2014',\n\tdebugBarAddWatch    : 'Add watch',\n\tdebugBarDeleteWatch : 'Delete watch',\n\tdebugBarWatchAll    : 'Watch all',\n\tdebugBarWatchNone   : 'Delete all',\n\tdebugBarLabelAdd    : 'Add',\n\tdebugBarLabelWatch  : 'Watch',\n\tdebugBarLabelTurn   : 'Turn', // (noun) chance to act (in a game), moment, period\n\tdebugBarLabelViews  : 'Views',\n\tdebugBarViewsToggle : 'Toggle the debug views',\n\tdebugBarWatchToggle : 'Toggle the watch panel',\n\n\t/*\n\t\tUI bar.\n\t*/\n\tuiBarToggle   : 'Toggle the UI bar',\n\tuiBarBackward : 'Go backward within the {identity} history',\n\tuiBarForward  : 'Go forward within the {identity} history',\n\tuiBarJumpto   : 'Jump to a specific point within the {identity} history',\n\n\t/*\n\t\tJump To.\n\t*/\n\tjumptoTitle       : 'Jump To',\n\tjumptoTurn        : 'Turn', // (noun) chance to act (in a game), moment, period\n\tjumptoUnavailable : 'No jump points currently available\\u2026',\n\n\t/*\n\t\tSaves.\n\t*/\n\tsavesTitle       : 'Saves',\n\tsavesDisallowed  : 'Saving has been disallowed on this passage.',\n\tsavesIncapable   : '{_warningIntroLacking} the capabilities required to support saves, so saves have been disabled for this session.',\n\tsavesLabelAuto   : 'Autosave',\n\tsavesLabelDelete : 'Delete',\n\tsavesLabelExport : 'Save to Disk\\u2026',\n\tsavesLabelImport : 'Load from Disk\\u2026',\n\tsavesLabelLoad   : 'Load',\n\tsavesLabelClear  : 'Delete All',\n\tsavesLabelSave   : 'Save',\n\tsavesLabelSlot   : 'Slot',\n\tsavesUnavailable : 'No save slots found\\u2026',\n\tsavesUnknownDate : 'unknown',\n\n\t/*\n\t\tSettings.\n\t*/\n\tsettingsTitle : 'Settings',\n\tsettingsOff   : 'Off',\n\tsettingsOn    : 'On',\n\tsettingsReset : 'Reset to Defaults',\n\n\t/*\n\t\tRestart.\n\t*/\n\trestartTitle  : 'Restart',\n\trestartPrompt : 'Are you sure that you want to restart? Unsaved progress will be lost.',\n\n\t/*\n\t\tShare.\n\t*/\n\tshareTitle : 'Share',\n\n\t/*\n\t\tAlert.\n\t*/\n\t/* none */\n\n\t/*\n\t\tAutoload.\n\t*/\n\tautoloadTitle  : 'Autoload',\n\tautoloadCancel : 'Go to start',\n\tautoloadOk     : 'Load autosave',\n\tautoloadPrompt : 'An autosave exists. Load it now or go to the start?',\n\n\t/*\n\t\tMacros.\n\t*/\n\tmacroBackText   : 'Back',  // (verb) rewind, revert\n\tmacroReturnText : 'Return' // (verb) go/send back\n};\n\n/***********************************************************************************************************************\n\n\tconfig.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util */\n\nvar Config = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// General settings.\n\tlet _debug                 = false;\n\tlet _addVisitedLinkClass   = false;\n\tlet _cleanupWikifierOutput = false;\n\tlet _loadDelay             = 0;\n\n\t// Audio settings.\n\tlet _audioPauseOnFadeToZero = true;\n\tlet _audioPreloadMetadata   = true;\n\n\t// State history settings.\n\tlet _historyControls  = true;\n\tlet _historyMaxStates = 100;\n\n\t// Macros settings.\n\tlet _macrosIfAssignmentError = true;\n\tlet _macrosMaxLoopIterations = 1000;\n\n\t// Navigation settings.\n\tlet _navigationOverride;\n\n\t// Passages settings.\n\tlet _passagesDescriptions;\n\tlet _passagesDisplayTitles = false;\n\tlet _passagesNobr          = false;\n\tlet _passagesStart; // set by `Story.load()`\n\tlet _passagesOnProcess;\n\tlet _passagesTransitionOut;\n\n\t// Saves settings.\n\tlet _savesAutoload;\n\tlet _savesAutosave;\n\tlet _savesId        = 'untitled-story';\n\tlet _savesIsAllowed;\n\tlet _savesOnLoad;\n\tlet _savesOnSave;\n\tlet _savesSlots     = 8;\n\tlet _savesVersion;\n\n\t// UI settings.\n\tlet _uiStowBarInitially    = 800;\n\tlet _uiUpdateStoryElements = true;\n\n\n\t/*******************************************************************************\n\t\tError Constants.\n\t*******************************************************************************/\n\n\tconst _errHistoryModeDeprecated     = 'Config.history.mode has been deprecated and is no longer used by SugarCube, please remove it from your code';\n\tconst _errHistoryTrackingDeprecated = 'Config.history.tracking has been deprecated, use Config.history.maxStates instead';\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze({\n\t\t/*\n\t\t\tGeneral settings.\n\t\t*/\n\t\tget debug() { return _debug; },\n\t\tset debug(value) { _debug = Boolean(value); },\n\n\t\tget addVisitedLinkClass() { return _addVisitedLinkClass; },\n\t\tset addVisitedLinkClass(value) { _addVisitedLinkClass = Boolean(value); },\n\n\t\tget cleanupWikifierOutput() { return _cleanupWikifierOutput; },\n\t\tset cleanupWikifierOutput(value) { _cleanupWikifierOutput = Boolean(value); },\n\n\t\tget loadDelay() { return _loadDelay; },\n\t\tset loadDelay(value) {\n\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\tthrow new RangeError('Config.loadDelay must be a non-negative integer');\n\t\t\t}\n\n\t\t\t_loadDelay = value;\n\t\t},\n\n\t\t/*\n\t\t\tAudio settings.\n\t\t*/\n\t\taudio : Object.freeze({\n\t\t\tget pauseOnFadeToZero() { return _audioPauseOnFadeToZero; },\n\t\t\tset pauseOnFadeToZero(value) { _audioPauseOnFadeToZero = Boolean(value); },\n\n\t\t\tget preloadMetadata() { return _audioPreloadMetadata; },\n\t\t\tset preloadMetadata(value) { _audioPreloadMetadata = Boolean(value); }\n\t\t}),\n\n\t\t/*\n\t\t\tState history settings.\n\t\t*/\n\t\thistory : Object.freeze({\n\t\t\t// TODO: (v3) This should be under UI settings → `Config.ui.historyControls`.\n\t\t\tget controls() { return _historyControls; },\n\t\t\tset controls(value) {\n\t\t\t\tconst controls = Boolean(value);\n\n\t\t\t\tif (_historyMaxStates === 1 && controls) {\n\t\t\t\t\tthrow new Error('Config.history.controls must be false when Config.history.maxStates is 1');\n\t\t\t\t}\n\n\t\t\t\t_historyControls = controls;\n\t\t\t},\n\n\t\t\tget maxStates() { return _historyMaxStates; },\n\t\t\tset maxStates(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new RangeError('Config.history.maxStates must be a non-negative integer');\n\t\t\t\t}\n\n\t\t\t\t_historyMaxStates = value;\n\n\t\t\t\t// Force `Config.history.controls` to `false`, when limited to `1` moment.\n\t\t\t\tif (_historyControls && value === 1) {\n\t\t\t\t\t_historyControls = false;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// legacy\n\t\t\t// Die if deprecated state history settings are accessed.\n\t\t\tget mode()  { throw new Error(_errHistoryModeDeprecated); },\n\t\t\tset mode(_) { throw new Error(_errHistoryModeDeprecated); },\n\t\t\tget tracking()  { throw new Error(_errHistoryTrackingDeprecated); },\n\t\t\tset tracking(_) { throw new Error(_errHistoryTrackingDeprecated); }\n\t\t\t// /legacy\n\t\t}),\n\n\t\t/*\n\t\t\tMacros settings.\n\t\t*/\n\t\tmacros : Object.freeze({\n\t\t\tget ifAssignmentError() { return _macrosIfAssignmentError; },\n\t\t\tset ifAssignmentError(value) { _macrosIfAssignmentError = Boolean(value); },\n\n\t\t\tget maxLoopIterations() { return _macrosMaxLoopIterations; },\n\t\t\tset maxLoopIterations(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new RangeError('Config.macros.maxLoopIterations must be a non-negative integer');\n\t\t\t\t}\n\n\t\t\t\t_macrosMaxLoopIterations = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tNavigation settings.\n\t\t*/\n\t\tnavigation : Object.freeze({\n\t\t\tget override() { return _navigationOverride; },\n\t\t\tset override(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.navigation.override must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_navigationOverride = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tPassages settings.\n\t\t*/\n\t\tpassages : Object.freeze({\n\t\t\tget descriptions() { return _passagesDescriptions; },\n\t\t\tset descriptions(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'boolean' && valueType !== 'Object' && valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.descriptions must be a boolean, object, function, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesDescriptions = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.updateTitle`.\n\t\t\tget displayTitles() { return _passagesDisplayTitles; },\n\t\t\tset displayTitles(value) { _passagesDisplayTitles = Boolean(value); },\n\n\t\t\tget nobr() { return _passagesNobr; },\n\t\t\tset nobr(value) { _passagesNobr = Boolean(value); },\n\n\t\t\tget onProcess() { return _passagesOnProcess; },\n\t\t\tset onProcess(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.onProcess must be a function or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesOnProcess = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.(start|startingPassage)`.\n\t\t\tget start() { return _passagesStart; },\n\t\t\tset start(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'string') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.start must be a string or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesStart = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.transitionOut`.\n\t\t\tget transitionOut() { return _passagesTransitionOut; },\n\t\t\tset transitionOut(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t   valueType !== 'string'\n\t\t\t\t\t\t&& (valueType !== 'number' || !Number.isSafeInteger(value) || value < 0)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.transitionOut must be a string, non-negative integer, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesTransitionOut = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tSaves settings.\n\t\t*/\n\t\tsaves : Object.freeze({\n\t\t\tget autoload() { return _savesAutoload; },\n\t\t\tset autoload(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'boolean' && valueType !== 'string' && valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.saves.autoload must be a boolean, string, function, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_savesAutoload = value;\n\t\t\t},\n\n\t\t\tget autosave() { return _savesAutosave; },\n\t\t\tset autosave(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\t// legacy\n\t\t\t\t\t// Convert a string value to an Array of string.\n\t\t\t\t\tif (valueType === 'string') {\n\t\t\t\t\t\t_savesAutosave = [value];\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// /legacy\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t   valueType !== 'boolean'\n\t\t\t\t\t\t&& (valueType !== 'Array' || !value.every(item => typeof item === 'string'))\n\t\t\t\t\t\t&& valueType !== 'function'\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new TypeError(`Config.saves.autosave must be a boolean, Array of strings, function, or null/undefined (received: ${valueType}${valueType === 'Array' ? ' of mixed' : ''})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_savesAutosave = value;\n\t\t\t},\n\n\t\t\tget id() { return _savesId; },\n\t\t\tset id(value) {\n\t\t\t\tif (typeof value !== 'string' || value === '') {\n\t\t\t\t\tthrow new TypeError(`Config.saves.id must be a non-empty string (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesId = value;\n\t\t\t},\n\n\t\t\tget isAllowed() { return _savesIsAllowed; },\n\t\t\tset isAllowed(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.isAllowed must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesIsAllowed = value;\n\t\t\t},\n\n\t\t\tget onLoad() { return _savesOnLoad; },\n\t\t\tset onLoad(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.onLoad must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesOnLoad = value;\n\t\t\t},\n\n\t\t\tget onSave() { return _savesOnSave; },\n\t\t\tset onSave(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.onSave must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesOnSave = value;\n\t\t\t},\n\n\t\t\tget slots() { return _savesSlots; },\n\t\t\tset slots(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new TypeError(`Config.saves.slots must be a non-negative integer (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesSlots = value;\n\t\t\t},\n\n\t\t\tget version() { return _savesVersion; },\n\t\t\tset version(value) { _savesVersion = value; }\n\t\t}),\n\n\t\t/*\n\t\t\tUI settings.\n\t\t*/\n\t\tui : Object.freeze({\n\t\t\tget stowBarInitially() { return _uiStowBarInitially; },\n\t\t\tset stowBarInitially(value) {\n\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\tif (\n\t\t\t\t\t   valueType !== 'boolean'\n\t\t\t\t\t&& (valueType !== 'number' || !Number.isSafeInteger(value) || value < 0)\n\t\t\t\t) {\n\t\t\t\t\tthrow new TypeError(`Config.ui.stowBarInitially must be a boolean or non-negative integer (received: ${valueType})`);\n\t\t\t\t}\n\n\t\t\t\t_uiStowBarInitially = value;\n\t\t\t},\n\n\t\t\tget updateStoryElements() { return _uiUpdateStoryElements; },\n\t\t\tset updateStoryElements(value) { _uiUpdateStoryElements = Boolean(value); }\n\t\t})\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tsimpleaudio.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser, Config, Has, LoadScreen, Story, Util, Visibility, clone */\n\nvar SimpleAudio = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tEvents that count as user activation—i.e. \"user gestures\", \"activation behavior\".\n\n\t\tNOTE (ca. Dec, 2018): This not an exhaustive list and varies significantly by browser.\n\t\tProposals for a specification/standard are still very much in flux at this point.\n\n\t\tTODO (ca. Dec, 2018): Revisit this topic.\n\n\t\tSEE: (too many to list)\n\t\t\thttps://github.com/whatwg/html/issues/3849\n\t\t\thttps://github.com/whatwg/html/issues/1903\n\t\t\thttps://html.spec.whatwg.org/#activation\n\t\t\thttps://docs.google.com/spreadsheets/d/1DGXjhQ6D3yZXIePOMo0dsd2agz0t5W7rYH1NwJ-QGJo/edit#gid=0\n\t*/\n\tconst _gestureEventNames = Object.freeze(['click', 'contextmenu', 'dblclick', 'keyup', 'mouseup', 'pointerup', 'touchend']);\n\n\t// Special group IDs.\n\tconst _specialIds = Object.freeze([':not', ':all', ':looped', ':muted', ':paused', ':playing']);\n\n\t// Format specifier regular expression.\n\tconst _formatSpecRe = /^([\\w-]+)\\s*\\|\\s*(\\S.*)$/; // e.g. 'mp3|https://audiohost.tld/id'\n\n\t// ID verification regular expressions.\n\tconst _badIdRe = /[:\\s]/;\n\n\t// Tracks collection.\n\tconst _tracks = new Map();\n\n\t// Groups collection.\n\tconst _groups = new Map();\n\n\t// Playlists collection.\n\tconst _lists = new Map();\n\n\t// Subscriber collection.\n\tconst _subscribers = new Map();\n\n\t// Master playback rate.\n\tlet _masterRate = 1;\n\n\t// Master playback volume.\n\tlet _masterVolume = 1;\n\n\t// Master mute state.\n\tlet _masterMute = false;\n\n\t// Master mute on tab/window visibility state.\n\tlet _masterMuteOnHidden = false;\n\n\n\t/*******************************************************************************************************************\n\t\tFeature Detection Functions.\n\t*******************************************************************************************************************/\n\t// Return whether the `<HTMLAudioElement>.play()` method returns a `Promise`.\n\t//\n\t// NOTE: The initial result is cached for future calls.\n\tconst _playReturnsPromise = (function () {\n\t\t// Cache of whether `<HTMLAudioElement>.play()` returns a `Promise`.\n\t\tlet _hasPromise = null;\n\n\t\tfunction _playReturnsPromise() {\n\t\t\tif (_hasPromise !== null) {\n\t\t\t\treturn _hasPromise;\n\t\t\t}\n\n\t\t\t_hasPromise = false;\n\n\t\t\tif (Has.audio) {\n\t\t\t\ttry {\n\t\t\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t\t\t// NOTE (ca. Jan 01, 2020): Firefox will still log an \"Autoplay is only allowed\n\t\t\t\t\t// when […] media is muted.\" message to the console when attempting the test\n\t\t\t\t\t// below, even though the audio has been muted.  Stay classy, Firefox.\n\t\t\t\t\t//\n\t\t\t\t\t// QUESTION (ca. Jan 01, 2020): Keep this?  It's only here to appease Firefox,\n\t\t\t\t\t// but doesn't seem to work as Firefox seems to ignore mute in violation of the\n\t\t\t\t\t// `HTMLAudioElement` specification—willfully or simply a bug, I can't say.\n\t\t\t\t\taudio.muted = true;\n\n\t\t\t\t\tconst value = audio.play();\n\n\t\t\t\t\t// Silence \"Uncaught (in promise)\" console errors from Blink.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: Swallowing errors is generally bad, but in this case we know there's\n\t\t\t\t\t// going to be an error regardless, since there's no source, and we don't actually\n\t\t\t\t\t// care about the error, since we just want the return value, so we consign it\n\t\t\t\t\t// to the bit bucket.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: We don't ensure that the return value is not `undefined` here because\n\t\t\t\t\t// having the attempted call to `<Promise>.catch()` on an `undefined` value throw\n\t\t\t\t\t// is acceptable, since it will be caught and `false` eventually returned.\n\t\t\t\t\tvalue.catch(() => { /* no-op */ });\n\n\t\t\t\t\t_hasPromise = value instanceof Promise;\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t}\n\n\t\t\treturn _hasPromise;\n\t\t}\n\n\t\treturn _playReturnsPromise;\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tAudioTrack Class.\n\t*******************************************************************************************************************/\n\tclass AudioTrack {\n\t\tconstructor(obj) {\n\t\t\t// Process the given array of sources or AudioTrack object.\n\t\t\tif (obj instanceof Array) {\n\t\t\t\tthis._create(obj);\n\t\t\t}\n\t\t\telse if (obj instanceof AudioTrack) {\n\t\t\t\tthis._copy(obj);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('sources parameter must be either an array, of URIs or source objects, or an AudioTrack instance');\n\t\t\t}\n\t\t}\n\n\t\t_create(sourceList) {\n\t\t\tconst dataUriRe   = /^data:\\s*audio\\/([^;,]+)\\s*[;,]/i;\n\t\t\tconst extRe       = /\\.([^./\\\\]+)$/;\n\t\t\tconst getType     = AudioTrack.getType;\n\t\t\tconst usedSources = [];\n\t\t\t/*\n\t\t\t\tHTMLAudioElement: DOM factory method vs. constructor\n\n\t\t\t\tUse of the DOM factory method, `document.createElement('audio')`, should be\n\t\t\t\tpreferred over use of the constructor, `new Audio()`.  The reason being that\n\t\t\t\tobjects created by the latter are, erroneously, treated differently, often\n\t\t\t\tunfavorably, by certain browser engines—e.g. within some versions of the iOS\n\t\t\t\tbrowser core.\n\n\t\t\t\tNotably, the only difference between the two, per the specification, is that\n\t\t\t\tobjects created via the constructor should have their `preload` property\n\t\t\t\tautomatically set to 'auto'.  Thus, there's no technical reason to prefer\n\t\t\t\tusage of the constructor, even discounting buggy browser implementations.\n\t\t\t*/\n\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t// Initially set the `preload` attribute to `'none'`.\n\t\t\taudio.preload = 'none';\n\n\t\t\t// Process the array of sources, adding any valid sources to the `usedSources`\n\t\t\t// array and to the audio element as source elements.\n\t\t\tsourceList.forEach(src => {\n\t\t\t\tlet srcObj = null;\n\n\t\t\t\tswitch (typeof src) {\n\t\t\t\tcase 'string':\n\t\t\t\t\t{\n\t\t\t\t\t\tlet match;\n\n\t\t\t\t\t\tif (src.slice(0, 5) === 'data:') {\n\t\t\t\t\t\t\tmatch = dataUriRe.exec(src);\n\n\t\t\t\t\t\t\tif (match === null) {\n\t\t\t\t\t\t\t\tthrow new Error('source data URI missing media type');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tmatch = extRe.exec(Util.parseUrl(src).pathname);\n\n\t\t\t\t\t\t\tif (match === null) {\n\t\t\t\t\t\t\t\tthrow new Error('source URL missing file extension');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst type = getType(match[1]);\n\n\t\t\t\t\t\tif (type !== null) {\n\t\t\t\t\t\t\tsrcObj = { src, type };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\t{\n\t\t\t\t\t\tif (src === null) {\n\t\t\t\t\t\t\tthrow new Error('source object cannot be null');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (!src.hasOwnProperty('src')) {\n\t\t\t\t\t\t\tthrow new Error('source object missing required \"src\" property');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (!src.hasOwnProperty('format')) {\n\t\t\t\t\t\t\tthrow new Error('source object missing required \"format\" property');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst type = getType(src.format);\n\n\t\t\t\t\t\tif (type !== null) {\n\t\t\t\t\t\t\tsrcObj = { src : src.src, type };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`invalid source value (type: ${typeof src})`);\n\t\t\t\t}\n\n\t\t\t\tif (srcObj !== null) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tOpera (Blink; ca. Jul 2017) fails to play audio from some sources\n\t\t\t\t\t\twith MIME-types containing a `codecs` parameter, despite the fact\n\t\t\t\t\t\tthat `canPlayType()` blessed the full MIME-type including `codecs`.\n\n\t\t\t\t\t\tBizarrely, this only affects some MIME-types—e.g. MP3s are affected,\n\t\t\t\t\t\twhile WAVEs are not.\n\t\t\t\t\t\t\tFails: 'audio/mpeg; codecs=\"mp3\"'\n\t\t\t\t\t\t\tPlays: 'audio/mpeg'\n\t\t\t\t\t\t\tPlays: 'audio/wav; codecs=\"1\"'\n\n\t\t\t\t\t\tTo workaround this we remove all parameters from the MIME-type in\n\t\t\t\t\t\tOpera.\n\t\t\t\t\t*/\n\t\t\t\t\tif (Browser.isOpera) {\n\t\t\t\t\t\tsrcObj.type =  srcObj.type.replace(/;.*$/, '');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst source = document.createElement('source');\n\t\t\t\t\tsource.src  = srcObj.src;\n\t\t\t\t\tsource.type = srcObj.type;\n\t\t\t\t\taudio.appendChild(source);\n\t\t\t\t\tusedSources.push(srcObj);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (audio.hasChildNodes()) {\n\t\t\t\t// Set the `preload` attribute to `'metadata'`, unless preloading has been disabled.\n\t\t\t\tif (Config.audio.preloadMetadata) {\n\t\t\t\t\taudio.preload = 'metadata';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._finalize(audio, usedSources, clone(sourceList));\n\t\t}\n\n\t\t_copy(obj) {\n\t\t\tthis._finalize(\n\t\t\t\tobj.audio.cloneNode(true), // deep clone of the audio element & its children\n\t\t\t\tclone(obj.sources),\n\t\t\t\tclone(obj.originals)\n\t\t\t);\n\t\t}\n\n\t\t_finalize(audio, sources, originals) {\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\taudio : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : audio\n\t\t\t\t},\n\n\t\t\t\tsources : {\n\t\t\t\t\tvalue : Object.freeze(sources)\n\t\t\t\t},\n\n\t\t\t\toriginals : {\n\t\t\t\t\tvalue : Object.freeze(originals)\n\t\t\t\t},\n\n\t\t\t\t_error : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_faderId : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_mute : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_rate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_volume : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Set up event handlers on the audio and source elements.\n\t\t\tjQuery(this.audio)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving a `loadstart` event on the audio element, set `_error` to\n\t\t\t\t\t`false`.\n\t\t\t\t*/\n\t\t\t\t.on('loadstart.AudioTrack', () => this._error = false)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving an `error` event on the audio element, set `_error` to\n\t\t\t\t\t`true`.\n\n\t\t\t\t\tCaveats by browser:\n\t\t\t\t\t\tEdge violates the specification by triggering `error` events from source\n\t\t\t\t\t\telements on their parent media element, rather than the source element.\n\t\t\t\t\t\tTo enable error handling in all browsers, we set the error handler on the\n\t\t\t\t\t\taudio element and have the final source element forward its `error` event.\n\n\t\t\t\t\t\tIE does not trigger, at least some, `error` events from source elements at\n\t\t\t\t\t\tall, not on the source element or its parent media element.  AFAIK, nothing\n\t\t\t\t\t\tcan be done about this lossage.\n\t\t\t\t*/\n\t\t\t\t.on('error.AudioTrack', () => this._error = true)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving an `error` event on the final source element (if any), trigger\n\t\t\t\t\tan `error` event on the audio element—that being necessary because the source\n\t\t\t\t\t`error` event does not bubble.\n\t\t\t\t*/\n\t\t\t\t.find('source:last-of-type')\n\t\t\t\t.on('error.AudioTrack', () => this._trigger('error'));\n\n\t\t\t// Subscribe to command messages.\n\t\t\tsubscribe(this, mesg => {\n\t\t\t\tif (!this.audio) {\n\t\t\t\t\tunsubscribe(this);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch (mesg) {\n\t\t\t\tcase 'loadwithscreen':\n\t\t\t\t\tif (this.hasSource()) {\n\t\t\t\t\t\tconst lockId = LoadScreen.lock();\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t// NOTE: Do not use an arrow function here.\n\t\t\t\t\t\t\t.one(\n\t\t\t\t\t\t\t\t'canplaythrough.AudioTrack_loadwithscreen error.AudioTrack_loadwithscreen',\n\t\t\t\t\t\t\t\tfunction () {\n\t\t\t\t\t\t\t\t\tjQuery(this).off('.AudioTrack_loadwithscreen');\n\t\t\t\t\t\t\t\t\tLoadScreen.unlock(lockId);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.load();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'load':   this.load();               break;\n\t\t\t\tcase 'mute':   this._updateAudioMute();   break;\n\t\t\t\tcase 'rate':   this._updateAudioRate();   break;\n\t\t\t\tcase 'stop':   this.stop();               break;\n\t\t\t\tcase 'volume': this._updateAudioVolume(); break;\n\t\t\t\tcase 'unload': this.unload();             break;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Synchronize with the current master audio settings.\n\t\t\tthis._updateAudioMute();\n\t\t\tthis._updateAudioRate();\n\t\t\tthis._updateAudioVolume();\n\t\t}\n\n\t\t_trigger(eventName) {\n\t\t\t// Do not use `trigger()` here as we do not want these events to bubble.\n\t\t\tjQuery(this.audio).triggerHandler(eventName);\n\t\t}\n\n\t\t_destroy() {\n\t\t\t/*\n\t\t\t\tStrictly speaking, self-destruction is not necessary as this object will,\n\t\t\t\teventually, be garbage collected.  That said, since the audio element contains\n\t\t\t\tdata buffers for the selected audio source, which may be quite large, manually\n\t\t\t\tpurging them as soon as we know that they're no longer needed is not a bad idea.\n\t\t\t*/\n\t\t\tunsubscribe(this);\n\n\t\t\tif (!this.audio) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tjQuery(this.audio).off();\n\t\t\tthis.unload();\n\t\t\tthis._error = true;\n\n\t\t\t// Delete the audio element property.\n\t\t\tdelete this.audio;\n\t\t}\n\n\t\tclone() {\n\t\t\treturn new AudioTrack(this);\n\t\t}\n\n\t\tload() {\n\t\t\tthis.fadeStop();\n\t\t\tthis.audio.pause();\n\n\t\t\tif (!this.audio.hasChildNodes()) {\n\t\t\t\tif (this.sources.length === 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.sources.forEach(srcObj => {\n\t\t\t\t\tconst source = document.createElement('source');\n\t\t\t\t\tsource.src  = srcObj.src;\n\t\t\t\t\tsource.type = srcObj.type;\n\t\t\t\t\tthis.audio.appendChild(source);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (this.audio.preload !== 'auto') {\n\t\t\t\tthis.audio.preload = 'auto';\n\t\t\t}\n\n\t\t\tif (!this.isLoading()) {\n\t\t\t\tthis.audio.load();\n\t\t\t}\n\t\t}\n\n\t\tunload() {\n\t\t\tthis.fadeStop();\n\t\t\tthis.stop();\n\n\t\t\tconst audio = this.audio;\n\t\t\taudio.preload = 'none';\n\n\t\t\t// Remove all source elements.\n\t\t\twhile (audio.hasChildNodes()) {\n\t\t\t\taudio.removeChild(audio.firstChild);\n\t\t\t}\n\n\t\t\t// Force the audio element to drop any existing data buffers.\n\t\t\taudio.load();\n\t\t}\n\n\t\tplay() {\n\t\t\tif (!this.hasSource()) {\n\t\t\t\treturn Promise.reject(new Error('none of the candidate sources were acceptable'));\n\t\t\t}\n\n\t\t\tif (this.isUnloaded()) {\n\t\t\t\treturn Promise.reject(new Error('no sources are loaded'));\n\t\t\t}\n\n\t\t\tif (this.isFailed()) {\n\t\t\t\treturn Promise.reject(new Error('failed to load any of the sources'));\n\t\t\t}\n\n\t\t\tif (this.audio.preload !== 'auto') {\n\t\t\t\tthis.audio.preload = 'auto';\n\t\t\t}\n\n\t\t\tconst namespace = '.AudioTrack_play';\n\n\t\t\treturn _playReturnsPromise()\n\t\t\t\t? this.audio.play()\n\t\t\t\t: new Promise((resolve, reject) => {\n\t\t\t\t\tif (this.isPlaying()) {\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tjQuery(this.audio)\n\t\t\t\t\t\t\t.off(namespace)\n\t\t\t\t\t\t\t.one(`error${namespace} playing${namespace} timeupdate${namespace}`, ev => {\n\t\t\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\t\t\tif (ev.type === 'error') {\n\t\t\t\t\t\t\t\t\treject(new Error('unknown audio play error'));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.audio.play();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tthis.play().catch(() => {\n\t\t\t\tconst gestures = _gestureEventNames.map(name => `${name}.AudioTrack_playWhenAllowed`).join(' ');\n\t\t\t\tjQuery(document).one(gestures, () => {\n\t\t\t\t\tjQuery(document).off('.AudioTrack_playWhenAllowed');\n\t\t\t\t\tthis.audio.play();\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tpause() {\n\t\t\tthis.audio.pause();\n\t\t}\n\n\t\tstop() {\n\t\t\tthis.audio.pause();\n\t\t\tthis.time(0);\n\t\t\tthis._trigger(':stopped');\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (typeof duration !== 'number') {\n\t\t\t\tthrow new TypeError('duration parameter must be a number');\n\t\t\t}\n\t\t\tif (typeof toVol !== 'number') {\n\t\t\t\tthrow new TypeError('toVolume parameter must be a number');\n\t\t\t}\n\t\t\tif (fromVol != null && typeof fromVol !== 'number') { // lazy equality for null\n\t\t\t\tthrow new TypeError('fromVolume parameter must be a number');\n\t\t\t}\n\n\t\t\tif (!this.hasSource()) {\n\t\t\t\treturn Promise.reject(new Error('none of the candidate sources were acceptable'));\n\t\t\t}\n\n\t\t\tif (this.isUnloaded()) {\n\t\t\t\treturn Promise.reject(new Error('no sources are loaded'));\n\t\t\t}\n\n\t\t\tif (this.isFailed()) {\n\t\t\t\treturn Promise.reject(new Error('failed to load any of the sources'));\n\t\t\t}\n\n\t\t\tthis.fadeStop();\n\n\t\t\tconst from = Math.clamp(fromVol == null ? this.volume() : fromVol, 0, 1); // lazy equality for null\n\t\t\tconst to   = Math.clamp(toVol, 0, 1);\n\n\t\t\tif (from === to) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.volume(from);\n\n\t\t\t/*\n\t\t\t\tWe listen for the `timeupdate` event here, rather than `playing`, because\n\t\t\t\tvarious browsers (notably, mobile browsers) are poor at firing media events\n\t\t\t\tin a timely fashion, so we use `timeupdate` to ensure that we don't start\n\t\t\t\tthe fade until the track is actually progressing.\n\t\t\t*/\n\t\t\tjQuery(this.audio)\n\t\t\t\t.off('timeupdate.AudioTrack_fade')\n\t\t\t\t.one('timeupdate.AudioTrack_fade', () => {\n\t\t\t\t\tlet min;\n\t\t\t\t\tlet max;\n\n\t\t\t\t\t// Fade in.\n\t\t\t\t\tif (from < to) {\n\t\t\t\t\t\tmin = from;\n\t\t\t\t\t\tmax = to;\n\t\t\t\t\t}\n\t\t\t\t\t// Fade out.\n\t\t\t\t\telse {\n\t\t\t\t\t\tmin = to;\n\t\t\t\t\t\tmax = from;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst time     = Math.max(duration, 1);\n\t\t\t\t\tconst interval = 25; // in milliseconds\n\t\t\t\t\tconst delta    = (to - from) / (time / (interval / 1000));\n\n\t\t\t\t\tthis._trigger(':fading');\n\t\t\t\t\tthis._faderId = setInterval(() => {\n\t\t\t\t\t\tif (!this.isPlaying()) {\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tWhile it may seem like a good idea to also set the track volume\n\t\t\t\t\t\t\t\tto the `to` value here, we should not do so.  We cannot know why\n\t\t\t\t\t\t\t\tthe track is no longer playing, nor if the volume has been modified\n\t\t\t\t\t\t\t\tin the interim, so doing so now may clobber an end-user set volume.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tthis.fadeStop();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthis.volume(Math.clamp(this.volume() + delta, min, max));\n\n\t\t\t\t\t\tif (Config.audio.pauseOnFadeToZero && this.volume() === 0) {\n\t\t\t\t\t\t\tthis.pause();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.volume() === to) {\n\t\t\t\t\t\t\tthis.fadeStop();\n\t\t\t\t\t\t\tthis._trigger(':faded');\n\t\t\t\t\t\t}\n\t\t\t\t\t}, interval);\n\t\t\t\t});\n\n\t\t\treturn this.play();\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\treturn this.fade(duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\treturn this.fade(duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tif (this._faderId !== null) {\n\t\t\t\tclearInterval(this._faderId);\n\t\t\t\tthis._faderId = null;\n\t\t\t}\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\treturn this.audio.loop;\n\t\t\t}\n\n\t\t\tthis.audio.loop = !!loop;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\treturn this._mute;\n\t\t\t}\n\n\t\t\tthis._mute = !!mute;\n\t\t\tthis._updateAudioMute();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioMute() {\n\t\t\tthis.audio.muted = this._mute || _masterMute;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\treturn this._rate;\n\t\t\t}\n\n\t\t\tif (typeof rate !== 'number') {\n\t\t\t\tthrow new TypeError('rate parameter must be a number');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tClamp the playback rate to sane values—some browsers also do this to varying degrees.\n\n\t\t\t\tNOTE (ca. Aug 2016): The specification allows negative values for reverse playback,\n\t\t\t\thowever, most browsers either completely ignore negative values or clamp them to\n\t\t\t\tsome positive value.  In some (notably, IE & Edge), setting a negative playback\n\t\t\t\trate breaks the associated controls, if displayed.\n\t\t\t*/\n\t\t\t/*\n\t\t\tthis._rate = rate < 0\n\t\t\t\t? Math.clamp(rate, -0.2, -5) // clamp to 5× slower & faster, backward\n\t\t\t\t: Math.clamp(rate, 0.2, 5);  // clamp to 5× slower & faster, forward\n\t\t\t*/\n\t\t\tthis._rate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\t\t\tthis._updateAudioRate();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioRate() {\n\t\t\t/*\n\t\t\tconst rate = this._rate * _masterRate;\n\t\t\tthis.audio.playbackRate = rate < 0\n\t\t\t\t? Math.clamp(rate, -0.2, -5) // clamp to 5× slower & faster, backward\n\t\t\t\t: Math.clamp(rate, 0.2, 5);  // clamp to 5× slower & faster, forward\n\t\t\t*/\n\t\t\tthis.audio.playbackRate = Math.clamp(this._rate * _masterRate, 0.2, 5); // clamp to 5× slower & faster\n\t\t}\n\n\t\ttime(time) {\n\t\t\tif (time == null) { // lazy equality for null\n\t\t\t\treturn this.audio.currentTime;\n\t\t\t}\n\n\t\t\tif (typeof time !== 'number') {\n\t\t\t\tthrow new TypeError('time parameter must be a number');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tNOTE (historic): If we try to modify the audio clip's `.currentTime` property\n\t\t\t\tbefore its metadata has been loaded, it will throw an `InvalidStateError`\n\t\t\t\t(since it doesn't know its duration, allowing `.currentTime` to be set would\n\t\t\t\tbe undefined behavior), so in case an exception is thrown we provide a fallback\n\t\t\t\tusing the `loadedmetadata` event.\n\n\t\t\t\tNOTE (ca. 2016): This workaround should no longer be necessary in most browsers.\n\t\t\t\tThat said, it will still be required for some time to service legacy browsers.\n\n\t\t\t\tNOTE (ca. Dec 09, 2018): Firefox will still log an `InvalidStateError` to the\n\t\t\t\tconsole when attempting to modify the clip's `.currentTime` property before its\n\t\t\t\tmetadata has been loaded, even though it handles the situation properly—by waiting\n\t\t\t\tfor the metadata, as all browsers do now.  To prevent this spurious logging, we\n\t\t\t\tmust now manually check for the existence of the metadata and always failover to\n\t\t\t\tan event regardless of if the browser needs it or not—because I don't want to\n\t\t\t\tintroduce a browser check here.  Stay classy, Firefox.\n\t\t\t*/\n\t\t\tif (this.hasMetadata()) {\n\t\t\t\tthis.audio.currentTime = time;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery(this.audio)\n\t\t\t\t\t.off('loadedmetadata.AudioTrack_time')\n\t\t\t\t\t.one('loadedmetadata.AudioTrack_time', () => this.audio.currentTime = time);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\treturn this._volume;\n\t\t\t}\n\n\t\t\tif (typeof volume !== 'number') {\n\t\t\t\tthrow new TypeError('volume parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._volume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\t\t\tthis._updateAudioVolume();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioVolume() {\n\t\t\tthis.audio.volume = Math.clamp(this._volume * _masterVolume, 0, 1);\n\t\t}\n\n\t\tduration() {\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.audio.duration;\n\t\t}\n\n\t\tremaining() {\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.audio.duration - this.audio.currentTime;\n\t\t}\n\n\t\tisFailed() {\n\t\t\treturn this._error;\n\t\t}\n\n\t\tisLoading() {\n\t\t\treturn this.audio.networkState === HTMLMediaElement.NETWORK_LOADING;\n\t\t}\n\n\t\tisUnloaded() {\n\t\t\treturn !this.audio.hasChildNodes();\n\t\t}\n\n\t\tisUnavailable() {\n\t\t\treturn !this.hasSource() || this.isUnloaded() || this.isFailed();\n\t\t}\n\n\t\tisPlaying() {\n\t\t\t// NOTE: The `this.hasSomeData()` check is probably no longer necessary.\n\t\t\treturn !this.audio.paused && this.hasSomeData();\n\t\t}\n\n\t\tisPaused() {\n\t\t\t/*\n\t\t\t\tIf the selected audio resource is a stream, `currentTime` may return a non-zero\n\t\t\t\tvalue even at the earliest available position within the stream as the browser\n\t\t\t\tmay have dropped the earliest chunks of buffered data or the stream may have a\n\t\t\t\ttimeline which does not start at zero.\n\n\t\t\t\tIn an attempt to guard against these possiblities, as best as we can, we test\n\t\t\t\t`duration` against `Infinity` first, which should yield true for actual streams.\n\t\t\t*/\n\t\t\treturn this.audio.paused\n\t\t\t\t&& (this.audio.duration === Infinity || this.audio.currentTime > 0)\n\t\t\t\t&& !this.audio.ended;\n\t\t}\n\n\t\tisStopped() {\n\t\t\treturn this.audio.paused && this.audio.currentTime === 0;\n\t\t}\n\n\t\tisEnded() {\n\t\t\treturn this.audio.ended;\n\t\t}\n\n\t\tisFading() {\n\t\t\treturn this._faderId !== null;\n\t\t}\n\n\t\tisSeeking() {\n\t\t\treturn this.audio.seeking;\n\t\t}\n\n\t\thasSource() {\n\t\t\treturn this.sources.length > 0;\n\t\t}\n\n\t\thasNoData() {\n\t\t\treturn this.audio.readyState === HTMLMediaElement.HAVE_NOTHING;\n\t\t}\n\n\t\thasMetadata() {\n\t\t\treturn this.audio.readyState >= HTMLMediaElement.HAVE_METADATA;\n\t\t}\n\n\t\thasSomeData() {\n\t\t\treturn this.audio.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA;\n\t\t}\n\n\t\thasData() {\n\t\t\treturn this.audio.readyState === HTMLMediaElement.HAVE_ENOUGH_DATA;\n\t\t}\n\n\t\ton(...args) {\n\t\t\tjQuery.fn.on.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\tone(...args) {\n\t\t\tjQuery.fn.one.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\toff(...args) {\n\t\t\tjQuery.fn.off.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\t/*\n\t\t\tVerifies that the browser supports the given MIME-type and then retuns either\n\t\t\tthe MIME-type, if it is supported, or `null`, if it is not.\n\t\t*/\n\t\tstatic _verifyType(type) {\n\t\t\tif (!type || !Has.audio) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst cache = AudioTrack._types;\n\n\t\t\tif (!cache.hasOwnProperty(type)) {\n\t\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t\t// Some early implementations return 'no' instead of the empty string.\n\t\t\t\tcache[type] = audio.canPlayType(type).replace(/^no$/i, '') !== '';\n\t\t\t}\n\n\t\t\treturn cache[type] ? type : null;\n\t\t}\n\n\t\t/*\n\t\t\tRetuns the MIME-type associated with the given format-ID, if it is supported,\n\t\t\telsewise `null`.\n\t\t*/\n\t\tstatic getType(format) {\n\t\t\tif (!format || !Has.audio) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst known = AudioTrack.formats;\n\t\t\tconst id    = format.toLowerCase();\n\t\t\tconst type  = known.hasOwnProperty(id) ? known[id] : `audio/${id}`;\n\n\t\t\treturn AudioTrack._verifyType(type);\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the browser potentially supports a format.\n\t\t*/\n\t\tstatic canPlayFormat(format) {\n\t\t\treturn AudioTrack.getType(format) !== null;\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the browser potentially supports a MIME-type.\n\t\t*/\n\t\tstatic canPlayType(type) {\n\t\t\treturn AudioTrack._verifyType(type) !== null;\n\t\t}\n\t}\n\n\t// Attach the static data members.\n\tObject.defineProperties(AudioTrack, {\n\t\t/*\n\t\t\tFormat-ID to MIME-type mappings for common audio types.\n\n\t\t\tIn most cases, the codecs property should not be included with the MIME-type,\n\t\t\tas we have no way of knowing which codec was used—and the browser will figure\n\t\t\tit out.  Conversely, in cases where the relationship relationship between a\n\t\t\tformat-ID and a specific codec is strong, we should include the codecs property.\n\n\t\t\tNOTE: Caveats by browser/engine:\n\t\t\t\tOpera ≤12 (Presto) will return a false-negative if the codecs value is quoted\n\t\t\t\twith single quotes, requiring the use of either double quotes or no quotes.\n\n\t\t\t\tBlink-based browsers (e.g. Chrome, Opera ≥15) will return a false-negative\n\t\t\t\tfor WAVE audio if the preferred MIME-type of 'audio/wave' is specified,\n\t\t\t\trequiring the use of 'audio/wav' instead.\n\t\t*/\n\t\tformats : {\n\t\t\tvalue : { // Leave this object extensible for users.\n\t\t\t\t// AAC — MPEG-2 AAC audio; specific profiles vary, but commonly \"AAC-LC\".\n\t\t\t\taac : 'audio/aac',\n\n\t\t\t\t// CAF — Codecs vary.\n\t\t\t\tcaf     : 'audio/x-caf',\n\t\t\t\t'x-caf' : 'audio/x-caf',\n\n\t\t\t\t// MP3 — MPEG-1/-2 Layer-III audio.\n\t\t\t\tmp3  : 'audio/mpeg; codecs=\"mp3\"',\n\t\t\t\tmpeg : 'audio/mpeg; codecs=\"mp3\"',\n\n\t\t\t\t// MP4 — Codecs vary, but commonly \"mp4a.40.2\" (a.k.a. \"AAC-LC\").\n\t\t\t\tm4a     : 'audio/mp4',\n\t\t\t\tmp4     : 'audio/mp4',\n\t\t\t\t'x-m4a' : 'audio/mp4',\n\t\t\t\t'x-mp4' : 'audio/mp4',\n\n\t\t\t\t// OGG — Codecs vary, but commonly \"vorbis\" and, recently, \"opus\".\n\t\t\t\toga : 'audio/ogg',\n\t\t\t\togg : 'audio/ogg',\n\n\t\t\t\t// OPUS — Opus audio in an Ogg container.\n\t\t\t\topus : 'audio/ogg; codecs=\"opus\"',\n\n\t\t\t\t// WAVE — Codecs vary, but commonly \"1\" (1 is the FourCC for PCM/LPCM).\n\t\t\t\twav  : 'audio/wav',\n\t\t\t\twave : 'audio/wav',\n\n\t\t\t\t// WEBM — Codecs vary, but commonly \"vorbis\" and, recently, \"opus\".\n\t\t\t\tweba : 'audio/webm',\n\t\t\t\twebm : 'audio/webm'\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t\tCache of supported MIME-types.\n\t\t*/\n\t\t_types : {\n\t\t\tvalue : {}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAudioList Class.\n\t*******************************************************************************************************************/\n\tclass AudioList {\n\t\tconstructor(obj) {\n\t\t\t// Process the given array of track objects or AudioList object.\n\t\t\tif (obj instanceof Array) {\n\t\t\t\tthis._create(obj);\n\t\t\t}\n\t\t\telse if (obj instanceof AudioList) {\n\t\t\t\tthis._copy(obj);\n\t\t\t\t// this._create(obj.tracks);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('tracks parameter must be either an array, of track objects, or an AudioTrack instance');\n\t\t\t}\n\t\t}\n\n\t\t_create(trackList) {\n\t\t\t// Map the array of tracks to playlist track objects.\n\t\t\tthis._finalize(trackList.map(trackObj => {\n\t\t\t\tif (typeof trackObj !== 'object') { // lazy equality for null\n\t\t\t\t\tthrow new Error('tracks parameter array members must be objects');\n\t\t\t\t}\n\n\t\t\t\tlet own;\n\t\t\t\tlet rate;\n\t\t\t\tlet track;\n\t\t\t\tlet volume;\n\n\t\t\t\tif (trackObj instanceof AudioTrack) {\n\t\t\t\t\town    = true;\n\t\t\t\t\trate   = trackObj.rate();\n\t\t\t\t\ttrack  = trackObj.clone();\n\t\t\t\t\tvolume = trackObj.volume();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (!trackObj.hasOwnProperty('track')) {\n\t\t\t\t\t\tthrow new Error('track object missing required \"track\" property');\n\t\t\t\t\t}\n\t\t\t\t\telse if (!(trackObj.track instanceof AudioTrack)) {\n\t\t\t\t\t\tthrow new Error('track object\\'s \"track\" property must be an AudioTrack object');\n\t\t\t\t\t}\n\t\t\t\t\t// else if (!trackObj.hasOwnProperty('volume')) {\n\t\t\t\t\t// \tthrow new Error('track object missing required \"volume\" property');\n\t\t\t\t\t// }\n\n\t\t\t\t\town    = trackObj.hasOwnProperty('own') && trackObj.own;\n\t\t\t\t\trate   = trackObj.hasOwnProperty('rate') ? trackObj.rate : trackObj.track.rate();\n\t\t\t\t\ttrack  = trackObj.track;\n\t\t\t\t\tvolume = trackObj.hasOwnProperty('volume') ? trackObj.volume : trackObj.track.volume();\n\t\t\t\t}\n\n\t\t\t\ttrack.stop();\n\t\t\t\ttrack.loop(false);\n\t\t\t\ttrack.mute(false);\n\t\t\t\ttrack.rate(rate);\n\t\t\t\ttrack.volume(volume);\n\t\t\t\ttrack.on('ended.AudioList', () => this._onEnd());\n\n\t\t\t\treturn { own, track, volume, rate };\n\t\t\t}));\n\t\t}\n\n\t\t_copy(obj) {\n\t\t\tthis._finalize(clone(obj.tracks));\n\t\t}\n\n\t\t_finalize(tracks) {\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\ttracks : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : Object.freeze(tracks)\n\t\t\t\t},\n\n\t\t\t\tqueue : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : []\n\t\t\t\t},\n\n\t\t\t\tcurrent : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_rate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_volume : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_mute : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_loop : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_shuffle : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t_destroy() {\n\t\t\t/*\n\t\t\t\tStrictly speaking, self-destruction is not necessary as this object will,\n\t\t\t\teventually, be garbage collected.\n\t\t\t*/\n\t\t\t// Stop playback.\n\t\t\tthis.stop();\n\n\t\t\t// Destroy all owned tracks.\n\t\t\tthis.tracks\n\t\t\t\t.filter(trackObj => trackObj.own)\n\t\t\t\t.forEach(trackObj => trackObj.track._destroy());\n\n\t\t\t// Delete the reference-type properties.\n\t\t\tdelete this.tracks;\n\t\t\tdelete this.queue;\n\t\t}\n\n\t\tload() {\n\t\t\tthis.tracks.forEach(trackObj => trackObj.track.load());\n\t\t}\n\n\t\tunload() {\n\t\t\tthis.stop();\n\t\t\tthis.tracks.forEach(trackObj => trackObj.track.unload());\n\t\t}\n\n\t\tplay() {\n\t\t\tif (this.current === null || this.current.track.isUnavailable() || this.current.track.isEnded()) {\n\t\t\t\tif (this.queue.length === 0) {\n\t\t\t\t\tthis._fillQueue();\n\t\t\t\t}\n\n\t\t\t\tif (!this._next()) {\n\t\t\t\t\treturn Promise.reject(new Error('no tracks were available'));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.current.track.play();\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tthis.play().catch(() => {\n\t\t\t\tconst gestures = _gestureEventNames.map(name => `${name}.AudioList_playWhenAllowed`).join(' ');\n\t\t\t\tjQuery(document).one(gestures, () => {\n\t\t\t\t\tjQuery(document).off('.AudioList_playWhenAllowed');\n\t\t\t\t\tthis.play();\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tpause() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.pause();\n\t\t\t}\n\t\t}\n\n\t\tstop() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.stop();\n\t\t\t\tthis.current = null;\n\t\t\t}\n\n\t\t\tthis._drainQueue();\n\t\t}\n\n\t\tskip() {\n\t\t\tif (this._next()) {\n\t\t\t\tthis.current.track.play();\n\t\t\t}\n\t\t\telse if (this._loop) {\n\t\t\t\tthis.play();\n\t\t\t}\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (typeof duration !== 'number') {\n\t\t\t\tthrow new TypeError('duration parameter must be a number');\n\t\t\t}\n\t\t\tif (typeof toVol !== 'number') {\n\t\t\t\tthrow new TypeError('toVolume parameter must be a number');\n\t\t\t}\n\t\t\tif (fromVol != null && typeof fromVol !== 'number') { // lazy equality for null\n\t\t\t\tthrow new TypeError('fromVolume parameter must be a number');\n\t\t\t}\n\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\tthis._fillQueue();\n\t\t\t}\n\n\t\t\tif (this.current === null || this.current.track.isUnavailable() || this.current.track.isEnded()) {\n\t\t\t\tif (!this._next()) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst adjToVol = Math.clamp(toVol, 0, 1) * this.current.volume;\n\t\t\tlet adjFromVol;\n\n\t\t\tif (fromVol != null) { // lazy equality for null\n\t\t\t\tadjFromVol = Math.clamp(fromVol, 0, 1) * this.current.volume;\n\t\t\t}\n\n\t\t\tthis._volume = toVol; // NOTE: Kludgey, but necessary.\n\n\t\t\treturn this.current.track.fade(duration, adjToVol, adjFromVol);\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\treturn this.fade(duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\treturn this.fade(duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.fadeStop();\n\t\t\t}\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\treturn this._loop;\n\t\t\t}\n\n\t\t\tthis._loop = !!loop;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\treturn this._mute;\n\t\t\t}\n\n\t\t\tthis._mute = !!mute;\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.mute(this._mute);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\treturn this._rate;\n\t\t\t}\n\n\t\t\tif (typeof rate !== 'number') {\n\t\t\t\tthrow new TypeError('rate parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._rate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.rate(this._rate * this.current.rate);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tshuffle(shuffle) {\n\t\t\tif (shuffle == null) { // lazy equality for null\n\t\t\t\treturn this._shuffle;\n\t\t\t}\n\n\t\t\tthis._shuffle = !!shuffle;\n\n\t\t\tif (this.queue.length > 0) {\n\t\t\t\tthis._fillQueue();\n\n\t\t\t\t// Try not to immediately replay the last track when not shuffling.\n\t\t\t\tif (!this._shuffle && this.current !== null && this.queue.length > 1) {\n\t\t\t\t\tconst firstIdx = this.queue.findIndex(trackObj => trackObj === this.current);\n\n\t\t\t\t\tif (firstIdx !== -1) {\n\t\t\t\t\t\tthis.queue.push(...this.queue.splice(0, firstIdx + 1));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\treturn this._volume;\n\t\t\t}\n\n\t\t\tif (typeof volume !== 'number') {\n\t\t\t\tthrow new TypeError('volume parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._volume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.volume(this._volume * this.current.volume);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tduration() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('duration takes no parameters');\n\t\t\t}\n\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.tracks\n\t\t\t\t.map(trackObj => trackObj.track.duration())\n\t\t\t\t.reduce((prev, cur) => prev + cur, 0);\n\t\t}\n\n\t\tremaining() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('remaining takes no parameters');\n\t\t\t}\n\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\tlet remainingTime = this.queue\n\t\t\t\t.map(trackObj => trackObj.track.duration())\n\t\t\t\t.reduce((prev, cur) => prev + cur, 0);\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tremainingTime += this.current.track.remaining();\n\t\t\t}\n\n\t\t\treturn remainingTime;\n\t\t}\n\n\t\ttime() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('time takes no parameters');\n\t\t\t}\n\n\t\t\treturn this.duration() - this.remaining();\n\t\t}\n\n\t\tisPlaying() {\n\t\t\treturn this.current !== null && this.current.track.isPlaying();\n\t\t}\n\n\t\tisPaused() {\n\t\t\treturn this.current === null || this.current.track.isPaused();\n\t\t}\n\n\t\tisStopped() {\n\t\t\treturn this.queue.length === 0 && this.current === null;\n\t\t}\n\n\t\tisEnded() {\n\t\t\treturn this.queue.length === 0 && (this.current === null || this.current.track.isEnded());\n\t\t}\n\n\t\tisFading() {\n\t\t\treturn this.current !== null && this.current.track.isFading();\n\t\t}\n\n\t\t_next() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.stop();\n\t\t\t\tthis.current = null;\n\t\t\t}\n\n\t\t\tlet nextTrack;\n\n\t\t\twhile ((nextTrack = this.queue.shift())) {\n\t\t\t\tif (!nextTrack.track.isUnavailable()) {\n\t\t\t\t\tthis.current = nextTrack;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.current === null) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis.current.track.mute(this._mute);\n\t\t\tthis.current.track.rate(this._rate * this.current.rate);\n\t\t\tthis.current.track.volume(this._volume * this.current.volume);\n\n\t\t\t// Attempt to protect against the `loop` state being reenabled\n\t\t\t// outside of the playlist.  Mostly for unowned tracks.\n\t\t\t//\n\t\t\t// TODO: Should we reapply the `ended` event handler too?\n\t\t\tthis.current.track.loop(false);\n\n\t\t\treturn true;\n\t\t}\n\n\t\t_onEnd() {\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\tif (!this._loop) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._fillQueue();\n\t\t\t}\n\n\t\t\tif (!this._next()) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.current.track.play();\n\t\t}\n\n\t\t_drainQueue() {\n\t\t\tthis.queue.splice(0);\n\t\t}\n\n\t\t_fillQueue() {\n\t\t\tthis._drainQueue();\n\t\t\tthis.queue.push(...this.tracks.filter(trackObj => !trackObj.track.isUnavailable()));\n\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (this._shuffle) {\n\t\t\t\tthis.queue.shuffle();\n\n\t\t\t\t// Try not to immediately replay the last track when shuffling.\n\t\t\t\tif (this.queue.length > 1 && this.queue[0] === this.current) {\n\t\t\t\t\tthis.queue.push(this.queue.shift());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAudioRunner Class.\n\t*******************************************************************************************************************/\n\tclass AudioRunner {\n\t\tconstructor(list) {\n\t\t\tif (!(list instanceof Set || list instanceof AudioRunner)) {\n\t\t\t\tthrow new TypeError('list parameter must be a Set or a AudioRunner instance');\n\t\t\t}\n\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\ttrackIds : {\n\t\t\t\t\tvalue : new Set(list instanceof AudioRunner ? list.trackIds : list)\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tload() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.load);\n\t\t}\n\n\t\tunload() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.unload);\n\t\t}\n\n\t\tplay() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.play);\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.playWhenAllowed);\n\t\t}\n\n\t\tpause() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.pause);\n\t\t}\n\n\t\tstop() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.stop);\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (duration == null || toVol == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fade requires parameters');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fade, duration, toVol, fromVol);\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\tif (duration == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fadeIn requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeIn, duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\tif (duration == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fadeOut requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeOut, duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeStop);\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\tthrow new Error('loop requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.loop, loop);\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\tthrow new Error('mute requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.mute, mute);\n\t\t\treturn this;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\tthrow new Error('rate requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.rate, rate);\n\t\t\treturn this;\n\t\t}\n\n\t\ttime(time) {\n\t\t\tif (time == null) { // lazy equality for null\n\t\t\t\tthrow new Error('time requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.time, time);\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\tthrow new Error('volume requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.volume, volume);\n\t\t\treturn this;\n\t\t}\n\n\t\ton(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.on, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\tone(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.one, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\toff(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.off, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\tstatic _run(ids, fn, ...args) {\n\t\t\tids.forEach(id => {\n\t\t\t\tconst track = _tracks.get(id);\n\n\t\t\t\tif (track) {\n\t\t\t\t\tfn.apply(track, args);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTrack Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.tracks.add(trackId, sources…);\n\n\t\tE.g.\n\t\t\tSimpleAudio.tracks.add(\n\t\t\t\t'over_the_top',\n\t\t\t\t'https://audiohost.tld/id/over_the_top.mp3',\n\t\t\t\t'https://audiohost.tld/id/over_the_top.ogg'\n\t\t\t);\n\t*/\n\tfunction trackAdd(/* trackId , sources… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('track ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('sources'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `track ID \"${id}\"`;\n\n\t\tif (_badIdRe.test(id)) {\n\t\t\tthrow new Error(`invalid ${what}: track IDs must not contain colons or whitespace`);\n\t\t}\n\n\t\tconst sources = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet track;\n\n\t\ttry {\n\t\t\ttrack = _newTrack(sources);\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during track initialization: ${ex.message}`);\n\t\t}\n\n\t\t// If in Test Mode and no supported sources were specified, throw an error.\n\t\tif (Config.debug && !track.hasSource()) {\n\t\t\tthrow new Error(`${what}: no supported audio sources found`);\n\t\t}\n\n\t\t// If a track by the given ID already exists, destroy it.\n\t\tif (_tracks.has(id)) {\n\t\t\t_tracks.get(id)._destroy();\n\t\t}\n\n\t\t// Add the track to the cache.\n\t\t_tracks.set(id, track);\n\t}\n\n\tfunction trackDelete(id) {\n\t\tif (_tracks.has(id)) {\n\t\t\t_tracks.get(id)._destroy();\n\t\t}\n\n\t\t// TODO: Should this also remove references to the track from groups and playlists?\n\n\t\treturn _tracks.delete(id);\n\t}\n\n\tfunction trackClear() {\n\t\t_tracks.forEach(track => track._destroy());\n\t\t_tracks.clear();\n\t}\n\n\tfunction trackHas(id) {\n\t\treturn _tracks.has(id);\n\t}\n\n\tfunction trackGet(id) {\n\t\treturn _tracks.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tGroup Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.groups.add(groupId, trackIds…);\n\n\t\tE.g.\n\t\t\tSimpleAudio.groups.add(':ui', 'beep', 'boop', 'boing');\n\t*/\n\tfunction groupAdd(/* groupId , trackIds… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('group ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('track IDs'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `group ID \"${id}\"`;\n\n\t\tif (id[0] !== ':' || _badIdRe.test(id.slice(1))) {\n\t\t\tthrow new Error(`invalid ${what}: group IDs must start with a colon and must not contain colons or whitespace`);\n\t\t}\n\n\t\tif (_specialIds.includes(id)) {\n\t\t\tthrow new Error(`cannot clobber special ${what}`);\n\t\t}\n\n\t\tconst trackIds = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet group;\n\n\t\ttry {\n\t\t\tgroup = new Set(trackIds.map(trackId => {\n\t\t\t\tif (!_tracks.has(trackId)) {\n\t\t\t\t\tthrow new Error(`track \"${trackId}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\treturn trackId;\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during group initialization: ${ex.message}`);\n\t\t}\n\n\t\t// Add the group to the cache.\n\t\t_groups.set(id, Object.freeze(Array.from(group)));\n\t}\n\n\tfunction groupDelete(id) {\n\t\treturn _groups.delete(id);\n\t}\n\n\tfunction groupClear() {\n\t\t_groups.clear();\n\t}\n\n\tfunction groupHas(id) {\n\t\treturn _groups.has(id);\n\t}\n\n\tfunction groupGet(id) {\n\t\treturn _groups.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPlaylist Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.lists.add(listId, sources…);\n\t\t\tWhere `sources` may be either a track ID or descriptor (object).\n\t\t\tTrack descriptors are either { id, [own], [rate], [volume] } or { sources, [rate], [volume] }.\n\n\t\tNOTE: Rate properties are currently unsupported due to poor browser support.\n\n\t\tE.g.\n\t\t\tSimpleAudio.lists.add(\n\t\t\t\t'bgm',\n\t\t\t\t'over_the_top',\n\t\t\t\t{\n\t\t\t\t\tid     : 'heavens_a_lie',\n\t\t\t\t\tvolume : 0.5,\n\t\t\t\t\town    : true\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tsources : [\n\t\t\t\t\t\t'https://audiohost.tld/id/swamped.mp3',\n\t\t\t\t\t\t'https://audiohost.tld/id/swamped.ogg'\n\t\t\t\t\t],\n\t\t\t\t\tvolume  : 0.75\n\t\t\t\t}\n\t\t\t);\n\t*/\n\tfunction listAdd(/* listId , sources… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('list ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('track IDs'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `list ID \"${id}\"`;\n\n\t\tif (_badIdRe.test(id)) {\n\t\t\treturn this.error(`invalid ${what}: list IDs must not contain colons or whitespace`);\n\t\t}\n\n\t\tconst descriptors = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet list;\n\n\t\ttry {\n\t\t\tlist = new AudioList(descriptors.map(desc => {\n\t\t\t\tif (desc === null) {\n\t\t\t\t\tthrow new Error('track descriptor must be a string or object (type: null)');\n\t\t\t\t}\n\n\t\t\t\tswitch (typeof desc) {\n\t\t\t\tcase 'string':\n\t\t\t\t\t// Simply a track ID, so convert it into an object.\n\t\t\t\t\tdesc = { id : desc }; // eslint-disable-line no-param-reassign\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\tif (!desc.hasOwnProperty('id') && !desc.hasOwnProperty('sources')) {\n\t\t\t\t\t\tthrow new Error('track descriptor must contain one of either an \"id\" or a \"sources\" property');\n\t\t\t\t\t}\n\t\t\t\t\telse if (desc.hasOwnProperty('id') && desc.hasOwnProperty('sources')) {\n\t\t\t\t\t\tthrow new Error('track descriptor must contain either an \"id\" or a \"sources\" property, not both');\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`track descriptor must be a string or object (type: ${typeof desc})`);\n\t\t\t\t}\n\n\t\t\t\tlet own;\n\t\t\t\t// let rate;\n\t\t\t\tlet track;\n\t\t\t\tlet volume;\n\n\t\t\t\tif (desc.hasOwnProperty('id')) {\n\t\t\t\t\tif (typeof desc.id !== 'string') {\n\t\t\t\t\t\tthrow new Error('\"id\" property must be a string');\n\t\t\t\t\t}\n\t\t\t\t\tif (!_tracks.has(desc.id)) {\n\t\t\t\t\t\tthrow new Error(`track \"${desc.id}\" does not exist`);\n\t\t\t\t\t}\n\n\t\t\t\t\ttrack = _tracks.get(desc.id);\n\t\t\t\t}\n\t\t\t\telse if (desc.hasOwnProperty('sources')) {\n\t\t\t\t\tif (!Array.isArray(desc.sources) || desc.sources.length === 0) {\n\t\t\t\t\t\tthrow new Error('\"sources\" property must be a non-empty array');\n\t\t\t\t\t}\n\t\t\t\t\tif (desc.hasOwnProperty('own')) {\n\t\t\t\t\t\tthrow new Error('\"own\" property is not allowed with the \"sources\" property');\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\ttrack = _newTrack(desc.sources);\n\t\t\t\t\t\town = true;\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`error during track initialization: ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// If in Test Mode and no supported sources were specified, return an error.\n\t\t\t\t\tif (Config.debug && !track.hasSource()) {\n\t\t\t\t\t\tthrow new Error('no supported audio sources found');\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (desc.hasOwnProperty('own')) {\n\t\t\t\t\tif (typeof desc.own !== 'boolean') {\n\t\t\t\t\t\tthrow new Error('\"own\" property must be a boolean');\n\t\t\t\t\t}\n\n\t\t\t\t\town = desc.own;\n\n\t\t\t\t\tif (own) {\n\t\t\t\t\t\ttrack = track.clone();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if (desc.hasOwnProperty('rate')) {\n\t\t\t\t// \tif (\n\t\t\t\t// \t\t   typeof desc.rate !== 'number'\n\t\t\t\t// \t\t|| Number.isNaN(desc.rate)\n\t\t\t\t// \t\t|| !Number.isFinite(desc.rate)\n\t\t\t\t// \t) {\n\t\t\t\t// \t\tthrow new Error('\"rate\" property must be a finite number');\n\t\t\t\t// \t}\n\t\t\t\t//\n\t\t\t\t// \trate = desc.rate;\n\t\t\t\t// }\n\n\t\t\t\tif (desc.hasOwnProperty('volume')) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t   typeof desc.volume !== 'number'\n\t\t\t\t\t\t|| Number.isNaN(desc.volume)\n\t\t\t\t\t\t|| !Number.isFinite(desc.volume)\n\t\t\t\t\t\t|| desc.volume < 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new Error('\"volume\" property must be a non-negative finite number');\n\t\t\t\t\t}\n\n\t\t\t\t\tvolume = desc.volume;\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\town    : own != null ? own : false, // lazy equality for null,\n\t\t\t\t\t// rate   : rate != null ? rate : track.rate(), // lazy equality for null,\n\t\t\t\t\ttrack,\n\t\t\t\t\tvolume : volume != null ? volume : track.volume() // lazy equality for null\n\t\t\t\t};\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during playlist initialization: ${ex.message}`);\n\t\t}\n\n\t\t// If a playlist by the given ID already exists, destroy it.\n\t\tif (_lists.has(id)) {\n\t\t\t_lists.get(id)._destroy();\n\t\t}\n\n\t\t// Add the playlist to the cache.\n\t\t_lists.set(id, list);\n\t}\n\n\tfunction listDelete(id) {\n\t\tif (_lists.has(id)) {\n\t\t\t_lists.get(id)._destroy();\n\t\t}\n\n\t\treturn _lists.delete(id);\n\t}\n\n\tfunction listClear() {\n\t\t_lists.forEach(list => list._destroy());\n\t\t_lists.clear();\n\t}\n\n\tfunction listHas(id) {\n\t\treturn _lists.has(id);\n\t}\n\n\tfunction listGet(id) {\n\t\treturn _lists.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tRunner Functions.\n\t*******************************************************************************************************************/\n\tconst _runnerParseSelector = (() => {\n\t\tconst notWsRe = /\\S/g;\n\t\tconst parenRe = /[()]/g;\n\n\t\tfunction processNegation(str, startPos) {\n\t\t\tlet match;\n\n\t\t\tnotWsRe.lastIndex = startPos;\n\t\t\tmatch = notWsRe.exec(str);\n\n\t\t\tif (match === null || match[0] !== '(') {\n\t\t\t\tthrow new Error('invalid \":not()\" syntax: missing parentheticals');\n\t\t\t}\n\n\t\t\tparenRe.lastIndex = notWsRe.lastIndex;\n\t\t\tconst start  = notWsRe.lastIndex;\n\t\t\tconst result = { str : '', nextMatch : -1 };\n\t\t\tlet depth = 1;\n\n\t\t\twhile ((match = parenRe.exec(str)) !== null) {\n\t\t\t\tif (match[0] === '(') {\n\t\t\t\t\t++depth;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t--depth;\n\t\t\t\t}\n\n\t\t\t\tif (depth < 1) {\n\t\t\t\t\tresult.nextMatch = parenRe.lastIndex;\n\t\t\t\t\tresult.str = str.slice(start, result.nextMatch - 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tfunction parseSelector(idArg) {\n\t\t\tconst ids  = [];\n\t\t\tconst idRe = /:?[^\\s:()]+/g;\n\t\t\tlet match;\n\n\t\t\twhile ((match = idRe.exec(idArg)) !== null) {\n\t\t\t\tconst id = match[0];\n\n\t\t\t\t// Group negation.\n\t\t\t\tif (id === ':not') {\n\t\t\t\t\tif (ids.length === 0) {\n\t\t\t\t\t\tthrow new Error('invalid negation: no group ID preceded \":not()\"');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst parent = ids[ids.length - 1];\n\n\t\t\t\t\tif (parent.id[0] !== ':') {\n\t\t\t\t\t\tthrow new Error(`invalid negation of track \"${parent.id}\": only groups may be negated with \":not()\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst negation = processNegation(idArg, idRe.lastIndex);\n\n\t\t\t\t\tif (negation.nextMatch === -1) {\n\t\t\t\t\t\tthrow new Error('unknown error parsing \":not()\"');\n\t\t\t\t\t}\n\n\t\t\t\t\tidRe.lastIndex = negation.nextMatch;\n\t\t\t\t\tparent.not = parseSelector(negation.str);\n\t\t\t\t}\n\n\t\t\t\t// Group or track ID.\n\t\t\t\telse {\n\t\t\t\t\tids.push({ id });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn ids;\n\t\t}\n\n\t\treturn parseSelector;\n\t})();\n\n\t/*\n\t\tSimpleAudio.select(selector).…;\n\n\t\tE.g.\n\t\t\tSimpleAudio.select(':ui').…\n\t\t\tSimpleAudio.select(':ui:not(boop)').…\n\t\t\tSimpleAudio.select('boop beep').…\n\t\t\tSimpleAudio.select(':ui :sfx').…\n\t\t\tSimpleAudio.select(':ui:not(boop) :sfx overthetop').…\n\t*/\n\tfunction runnerGet(/* selector */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('no track selector specified');\n\t\t}\n\n\t\tconst selector = String(arguments[0]).trim();\n\t\tconst trackIds = new Set();\n\n\t\ttry {\n\t\t\tconst allIds = Array.from(_tracks.keys());\n\n\t\t\tfunction renderIds(idObj) {\n\t\t\t\tconst id = idObj.id;\n\t\t\t\tlet ids;\n\n\t\t\t\tswitch (id) {\n\t\t\t\tcase ':all':     ids = allIds; break;\n\t\t\t\tcase ':looped':  ids = allIds.filter(id => _tracks.get(id).loop()); break;\n\t\t\t\tcase ':muted':   ids = allIds.filter(id => _tracks.get(id).mute()); break;\n\t\t\t\tcase ':paused':  ids = allIds.filter(id => _tracks.get(id).isPaused()); break;\n\t\t\t\tcase ':playing': ids = allIds.filter(id => _tracks.get(id).isPlaying()); break;\n\t\t\t\tdefault:         ids = id[0] === ':' ? _groups.get(id) : [id]; break;\n\t\t\t\t}\n\n\t\t\t\tif (idObj.hasOwnProperty('not')) {\n\t\t\t\t\tconst negated = idObj.not.map(idObj => renderIds(idObj)).flat(Infinity);\n\t\t\t\t\tids = ids.filter(id => !negated.includes(id));\n\t\t\t\t}\n\n\t\t\t\treturn ids;\n\t\t\t}\n\n\t\t\t_runnerParseSelector(selector).forEach(idObj => renderIds(idObj).forEach(id => {\n\t\t\t\tif (!_tracks.has(id)) {\n\t\t\t\t\tthrow new Error(`track \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\ttrackIds.add(id);\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`error during runner initialization: ${ex.message}`);\n\t\t}\n\n\t\treturn new AudioRunner(trackIds);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMaster Audio Functions.\n\t*******************************************************************************************************************/\n\tfunction masterLoad() {\n\t\tpublish('load');\n\t}\n\n\tfunction masterLoadWithScreen() {\n\t\tpublish('loadwithscreen');\n\t}\n\n\tfunction masterMute(mute) {\n\t\tif (mute == null) { // lazy equality for null\n\t\t\treturn _masterMute;\n\t\t}\n\n\t\t_masterMute = !!mute;\n\t\tpublish('mute', _masterMute);\n\t}\n\n\tfunction masterMuteOnHidden(mute) {\n\t\t// NOTE: Some older browsers—notably: IE 9—do not support the Page Visibility API.\n\t\tif (!Visibility.isEnabled()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (mute == null) { // lazy equality for null\n\t\t\treturn _masterMuteOnHidden;\n\t\t}\n\n\t\t_masterMuteOnHidden = !!mute;\n\n\t\tconst namespace = '.SimpleAudio_masterMuteOnHidden';\n\n\t\tif (_masterMuteOnHidden) {\n\t\t\tconst visibilityChange = `${Visibility.changeEvent}${namespace}`;\n\t\t\tjQuery(document)\n\t\t\t\t.off(namespace)\n\t\t\t\t.on(visibilityChange, () => masterMute(Visibility.isHidden()));\n\n\t\t\t// Only change the mute state initially if hidden.\n\t\t\tif (Visibility.isHidden()) {\n\t\t\t\tmasterMute(true);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tjQuery(document).off(namespace);\n\t\t}\n\t}\n\n\tfunction masterRate(rate) {\n\t\tif (rate == null) { // lazy equality for null\n\t\t\treturn _masterRate;\n\t\t}\n\n\t\tif (typeof rate !== 'number' || Number.isNaN(rate) || !Number.isFinite(rate)) {\n\t\t\tthrow new Error('rate must be a finite number');\n\t\t}\n\n\t\t_masterRate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\t\tpublish('rate', _masterRate);\n\t}\n\n\tfunction masterStop() {\n\t\tpublish('stop');\n\t}\n\n\tfunction masterUnload() {\n\t\tpublish('unload');\n\t}\n\n\tfunction masterVolume(volume) {\n\t\tif (volume == null) { // lazy equality for null\n\t\t\treturn _masterVolume;\n\t\t}\n\n\t\tif (typeof volume !== 'number' || Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\tthrow new Error('volume must be a finite number');\n\t\t}\n\n\t\t_masterVolume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\t\tpublish('volume', _masterVolume);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSubscription Functions.\n\t*******************************************************************************************************************/\n\tfunction subscribe(id, callback) {\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new Error('callback parameter must be a function');\n\t\t}\n\n\t\t_subscribers.set(id, callback);\n\t}\n\n\tfunction unsubscribe(id) {\n\t\t_subscribers.delete(id);\n\t}\n\n\tfunction publish(mesg, data) {\n\t\t_subscribers.forEach(fn => fn(mesg, data));\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _newTrack(sources) {\n\t\treturn new AudioTrack(sources.map(source => {\n\t\t\t// Handle audio passages.\n\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\tif (passage.tags.includes('Twine.audio')) {\n\t\t\t\t\treturn passage.text.trim();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle URIs—possibly prefixed with a format specifier.\n\t\t\tconst match = _formatSpecRe.exec(source);\n\t\t\treturn match === null ? source : {\n\t\t\t\tformat : match[1],\n\t\t\t\tsrc    : match[2]\n\t\t\t};\n\t\t}));\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Track Functions.\n\t\ttracks : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : trackAdd },\n\t\t\t\tdelete : { value : trackDelete },\n\t\t\t\tclear  : { value : trackClear },\n\t\t\t\thas    : { value : trackHas },\n\t\t\t\tget    : { value : trackGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Group Functions.\n\t\tgroups : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : groupAdd },\n\t\t\t\tdelete : { value : groupDelete },\n\t\t\t\tclear  : { value : groupClear },\n\t\t\t\thas    : { value : groupHas },\n\t\t\t\tget    : { value : groupGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Playlist Functions.\n\t\tlists : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : listAdd },\n\t\t\t\tdelete : { value : listDelete },\n\t\t\t\tclear  : { value : listClear },\n\t\t\t\thas    : { value : listHas },\n\t\t\t\tget    : { value : listGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Runner Functions.\n\t\tselect : { value : runnerGet },\n\n\t\t// Master Audio Functions.\n\t\tload           : { value : masterLoad },\n\t\tloadWithScreen : { value : masterLoadWithScreen },\n\t\tmute           : { value : masterMute },\n\t\tmuteOnHidden   : { value : masterMuteOnHidden },\n\t\trate           : { value : masterRate },\n\t\tstop           : { value : masterStop },\n\t\tunload         : { value : masterUnload },\n\t\tvolume         : { value : masterVolume }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tstate.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Diff, Engine, PRNGWrapper, Patterns, clone, session, storage */\n\nvar State = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// History moment stack.\n\tlet _history = [];\n\n\t// Currently active/played moment.\n\tlet _active = momentCreate();\n\n\t// Currently active/played moment index.\n\tlet _activeIndex = -1;\n\n\t// Titles of all moments which have expired (i.e. fallen off the bottom of the stack).\n\tlet _expired = [];\n\n\t// (optional) Seedable PRNG object.\n\tlet _prng = null;\n\n\t// Temporary variables object.\n\tlet _tempVariables = {};\n\n\n\t/*******************************************************************************************************************\n\t\tState Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tResets the story state.\n\t*/\n\tfunction stateReset() {\n\t\tif (DEBUG) { console.log('[State/stateReset()]'); }\n\n\t\t/*\n\t\t\tDelete the active session.\n\t\t*/\n\t\tsession.delete('state');\n\n\t\t/*\n\t\t\tReset the properties.\n\t\t*/\n\t\t_history     = [];\n\t\t_active      = momentCreate();\n\t\t_activeIndex = -1;\n\t\t_expired     = [];\n\t\t_prng        = _prng === null ? null : new PRNGWrapper(_prng.seed, false);\n\t}\n\n\t/*\n\t\tRestores the story state from the active session.\n\t*/\n\tfunction stateRestore() {\n\t\tif (DEBUG) { console.log('[State/stateRestore()]'); }\n\n\t\t/*\n\t\t\tAttempt to restore an active session.\n\t\t*/\n\t\tif (session.has('state')) {\n\t\t\t/*\n\t\t\t\tRetrieve the session.\n\t\t\t*/\n\t\t\tconst stateObj = session.get('state');\n\n\t\t\tif (DEBUG) { console.log('\\tsession state:', stateObj); }\n\n\t\t\tif (stateObj == null) { // lazy equality for null\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tRestore the session.\n\t\t\t*/\n\t\t\tstateUnmarshal(stateObj);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tReturns the current story state marshaled into a serializable object.\n\t*/\n\tfunction stateMarshal(noDelta) {\n\t\t/*\n\t\t\tGather the properties.\n\t\t*/\n\t\tconst stateObj = {\n\t\t\tindex : _activeIndex\n\t\t};\n\n\t\tif (noDelta) {\n\t\t\tstateObj.history = clone(_history);\n\t\t}\n\t\telse {\n\t\t\tstateObj.delta = historyDeltaEncode(_history);\n\t\t}\n\n\t\tif (_expired.length > 0) {\n\t\t\tstateObj.expired = [];\n\t\t}\n\n\t\tif (_prng !== null) {\n\t\t\tstateObj.seed = _prng.seed;\n\t\t}\n\n\t\treturn stateObj;\n\t}\n\n\t/*\n\t\tRestores the story state from a marshaled story state serialization object.\n\t*/\n\tfunction stateUnmarshal(stateObj, noDelta) {\n\t\tif (stateObj == null) { // lazy equality for null\n\t\t\tthrow new Error('state object is null or undefined');\n\t\t}\n\n\t\tif (\n\t\t\t   !stateObj.hasOwnProperty(noDelta ? 'history' : 'delta')\n\t\t\t|| stateObj[noDelta ? 'history' : 'delta'].length === 0\n\t\t) {\n\t\t\tthrow new Error('state object has no history or history is empty');\n\t\t}\n\n\t\tif (!stateObj.hasOwnProperty('index')) {\n\t\t\tthrow new Error('state object has no index');\n\t\t}\n\n\t\tif (_prng !== null && !stateObj.hasOwnProperty('seed')) {\n\t\t\tthrow new Error('state object has no seed, but PRNG is enabled');\n\t\t}\n\n\t\tif (_prng === null && stateObj.hasOwnProperty('seed')) {\n\t\t\tthrow new Error('state object has seed, but PRNG is disabled');\n\t\t}\n\n\t\t/*\n\t\t\tRestore the properties.\n\t\t*/\n\t\t_history     = noDelta ? clone(stateObj.history) : historyDeltaDecode(stateObj.delta);\n\t\t_activeIndex = stateObj.index;\n\t\t_expired     = stateObj.hasOwnProperty('expired') ? [...stateObj.expired] : [];\n\n\t\tif (stateObj.hasOwnProperty('seed')) {\n\t\t\t/*\n\t\t\t\tWe only need to restore the PRNG's seed here as `momentActivate()` will handle\n\t\t\t\tfully restoring the PRNG to its proper state.\n\t\t\t*/\n\t\t\t_prng.seed = stateObj.seed;\n\t\t}\n\n\t\t/*\n\t\t\tActivate the current moment (do this only after all properties have been restored).\n\t\t*/\n\t\tmomentActivate(_activeIndex);\n\t}\n\n\t/*\n\t\tReturns the current story state marshaled into a save-compatible serializable object.\n\t*/\n\tfunction stateMarshalForSave() {\n\t\treturn stateMarshal(true);\n\t}\n\n\t/*\n\t\tRestores the story state from a marshaled save-compatible story state serialization object.\n\t*/\n\tfunction stateUnmarshalForSave(stateObj) {\n\t\treturn stateUnmarshal(stateObj, true);\n\t}\n\n\t/*\n\t\tReturns the titles of expired moments.\n\t*/\n\tfunction stateExpired() {\n\t\treturn _expired;\n\t}\n\n\t/*\n\t\tReturns the total number of played moments (expired + in-play history moments).\n\t*/\n\tfunction stateTurns() {\n\t\treturn _expired.length + historyLength();\n\t}\n\n\t/*\n\t\tReturns the passage titles of all played moments (expired + in-play history moments).\n\t*/\n\tfunction stateTitles() {\n\t\treturn _expired.concat(_history.slice(0, historyLength()).map(moment => moment.title));\n\t}\n\n\t/*\n\t\tReturns whether a passage with the given title has been played (expired + in-play history moments).\n\t*/\n\tfunction stateHasPlayed(title) {\n\t\tif (title == null || title === '') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tif (_expired.includes(title)) {\n\t\t\treturn true;\n\t\t}\n\t\telse if (_history.slice(0, historyLength()).some(moment => moment.title === title)) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMoment Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a new moment object created from the given passage title and variables object.\n\t*/\n\tfunction momentCreate(title, variables) {\n\t\treturn {\n\t\t\ttitle     : title == null ? '' : String(title), // lazy equality for null\n\t\t\tvariables : variables == null ? {} : variables   // lazy equality for null\n\t\t};\n\t}\n\n\t/*\n\t\tReturns the active (present) moment.\n\t*/\n\tfunction momentActive() {\n\t\treturn _active;\n\t}\n\n\t/*\n\t\tReturns the index within the history of the active (present) moment.\n\t*/\n\tfunction momentActiveIndex() {\n\t\treturn _activeIndex;\n\t}\n\n\t/*\n\t\tReturns the title from the active (present) moment.\n\t*/\n\tfunction momentActiveTitle() {\n\t\treturn _active.title;\n\t}\n\n\t/*\n\t\tReturns the variables from the active (present) moment.\n\t*/\n\tfunction momentActiveVariables() {\n\t\treturn _active.variables;\n\t}\n\n\t/*\n\t\tReturns the active (present) moment after setting it to either the given moment object\n\t\tor the moment object at the given history index.  Additionally, updates the active session\n\t\tand triggers a history update event.\n\t*/\n\tfunction momentActivate(moment) {\n\t\tif (moment == null) { // lazy equality for null\n\t\t\tthrow new Error('moment activation attempted with null or undefined');\n\t\t}\n\n\t\t/*\n\t\t\tSet the active moment.\n\t\t*/\n\t\tswitch (typeof moment) {\n\t\tcase 'object':\n\t\t\t_active = clone(moment);\n\t\t\tbreak;\n\n\t\tcase 'number':\n\t\t\tif (historyIsEmpty()) {\n\t\t\t\tthrow new Error('moment activation attempted with index on empty history');\n\t\t\t}\n\n\t\t\tif (moment < 0 || moment >= historySize()) {\n\t\t\t\tthrow new RangeError(`moment activation attempted with out-of-bounds index; need [0, ${historySize() - 1}], got ${moment}`);\n\t\t\t}\n\n\t\t\t_active = clone(_history[moment]);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new TypeError(`moment activation attempted with a \"${typeof moment}\"; must be an object or valid history stack index`);\n\t\t}\n\n\t\t/*\n\t\t\tRestore the seedable PRNG.\n\n\t\t\tNOTE: We cannot simply set `_prng.pull` to `_active.pull` as that would\n\t\t\tnot properly mutate the PRNG's internal state.\n\t\t*/\n\t\tif (_prng !== null) {\n\t\t\t_prng = PRNGWrapper.unmarshal({\n\t\t\t\tseed : _prng.seed,\n\t\t\t\tpull : _active.pull\n\t\t\t});\n\t\t}\n\n\t\t/*\n\t\t\tUpdate the active session.\n\t\t*/\n\t\tsession.set('state', stateMarshal());\n\n\t\t/*\n\t\t\tTrigger a global `:historyupdate` event.\n\n\t\t\tNOTE: We do this here because setting a new active moment is a core component\n\t\t\tof, virtually, all history updates.\n\t\t*/\n\t\tjQuery.event.trigger(':historyupdate');\n\n\t\treturn _active;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tHistory Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the moment history.\n\t*/\n\tfunction historyGet() {\n\t\treturn _history;\n\t}\n\n\t/*\n\t\tReturns the number of active history moments (past only).\n\t*/\n\tfunction historyLength() {\n\t\treturn _activeIndex + 1;\n\t}\n\n\t/*\n\t\tReturns the total number of history moments (past + future).\n\t*/\n\tfunction historySize() {\n\t\treturn _history.length;\n\t}\n\n\t/*\n\t\tReturns whether the history is empty.\n\t*/\n\tfunction historyIsEmpty() {\n\t\treturn _history.length === 0;\n\t}\n\n\t/*\n\t\tReturns the current (pre-play version of the active) moment within the history.\n\t*/\n\tfunction historyCurrent() {\n\t\treturn _history.length > 0 ? _history[_activeIndex] : null;\n\t}\n\n\t/*\n\t\tReturns the topmost (most recent) moment within the history.\n\t*/\n\tfunction historyTop() {\n\t\treturn _history.length > 0 ? _history[_history.length - 1] : null;\n\t}\n\n\t/*\n\t\tReturns the bottommost (least recent) moment within the history.\n\t*/\n\tfunction historyBottom() {\n\t\treturn _history.length > 0 ? _history[0] : null;\n\t}\n\n\t/*\n\t\tReturns the moment at the given index within the history.\n\t*/\n\tfunction historyIndex(index) {\n\t\tif (historyIsEmpty() || index < 0 || index > _activeIndex) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn _history[index];\n\t}\n\n\t/*\n\t\tReturns the moment at the given offset from the active moment within the history.\n\t*/\n\tfunction historyPeek(offset) {\n\t\tif (historyIsEmpty()) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst lengthOffset = 1 + (offset ? Math.abs(offset) : 0);\n\n\t\tif (lengthOffset > historyLength()) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn _history[historyLength() - lengthOffset];\n\t}\n\n\t/*\n\t\tReturns whether a moment with the given title exists within the history.\n\t*/\n\tfunction historyHas(title) {\n\t\tif (historyIsEmpty() || title == null || title === '') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (let i = _activeIndex; i >= 0; --i) {\n\t\t\tif (_history[i].title === title) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tCreates a new moment and pushes it onto the history, discarding future moments if necessary.\n\t*/\n\tfunction historyCreate(title) {\n\t\tif (DEBUG) { console.log(`[State/historyCreate(title: \"${title}\")]`); }\n\n\t\t/*\n\t\t\tTODO: It might be good to have some assertions about the passage title here.\n\t\t*/\n\n\t\t/*\n\t\t\tIf we're not at the top of the stack, discard the future moments.\n\t\t*/\n\t\tif (historyLength() < historySize()) {\n\t\t\tif (DEBUG) { console.log(`\\tnon-top push; discarding ${historySize() - historyLength()} future moments`); }\n\n\t\t\t_history.splice(historyLength(), historySize() - historyLength());\n\t\t}\n\n\t\t/*\n\t\t\tPush the new moment onto the history stack.\n\t\t*/\n\t\t_history.push(momentCreate(title, _active.variables));\n\n\t\tif (_prng) {\n\t\t\thistoryTop().pull = _prng.pull;\n\t\t}\n\n\t\t/*\n\t\t\tTruncate the history, if necessary, by discarding moments from the bottom.\n\t\t*/\n\t\tif (Config.history.maxStates > 0) {\n\t\t\twhile (historySize() > Config.history.maxStates) {\n\t\t\t\t_expired.push(_history.shift().title);\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t\tActivate the new top moment.\n\t\t*/\n\t\t_activeIndex = historySize() - 1;\n\t\tmomentActivate(_activeIndex);\n\n\t\treturn historyLength();\n\t}\n\n\t/*\n\t\tActivate the moment at the given index within the history.\n\t*/\n\tfunction historyGoTo(index) {\n\t\tif (DEBUG) { console.log(`[State/historyGoTo(index: ${index})]`); }\n\n\t\tif (\n\t\t\t   index == null /* lazy equality for null */\n\t\t\t|| index < 0\n\t\t\t|| index >= historySize()\n\t\t\t|| index === _activeIndex\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\t_activeIndex = index;\n\t\tmomentActivate(_activeIndex);\n\n\t\treturn true;\n\t}\n\n\t/*\n\t\tActivate the moment at the given offset from the active moment within the history.\n\t*/\n\tfunction historyGo(offset) {\n\t\tif (DEBUG) { console.log(`[State/historyGo(offset: ${offset})]`); }\n\n\t\tif (offset == null || offset === 0) { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\treturn historyGoTo(_activeIndex + offset);\n\t}\n\n\t/*\n\t\tReturns the delta encoded form of the given history array.\n\t*/\n\tfunction historyDeltaEncode(historyArr) {\n\t\tif (!Array.isArray(historyArr)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (historyArr.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst delta = [historyArr[0]];\n\n\t\tfor (let i = 1, iend = historyArr.length; i < iend; ++i) {\n\t\t\tdelta.push(Diff.diff(historyArr[i - 1], historyArr[i]));\n\t\t}\n\n\t\treturn delta;\n\t}\n\n\t/*\n\t\tReturns a history array from the given delta encoded history array.\n\t*/\n\tfunction historyDeltaDecode(delta) {\n\t\tif (!Array.isArray(delta)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (delta.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst historyArr = [clone(delta[0])];\n\n\t\tfor (let i = 1, iend = delta.length; i < iend; ++i) {\n\t\t\thistoryArr.push(Diff.patch(historyArr[i - 1], delta[i]));\n\t\t}\n\n\t\treturn historyArr;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPRNG Functions.\n\t*******************************************************************************************************************/\n\tfunction prngInit(seed, useEntropy) {\n\t\tif (DEBUG) { console.log(`[State/prngInit(seed: ${seed}, useEntropy: ${useEntropy})]`); }\n\n\t\tif (!historyIsEmpty()) {\n\t\t\tlet scriptSection;\n\n\t\t\tif (TWINE1) { // for Twine 1\n\t\t\t\tscriptSection = 'a script-tagged passage';\n\t\t\t}\n\t\t\telse { // for Twine 2\n\t\t\t\tscriptSection = 'the Story JavaScript';\n\t\t\t}\n\n\t\t\tthrow new Error(`State.initPRNG must be called during initialization, within either ${scriptSection} or the StoryInit special passage`);\n\t\t}\n\n\t\t_prng = new PRNGWrapper(seed, useEntropy);\n\t\t_active.pull = _prng.pull;\n\t}\n\n\tfunction prngIsEnabled() {\n\t\treturn _prng !== null;\n\t}\n\n\tfunction prngPull() {\n\t\treturn _prng ? _prng.pull : NaN;\n\t}\n\n\tfunction prngSeed() {\n\t\treturn _prng ? _prng.seed : null;\n\t}\n\n\tfunction prngRandom() {\n\t\tif (DEBUG) { console.log('[State/prngRandom()]'); }\n\n\t\treturn _prng ? _prng.random() : Math.random();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTemporary Variables Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tClear the temporary variables.\n\t*/\n\tfunction tempVariablesClear() {\n\t\tif (DEBUG) { console.log('[State/tempVariablesReset()]'); }\n\n\t\t_tempVariables = {};\n\n\t\t/* legacy */\n\t\tTempVariables = _tempVariables; // eslint-disable-line no-undef\n\t\t/* /legacy */\n\t}\n\n\t/*\n\t\tReturns the current temporary variables.\n\t*/\n\tfunction tempVariables() {\n\t\treturn _tempVariables;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tVariable Chain Parsing Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the value of the given story/temporary variable.\n\t*/\n\tfunction variableGet(name) {\n\t\tconst varData = _parseVariableChain(name);\n\n\t\tif (varData === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst pNames = varData.names;\n\t\tlet retVal = varData.store;\n\n\t\tfor (let i = 0, iend = pNames.length; i < iend; ++i) {\n\t\t\tif (typeof retVal[pNames[i]] === 'undefined') {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tretVal = retVal[pNames[i]];\n\t\t}\n\n\t\treturn retVal;\n\t}\n\n\t/*\n\t\tSets the value of the given story/temporary variable.\n\t*/\n\tfunction variableSet(name, value) {\n\t\tconst varData = _parseVariableChain(name);\n\n\t\tif (varData === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst pNames  = varData.names;\n\t\tconst varName = pNames.pop();\n\t\tlet baseObj = varData.store;\n\n\t\tfor (let i = 0, iend = pNames.length; i < iend; ++i) {\n\t\t\tif (typeof baseObj[pNames[i]] === 'undefined') {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tbaseObj = baseObj[pNames[i]];\n\t\t}\n\n\t\tbaseObj[varName] = value;\n\t\treturn true;\n\t}\n\n\t/*\n\t\tReturns the property name chain of the given story/temporary variable,\n\t\twhich may be of arbitrary complexity.\n\t*/\n\tconst _parseVarRegExp = new RegExp(`^(?:${Patterns.variableSigil}(${Patterns.identifier})|\\\\.(${Patterns.identifier})|\\\\[(?:(?:\"((?:\\\\\\\\.|[^\"\\\\\\\\])+)\")|(?:'((?:\\\\\\\\.|[^'\\\\\\\\])+)')|(${Patterns.variableSigil}${Patterns.identifierFirstChar}.*)|(\\\\d+))\\\\])`);\n\tfunction _parseVariableChain(varText) {\n\t\tconst retVal = {\n\t\t\tstore : varText[0] === '$' ? State.variables : State.temporary,\n\t\t\tnames : []\n\t\t};\n\t\tlet text  = varText;\n\t\tlet match;\n\n\t\twhile ((match = _parseVarRegExp.exec(text)) !== null) {\n\t\t\t// Remove full match from text.\n\t\t\ttext = text.slice(match[0].length);\n\n\t\t\t// Base variable.\n\t\t\tif (match[1]) {\n\t\t\t\tretVal.names.push(match[1]);\n\t\t\t}\n\n\t\t\t// Dot property.\n\t\t\telse if (match[2]) {\n\t\t\t\tretVal.names.push(match[2]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (double quoted).\n\t\t\telse if (match[3]) {\n\t\t\t\tretVal.names.push(match[3]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (single quoted).\n\t\t\telse if (match[4]) {\n\t\t\t\tretVal.names.push(match[4]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (embedded variable).\n\t\t\telse if (match[5]) {\n\t\t\t\tretVal.names.push(variableGet(match[5]));\n\t\t\t}\n\n\t\t\t// Square-bracketed property (numeric index).\n\t\t\telse if (match[6]) {\n\t\t\t\tretVal.names.push(Number(match[6]));\n\t\t\t}\n\t\t}\n\n\t\treturn text === '' ? retVal : null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tStory Metadata Functions.\n\t*******************************************************************************************************************/\n\tconst _METADATA_STORE = 'metadata';\n\n\tfunction metadataClear() {\n\t\tstorage.delete(_METADATA_STORE);\n\t}\n\n\tfunction metadataDelete(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.delete key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\n\t\tif (store && store.hasOwnProperty(key)) {\n\t\t\tif (Object.keys(store).length === 1) {\n\t\t\t\tstorage.delete(_METADATA_STORE);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdelete store[key];\n\t\t\t\tstorage.set(_METADATA_STORE, store);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction metadataGet(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.get key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store && store.hasOwnProperty(key) ? store[key] : undefined;\n\t}\n\n\tfunction metadataHas(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.has key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store && store.hasOwnProperty(key);\n\t}\n\n\tfunction metadataSet(key, value) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.set key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tif (typeof value === 'undefined') {\n\t\t\tmetadataDelete(key);\n\t\t}\n\t\telse {\n\t\t\tconst store = storage.get(_METADATA_STORE) || {};\n\t\t\tstore[key] = value;\n\t\t\tstorage.set(_METADATA_STORE, store);\n\t\t}\n\t}\n\n\tfunction metadataSize() {\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store ? Object.keys(store).length : 0;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tState Functions.\n\t\t*/\n\t\treset            : { value : stateReset },\n\t\trestore          : { value : stateRestore },\n\t\tmarshalForSave   : { value : stateMarshalForSave },\n\t\tunmarshalForSave : { value : stateUnmarshalForSave },\n\t\texpired          : { get : stateExpired },\n\t\tturns            : { get : stateTurns },\n\t\tpassages         : { get : stateTitles },\n\t\thasPlayed        : { value : stateHasPlayed },\n\n\t\t/*\n\t\t\tMoment Functions.\n\t\t*/\n\t\tactive      : { get : momentActive },\n\t\tactiveIndex : { get : momentActiveIndex },\n\t\tpassage     : { get : momentActiveTitle },     // shortcut for `State.active.title`\n\t\tvariables   : { get : momentActiveVariables }, // shortcut for `State.active.variables`\n\n\t\t/*\n\t\t\tHistory Functions.\n\t\t*/\n\t\thistory     : { get : historyGet },\n\t\tlength      : { get : historyLength },\n\t\tsize        : { get : historySize },\n\t\tisEmpty     : { value : historyIsEmpty },\n\t\tcurrent     : { get : historyCurrent },\n\t\ttop         : { get : historyTop },\n\t\tbottom      : { get : historyBottom },\n\t\tindex       : { value : historyIndex },\n\t\tpeek        : { value : historyPeek },\n\t\thas         : { value : historyHas },\n\t\tcreate      : { value : historyCreate },\n\t\tgoTo        : { value : historyGoTo },\n\t\tgo          : { value : historyGo },\n\t\tdeltaEncode : { value : historyDeltaEncode },\n\t\tdeltaDecode : { value : historyDeltaDecode },\n\n\t\t/*\n\t\t\tPRNG Functions.\n\t\t*/\n\t\tprng : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tinit      : { value : prngInit },\n\t\t\t\tisEnabled : { value : prngIsEnabled },\n\t\t\t\tpull      : { get : prngPull },\n\t\t\t\tseed      : { get : prngSeed }\n\t\t\t}))\n\t\t},\n\t\trandom : { value : prngRandom },\n\n\t\t/*\n\t\t\tTemporary Variables Functions.\n\t\t*/\n\t\tclearTemporary : { value : tempVariablesClear },\n\t\ttemporary      : { get : tempVariables },\n\n\t\t/*\n\t\t\tVariable Chain Parsing Functions.\n\t\t*/\n\t\tgetVar : { value : variableGet },\n\t\tsetVar : { value : variableSet },\n\n\t\t/*\n\t\t\tStory Metadata Functions.\n\t\t*/\n\t\tmetadata : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tclear  : { value : metadataClear },\n\t\t\t\tdelete : { value : metadataDelete },\n\t\t\t\tget    : { value : metadataGet },\n\t\t\t\thas    : { value : metadataHas },\n\t\t\t\tset    : { value : metadataSet },\n\t\t\t\tsize   : { get : metadataSize }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tinitPRNG : { value : prngInit },\n\t\trestart  : { value : () => Engine.restart() },\n\t\tbackward : { value : () => Engine.backward() },\n\t\tforward  : { value : () => Engine.forward() },\n\t\tdisplay  : { value : (...args) => Engine.display(...args) },\n\t\tshow     : { value : (...args) => Engine.show(...args) },\n\t\tplay     : { value : (...args) => Engine.play(...args) }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/scripting.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Engine, Patterns, State, Story, Util */\n\nvar Scripting = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/* eslint-disable no-unused-vars */\n\n\t/*******************************************************************************************************************\n\t\tDeprecated Legacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Returns the jQuery-wrapped target element(s) after making them accessible\n\t\tclickables (ARIA compatibility).\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction addAccessibleClickHandler(targets, selector, handler, one, namespace) {\n\t\tif (arguments.length < 2) {\n\t\t\tthrow new Error('addAccessibleClickHandler insufficient number of parameters');\n\t\t}\n\n\t\tlet fn;\n\t\tlet opts;\n\n\t\tif (typeof selector === 'function') {\n\t\t\tfn = selector;\n\t\t\topts = {\n\t\t\t\tnamespace : one,\n\t\t\t\tone       : !!handler\n\t\t\t};\n\t\t}\n\t\telse {\n\t\t\tfn = handler;\n\t\t\topts = {\n\t\t\t\tnamespace,\n\t\t\t\tone : !!one,\n\t\t\t\tselector\n\t\t\t};\n\t\t}\n\n\t\tif (typeof fn !== 'function') {\n\t\t\tthrow new TypeError('addAccessibleClickHandler handler parameter must be a function');\n\t\t}\n\n\t\treturn jQuery(targets).ariaClick(opts, fn);\n\t}\n\n\t/*\n\t\t[DEPRECATED] Returns a new DOM element, optionally appending it to the passed DOM element, if any.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction insertElement(place, type, id, classNames, text, title) { // eslint-disable-line max-params\n\t\tconst $el = jQuery(document.createElement(type));\n\n\t\t// Add attributes/properties.\n\t\tif (id) {\n\t\t\t$el.attr('id', id);\n\t\t}\n\n\t\tif (classNames) {\n\t\t\t$el.addClass(classNames);\n\t\t}\n\n\t\tif (title) {\n\t\t\t$el.attr('title', title);\n\t\t}\n\n\t\t// Add text content.\n\t\tif (text) {\n\t\t\t$el.text(text);\n\t\t}\n\n\t\t// Append it to the given node.\n\t\tif (place) {\n\t\t\t$el.appendTo(place);\n\t\t}\n\n\t\treturn $el[0];\n\t}\n\n\t/*\n\t\t[DEPRECATED] Creates a new text node and appends it to the passed DOM element.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction insertText(place, text) {\n\t\tjQuery(place).append(document.createTextNode(text));\n\t}\n\n\t/*\n\t\t[DEPRECATED] Removes all children from the passed DOM node.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction removeChildren(node) {\n\t\tjQuery(node).empty();\n\t}\n\n\t/*\n\t\t[DEPRECATED] Removes the passed DOM node.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction removeElement(node) {\n\t\tjQuery(node).remove();\n\t}\n\n\t/*\n\t\t[DEPRECATED] Fades a DOM element in or out.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction fade(el, options) {\n\t\t/* eslint-disable no-param-reassign */\n\t\tconst direction = options.fade === 'in' ? 1 : -1;\n\t\tlet current;\n\t\tlet proxy      = el.cloneNode(true);\n\t\tlet intervalId; // eslint-disable-line prefer-const\n\n\t\tfunction tick() {\n\t\t\tcurrent += 0.05 * direction;\n\t\t\tsetOpacity(proxy, Math.easeInOut(current));\n\n\t\t\tif (direction === 1 && current >= 1 || direction === -1 && current <= 0) {\n\t\t\t\tel.style.visibility = options.fade === 'in' ? 'visible' : 'hidden';\n\t\t\t\tproxy.parentNode.replaceChild(el, proxy);\n\t\t\t\tproxy = null;\n\t\t\t\twindow.clearInterval(intervalId);\n\n\t\t\t\tif (options.onComplete) {\n\t\t\t\t\toptions.onComplete();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction setOpacity(el, opacity) {\n\t\t\t// Old IE.\n\t\t\tel.style.zoom = 1;\n\t\t\tel.style.filter = `alpha(opacity=${Math.floor(opacity * 100)})`;\n\n\t\t\t// CSS.\n\t\t\tel.style.opacity = opacity;\n\t\t}\n\n\t\tel.parentNode.replaceChild(proxy, el);\n\n\t\tif (options.fade === 'in') {\n\t\t\tcurrent = 0;\n\t\t\tproxy.style.visibility = 'visible';\n\t\t}\n\t\telse {\n\t\t\tcurrent = 1;\n\t\t}\n\n\t\tsetOpacity(proxy, current);\n\t\tintervalId = window.setInterval(tick, 25);\n\t\t/* eslint-enable no-param-reassign */\n\t}\n\n\t/*\n\t\t[DEPRECATED] Scrolls the browser window to ensure that a DOM element is in view.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction scrollWindowTo(el, incrementBy) {\n\t\t/* eslint-disable no-param-reassign */\n\t\tlet increment = incrementBy != null ? Number(incrementBy) : 0.1; // lazy equality for null\n\n\t\tif (Number.isNaN(increment) || !Number.isFinite(increment) || increment < 0) {\n\t\t\tincrement = 0.1;\n\t\t}\n\t\telse if (increment > 1) {\n\t\t\tincrement = 1;\n\t\t}\n\n\t\tconst start     = window.scrollY ? window.scrollY : document.body.scrollTop;\n\t\tconst end       = ensureVisible(el);\n\t\tconst distance  = Math.abs(start - end);\n\t\tconst direction = start > end ? -1 : 1;\n\t\tlet progress   = 0;\n\t\tlet intervalId; // eslint-disable-line prefer-const\n\n\t\tfunction tick() {\n\t\t\tprogress += increment;\n\t\t\twindow.scroll(0, start + direction * (distance * Math.easeInOut(progress)));\n\n\t\t\tif (progress >= 1) {\n\t\t\t\twindow.clearInterval(intervalId);\n\t\t\t}\n\t\t}\n\n\t\tfunction findPosY(el) { // eslint-disable-line no-shadow\n\t\t\tlet curtop = 0;\n\n\t\t\twhile (el.offsetParent) {\n\t\t\t\tcurtop += el.offsetTop;\n\t\t\t\tel = el.offsetParent;\n\t\t\t}\n\n\t\t\treturn curtop;\n\t\t}\n\n\t\tfunction ensureVisible(el) { // eslint-disable-line no-shadow\n\t\t\tconst posTop    = findPosY(el);\n\t\t\tconst posBottom = posTop + el.offsetHeight;\n\t\t\tconst winTop    = window.scrollY ? window.scrollY : document.body.scrollTop;\n\t\t\tconst winHeight = window.innerHeight ? window.innerHeight : document.body.clientHeight;\n\t\t\tconst winBottom = winTop + winHeight;\n\n\t\t\treturn posTop >= winTop && posBottom > winBottom && el.offsetHeight < winHeight\n\t\t\t\t? posTop - (winHeight - el.offsetHeight) + 20\n\t\t\t\t: posTop;\n\t\t}\n\n\t\tintervalId = window.setInterval(tick, 25);\n\t\t/* eslint-enable no-param-reassign */\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUser Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a random value from its given arguments.\n\t*/\n\tfunction either(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn Array.prototype.concat.apply([], arguments).random();\n\t}\n\n\t/*\n\t\tRemoves the given key, and its value, from the story metadata store.\n\t*/\n\tfunction forget(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`forget key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\tState.metadata.delete(key);\n\t}\n\n\t/*\n\t\tReturns whether a passage with the given title exists within the story\n\t\thistory.  If multiple passage titles are given, returns the logical-AND\n\t\taggregate of the set.\n\t*/\n\tfunction hasVisited(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('hasVisited called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst played  = State.passages;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend; ++i) {\n\t\t\tif (!played.includes(needles[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/*\n\t\tReturns the number of turns that have passed since the last instance of the given passage\n\t\toccurred within the story history or `-1` if it does not exist.  If multiple passages are\n\t\tgiven, returns the lowest count (which can be `-1`).\n\t*/\n\tfunction lastVisited(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('lastVisited called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn -1;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst played  = State.passages;\n\t\tconst uBound  = played.length - 1;\n\t\tlet turns = State.turns;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend && turns > -1; ++i) {\n\t\t\tconst lastIndex = played.lastIndexOf(needles[i]);\n\t\t\tturns = Math.min(turns, lastIndex === -1 ? -1 : uBound - lastIndex);\n\t\t}\n\n\t\treturn turns;\n\t}\n\n\t/*\n\t\tSets the given key/value pair within the story metadata store.\n\t*/\n\tfunction memorize(key, value) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`memorize key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\tState.metadata.set(key, value);\n\t}\n\n\t/*\n\t\tReturns the title of the current passage.\n\t*/\n\tfunction passage() {\n\t\treturn State.passage;\n\t}\n\n\t/*\n\t\tReturns the title of a previous passage, either the most recent one whose title does not\n\t\tmatch that of the active passage or the one at the optional offset, or an empty string,\n\t\tif there is no such passage.\n\t*/\n\tfunction previous(/* legacy: offset */) {\n\t\tconst passages = State.passages;\n\n\t\t/* legacy: behavior with an offset */\n\t\tif (arguments.length > 0) {\n\t\t\tconst offset = Number(arguments[0]);\n\n\t\t\tif (!Number.isSafeInteger(offset) || offset < 1) {\n\t\t\t\tthrow new RangeError('previous offset parameter must be a positive integer greater than zero');\n\t\t\t}\n\n\t\t\treturn passages.length > offset ? passages[passages.length - 1 - offset] : '';\n\t\t}\n\t\t/* /legacy */\n\n\t\tfor (let i = passages.length - 2; i >= 0; --i) {\n\t\t\tif (passages[i] !== State.passage) {\n\t\t\t\treturn passages[i];\n\t\t\t}\n\t\t}\n\n\t\treturn '';\n\t}\n\n\t/*\n\t\tReturns a pseudo-random whole number (integer) within the range of the given bounds.\n\t*/\n\tfunction random(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('random called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = Math.trunc(arguments[0]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Math.trunc(arguments[0]);\n\t\t\tmax = Math.trunc(arguments[1]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (!Number.isInteger(min)) {\n\t\t\tthrow new Error('random min parameter must be an integer');\n\t\t}\n\t\tif (!Number.isInteger(max)) {\n\t\t\tthrow new Error('random max parameter must be an integer');\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn Math.floor(State.random() * (max - min + 1)) + min;\n\t}\n\n\t/*\n\t\tReturns a pseudo-random real number (floating-point) within the range of the given bounds.\n\n\t\tNOTE: Unlike with its sibling function `random()`, the `max` parameter\n\t\tis exclusive, not inclusive—i.e. the range goes to, but does not include,\n\t\tthe given value.\n\t*/\n\tfunction randomFloat(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('randomFloat called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0.0;\n\t\t\tmax = Number(arguments[0]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Number(arguments[0]);\n\t\t\tmax = Number(arguments[1]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (Number.isNaN(min) || !Number.isFinite(min)) {\n\t\t\tthrow new Error('randomFloat min parameter must be a number');\n\t\t}\n\t\tif (Number.isNaN(max) || !Number.isFinite(max)) {\n\t\t\tthrow new Error('randomFloat max parameter must be a number');\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn State.random() * (max - min) + min;\n\t}\n\n\t/*\n\t\tReturns the value of the given key from the story metadata store\n\t\tor the given default value if the key does not exist.\n\t*/\n\tfunction recall(key, defaultValue) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`recall key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\treturn State.metadata.has(key) ? State.metadata.get(key) : defaultValue;\n\t}\n\n\t/*\n\t\tReturns a new array consisting of all of the tags of the given passages.\n\t*/\n\tfunction tags(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\treturn Story.get(State.passage).tags.slice(0);\n\t\t}\n\n\t\tconst passages = Array.prototype.concat.apply([], arguments);\n\t\tlet tags = [];\n\n\t\tfor (let i = 0, iend = passages.length; i < iend; ++i) {\n\t\t\ttags = tags.concat(Story.get(passages[i]).tags);\n\t\t}\n\n\t\treturn tags;\n\t}\n\n\t/*\n\t\tReturns a reference to the current temporary _variables store.\n\t*/\n\tfunction temporary() {\n\t\treturn State.temporary;\n\t}\n\n\t/*\n\t\tReturns the number of milliseconds which have passed since the current passage was rendered.\n\t*/\n\tfunction time() {\n\t\treturn Engine.lastPlay === null ? 0 : Util.now() - Engine.lastPlay;\n\t}\n\n\t/*\n\t\tReturns the number of passages that the player has visited.\n\n\t\tNOTE: Passages which were visited but have been undone—e.g. via the backward\n\t\tbutton or the `<<back>>` macro—are no longer part of the in-play story\n\t\thistory and thus are not tallied.  Passages which were visited but have\n\t\texpired from the story history, on the other hand, are tallied.\n\t*/\n\tfunction turns() {\n\t\treturn State.turns;\n\t}\n\n\t/*\n\t\tReturns a reference to the current story $variables store.\n\t*/\n\tfunction variables() {\n\t\treturn State.variables;\n\t}\n\n\t/*\n\t\tReturns the number of times that the passage with the given title exists within the story\n\t\thistory.  If multiple passage titles are given, returns the lowest count.\n\t*/\n\tfunction visited(/* variadic */) {\n\t\tif (State.isEmpty()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments.length === 0 ? [State.passage] : arguments);\n\t\tconst played  = State.passages;\n\t\tlet count = State.turns;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend && count > 0; ++i) {\n\t\t\tcount = Math.min(count, played.count(needles[i]));\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/*\n\t\tReturns the number of passages within the story history which are tagged with all of the given tags.\n\t*/\n\tfunction visitedTags(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('visitedTags called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst nLength = needles.length;\n\t\tconst played  = State.passages;\n\t\tconst seen    = new Map();\n\t\tlet count = 0;\n\n\t\tfor (let i = 0, iend = played.length; i < iend; ++i) {\n\t\t\tconst title = played[i];\n\n\t\t\tif (seen.has(title)) {\n\t\t\t\tif (seen.get(title)) {\n\t\t\t\t\t++count;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst tags = Story.get(title).tags;\n\n\t\t\t\tif (tags.length > 0) {\n\t\t\t\t\tlet found = 0;\n\n\t\t\t\t\tfor (let j = 0; j < nLength; ++j) {\n\t\t\t\t\t\tif (tags.includes(needles[j])) {\n\t\t\t\t\t\t\t++found;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (found === nLength) {\n\t\t\t\t\t\t++count;\n\t\t\t\t\t\tseen.set(title, true);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tseen.set(title, false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/* eslint-enable no-unused-vars */\n\n\n\t/*******************************************************************************************************************\n\t\tImport Functions.\n\t*******************************************************************************************************************/\n\tvar { // eslint-disable-line no-var\n\t\t/* eslint-disable no-unused-vars */\n\t\timportScripts,\n\t\timportStyles\n\t\t/* eslint-enable no-unused-vars */\n\t} = (() => {\n\t\t// Slugify the given URL.\n\t\tfunction slugifyUrl(url) {\n\t\t\treturn Util.parseUrl(url).path\n\t\t\t\t.replace(/^[^\\w]+|[^\\w]+$/g, '')\n\t\t\t\t.replace(/[^\\w]+/g, '-')\n\t\t\t\t.toLocaleLowerCase();\n\t\t}\n\n\t\t// Add a <script> element which will load the script from the given URL.\n\t\tfunction addScript(url) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t/*\n\t\t\t\t\tWARNING: The ordering of the code within this function is important,\n\t\t\t\t\tas some browsers don't play well with different arrangements, so\n\t\t\t\t\tbe careful when mucking around with it.\n\n\t\t\t\t\tThe best supported ordering seems be: events → DOM append → attributes.\n\t\t\t\t*/\n\t\t\t\tjQuery(document.createElement('script'))\n\t\t\t\t\t.one('load abort error', ev => {\n\t\t\t\t\t\tjQuery(ev.target).off();\n\n\t\t\t\t\t\tif (ev.type === 'load') {\n\t\t\t\t\t\t\tresolve(ev.target);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treject(new Error(`importScripts failed to load the script \"${url}\".`));\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo(document.head)\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid   : `script-imported-${slugifyUrl(url)}`,\n\t\t\t\t\t\ttype : 'text/javascript',\n\t\t\t\t\t\tsrc  : url\n\t\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\t// Add a <link> element which will load the stylesheet from the given URL.\n\t\tfunction addStyle(url) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t/*\n\t\t\t\t\tWARNING: The ordering of the code within this function is important,\n\t\t\t\t\tas some browsers don't play well with different arrangements, so\n\t\t\t\t\tbe careful when mucking around with it.\n\n\t\t\t\t\tThe best supported ordering seems be: events → DOM append → attributes.\n\t\t\t\t*/\n\t\t\t\tjQuery(document.createElement('link'))\n\t\t\t\t\t.one('load abort error', ev => {\n\t\t\t\t\t\tjQuery(ev.target).off();\n\n\t\t\t\t\t\tif (ev.type === 'load') {\n\t\t\t\t\t\t\tresolve(ev.target);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treject(new Error(`importStyles failed to load the stylesheet \"${url}\".`));\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo(document.head)\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid   : `style-imported-${slugifyUrl(url)}`,\n\t\t\t\t\t\trel  : 'stylesheet',\n\t\t\t\t\t\thref : url\n\t\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\t// Turn a list of callbacks into a sequential chain of `Promise` objects.\n\t\tfunction sequence(callbacks) {\n\t\t\treturn callbacks.reduce((seq, fn) => seq = seq.then(fn), Promise.resolve()); // eslint-disable-line no-param-reassign\n\t\t}\n\n\t\t/*\n\t\t\tImport scripts from a URL.\n\t\t*/\n\t\tfunction importScripts(...urls) {\n\t\t\treturn Promise.all(urls.map(oneOrSeries => {\n\t\t\t\t// Array of URLs to be imported in sequence.\n\t\t\t\tif (Array.isArray(oneOrSeries)) {\n\t\t\t\t\treturn sequence(oneOrSeries.map(url => () => addScript(url)));\n\t\t\t\t}\n\n\t\t\t\t// Single URL to be imported.\n\t\t\t\treturn addScript(oneOrSeries);\n\t\t\t}));\n\t\t}\n\n\t\t/*\n\t\t\tImport stylesheets from a URL.\n\t\t*/\n\t\tfunction importStyles(...urls) {\n\t\t\treturn Promise.all(urls.map(oneOrSeries => {\n\t\t\t\t// Array of URLs to be imported in sequence.\n\t\t\t\tif (Array.isArray(oneOrSeries)) {\n\t\t\t\t\treturn sequence(oneOrSeries.map(url => () => addStyle(url)));\n\t\t\t\t}\n\n\t\t\t\t// Single URL to be imported.\n\t\t\t\treturn addStyle(oneOrSeries);\n\t\t\t}));\n\t\t}\n\n\t\t// Exports.\n\t\treturn {\n\t\t\timportScripts,\n\t\t\timportStyles\n\t\t};\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tParsing Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the given string after converting all TwineScript syntactical sugars to\n\t\ttheir native JavaScript counterparts.\n\t*/\n\tconst parse = (() => {\n\t\tconst parseMap = Object.freeze({\n\t\t\t/* eslint-disable quote-props */\n\t\t\t// Story $variable sigil-prefix.\n\t\t\t'$'     : 'State.variables.',\n\t\t\t// Temporary _variable sigil-prefix.\n\t\t\t'_'     : 'State.temporary.',\n\t\t\t// Assignment operators.\n\t\t\t'to'    : '=',\n\t\t\t// Equality operators.\n\t\t\t'eq'    : '==',\n\t\t\t'neq'   : '!=',\n\t\t\t'is'    : '===',\n\t\t\t'isnot' : '!==',\n\t\t\t// Relational operators.\n\t\t\t'gt'    : '>',\n\t\t\t'gte'   : '>=',\n\t\t\t'lt'    : '<',\n\t\t\t'lte'   : '<=',\n\t\t\t// Logical operators.\n\t\t\t'and'   : '&&',\n\t\t\t'or'    : '||',\n\t\t\t// Unary operators.\n\t\t\t'not'   : '!',\n\t\t\t'def'   : '\"undefined\" !== typeof',\n\t\t\t'ndef'  : '\"undefined\" === typeof'\n\t\t\t/* eslint-enable quote-props */\n\t\t});\n\t\tconst parseRe = new RegExp([\n\t\t\t'(\"\"|\\'\\')',                                          // 1=Empty quotes\n\t\t\t'(\"(?:\\\\\\\\.|[^\"\\\\\\\\])+\")',                            // 2=Double quoted, non-empty\n\t\t\t\"('(?:\\\\\\\\.|[^'\\\\\\\\])+')\",                            // 3=Single quoted, non-empty\n\t\t\t'([=+\\\\-*\\\\/%<>&\\\\|\\\\^~!?:,;\\\\(\\\\)\\\\[\\\\]{}]+)',       // 4=Operator delimiters\n\t\t\t'([^\"\\'=+\\\\-*\\\\/%<>&\\\\|\\\\^~!?:,;\\\\(\\\\)\\\\[\\\\]{}\\\\s]+)' // 5=Barewords\n\t\t].join('|'), 'g');\n\t\tconst varTest = new RegExp(`^${Patterns.variable}`);\n\n\t\tfunction parse(rawCodeString) {\n\t\t\tif (parseRe.lastIndex !== 0) {\n\t\t\t\tthrow new RangeError('Scripting.parse last index is non-zero at start');\n\t\t\t}\n\n\t\t\tlet code  = rawCodeString;\n\t\t\tlet match;\n\n\t\t\twhile ((match = parseRe.exec(code)) !== null) {\n\t\t\t\t// no-op: Empty quotes | Double quoted | Single quoted | Operator delimiters\n\n\t\t\t\t/*\n\t\t\t\t\tBarewords.\n\t\t\t\t*/\n\t\t\t\tif (match[5]) {\n\t\t\t\t\tlet token = match[5];\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is simply a dollar-sign or underscore, then it's either\n\t\t\t\t\t\tjust the raw character or, probably, a function alias, so skip it.\n\t\t\t\t\t*/\n\t\t\t\t\tif (token === '$' || token === '_') {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is a story $variable or temporary _variable, reset it\n\t\t\t\t\t\tto just its sigil—for later mapping.\n\t\t\t\t\t*/\n\t\t\t\t\telse if (varTest.test(token)) {\n\t\t\t\t\t\ttoken = token[0];\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is `is`, check to see if it's followed by `not`, if so,\n\t\t\t\t\t\tconvert them into the `isnot` operator.\n\n\t\t\t\t\t\tNOTE: This is a safety feature, since `$a is not $b` probably sounds\n\t\t\t\t\t\treasonable to most users.\n\t\t\t\t\t*/\n\t\t\t\t\telse if (token === 'is') {\n\t\t\t\t\t\tconst start = parseRe.lastIndex;\n\t\t\t\t\t\tconst part  = code.slice(start);\n\n\t\t\t\t\t\tif (/^\\s+not\\b/.test(part)) {\n\t\t\t\t\t\t\tcode = code.splice(start, part.search(/\\S/));\n\t\t\t\t\t\t\ttoken = 'isnot';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the finalized token has a mapping, replace it within the code string\n\t\t\t\t\t\twith its counterpart.\n\n\t\t\t\t\t\tNOTE: We must use `parseMap.hasOwnProperty(token)` here, rather than\n\t\t\t\t\t\tsimply using something like `parseMap[token]`, otherwise tokens which\n\t\t\t\t\t\tmatch properties from the prototype chain will cause shenanigans.\n\t\t\t\t\t*/\n\t\t\t\t\tif (parseMap.hasOwnProperty(token)) {\n\t\t\t\t\t\tcode = code.splice(\n\t\t\t\t\t\t\tmatch.index,    // starting index\n\t\t\t\t\t\t\ttoken.length,   // replace how many\n\t\t\t\t\t\t\tparseMap[token] // replacement string\n\t\t\t\t\t\t);\n\t\t\t\t\t\tparseRe.lastIndex += parseMap[token].length - token.length;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn code;\n\t\t}\n\n\t\treturn parse;\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tEval Functions.\n\t*******************************************************************************************************************/\n\t/* eslint-disable no-eval, no-extra-parens, no-unused-vars */\n\t/*\n\t\tEvaluates the given JavaScript code and returns the result, throwing if there were errors.\n\t*/\n\tfunction evalJavaScript(code, output) {\n\t\treturn (function (code, output) {\n\t\t\treturn eval(code);\n\t\t}).call(output ? { output } : null, String(code), output);\n\t}\n\n\t/*\n\t\tEvaluates the given TwineScript code and returns the result, throwing if there were errors.\n\t*/\n\tfunction evalTwineScript(code, output) {\n\t\treturn (function (code, output) {\n\t\t\treturn eval(code);\n\t\t}).call(output ? { output } : null, parse(String(code)), output);\n\t}\n\t/* eslint-enable no-eval, no-extra-parens, no-unused-vars */\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tparse           : { value : parse },\n\t\tevalJavaScript  : { value : evalJavaScript },\n\t\tevalTwineScript : { value : evalTwineScript }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/lexer.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar { // eslint-disable-line no-var\n\t/* eslint-disable no-unused-vars */\n\tEOF,\n\tLexer\n\t/* eslint-enable no-unused-vars */\n} = (() => {\n\t'use strict';\n\n\t// End of file (string, actually).\n\tconst EOF = -1;\n\n\n\t/*******************************************************************************************************************\n\t\tLexer Class.\n\t*******************************************************************************************************************/\n\tclass Lexer {\n\t\tconstructor(source, initialState) {\n\t\t\tif (arguments.length < 2) {\n\t\t\t\tthrow new Error('Lexer constructor called with too few parameters (source:string , initialState:function)');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tthis.source  → the string to be scanned\n\t\t\t\tthis.initial → initial state\n\t\t\t\tthis.state   → current state\n\t\t\t\tthis.start   → start position of an item\n\t\t\t\tthis.pos     → current position in the source string\n\t\t\t\tthis.depth   → current brace/bracket/parenthesis nesting depth\n\t\t\t\tthis.items   → scanned item queue\n\t\t\t\tthis.data    → lexing data\n\t\t\t*/\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : source\n\t\t\t\t},\n\n\t\t\t\tinitial : {\n\t\t\t\t\tvalue : initialState\n\t\t\t\t},\n\n\t\t\t\tstate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : initialState\n\t\t\t\t},\n\n\t\t\t\tstart : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\tpos : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\tdepth : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\titems : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : []\n\t\t\t\t},\n\n\t\t\t\tdata : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : {}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treset() {\n\t\t\tthis.state  = this.initial;\n\t\t\tthis.start  = 0;\n\t\t\tthis.pos    = 0;\n\t\t\tthis.depth  = 0;\n\t\t\tthis.items  = [];\n\t\t\tthis.data   = {};\n\t\t}\n\n\t\trun() {\n\t\t\t// scan the source string until no states remain\n\t\t\twhile (this.state !== null) {\n\t\t\t\tthis.state = this.state(this);\n\t\t\t}\n\n\t\t\t// return the array of items\n\t\t\treturn this.items;\n\t\t}\n\n\t\tnextItem() {\n\t\t\t// scan the source string until we have an item or no states remain\n\t\t\twhile (this.items.length === 0 && this.state !== null) {\n\t\t\t\tthis.state = this.state(this);\n\t\t\t}\n\n\t\t\t// return the current item\n\t\t\treturn this.items.shift();\n\t\t}\n\n\t\tnext() {\n\t\t\tif (this.pos >= this.source.length) {\n\t\t\t\treturn EOF;\n\t\t\t}\n\n\t\t\treturn this.source[this.pos++];\n\t\t}\n\n\t\tpeek() {\n\t\t\tif (this.pos >= this.source.length) {\n\t\t\t\treturn EOF;\n\t\t\t}\n\n\t\t\treturn this.source[this.pos];\n\t\t}\n\n\t\tbackup(num) {\n\t\t\t// if (num) {\n\t\t\t// \tthis.pos -= num;\n\t\t\t// }\n\t\t\t// else {\n\t\t\t// \t--this.pos;\n\t\t\t// }\n\t\t\tthis.pos -= num || 1;\n\t\t}\n\n\t\tforward(num) {\n\t\t\t// if (num) {\n\t\t\t// \tthis.pos += num;\n\t\t\t// }\n\t\t\t// else {\n\t\t\t// \t++this.pos;\n\t\t\t// }\n\t\t\tthis.pos += num || 1;\n\t\t}\n\n\t\tignore() {\n\t\t\tthis.start = this.pos;\n\t\t}\n\n\t\taccept(valid) {\n\t\t\tconst ch = this.next();\n\n\t\t\tif (ch === EOF) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (valid.includes(ch)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t\treturn false;\n\t\t}\n\n\t\tacceptRe(validRe) {\n\t\t\tconst ch = this.next();\n\n\t\t\tif (ch === EOF) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (validRe.test(ch)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t\treturn false;\n\t\t}\n\n\t\tacceptRun(valid) {\n\t\t\tfor (;;) {\n\t\t\t\tconst ch = this.next();\n\n\t\t\t\tif (ch === EOF) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!valid.includes(ch)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t}\n\n\t\tacceptRunRe(validRe) {\n\t\t\tfor (;;) {\n\t\t\t\tconst ch = this.next();\n\n\t\t\t\tif (ch === EOF) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!validRe.test(ch)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t}\n\n\t\temit(type) {\n\t\t\tthis.items.push({\n\t\t\t\ttype,\n\t\t\t\ttext  : this.source.slice(this.start, this.pos),\n\t\t\t\tstart : this.start,\n\t\t\t\tpos   : this.pos\n\t\t\t});\n\t\t\tthis.start = this.pos;\n\t\t}\n\n\t\terror(type, message) {\n\t\t\tif (arguments.length < 2) {\n\t\t\t\tthrow new Error('Lexer.prototype.error called with too few parameters (type:number , message:string)');\n\t\t\t}\n\n\t\t\tthis.items.push({\n\t\t\t\ttype,\n\t\t\t\tmessage,\n\t\t\t\ttext  : this.source.slice(this.start, this.pos),\n\t\t\t\tstart : this.start,\n\t\t\t\tpos   : this.pos\n\t\t\t});\n\t\t\treturn null;\n\t\t}\n\n\t\tstatic enumFromNames(names) {\n\t\t\tconst obj = names.reduce((obj, name, i) => {\n\t\t\t\tobj[name] = i; // eslint-disable-line no-param-reassign\n\t\t\t\treturn obj;\n\t\t\t}, {});\n\t\t\treturn Object.freeze(Object.assign(Object.create(null), obj));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn {\n\t\tEOF,\n\t\tLexer\n\t};\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/wikifier.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, EOF, Engine, Lexer, Patterns, Scripting, State, Story, TempState, Util, convertBreaks,\n\t       errorPrologRegExp\n*/\n\n/*\n\tTODO: The Wikifier, and associated code, could stand to receive a serious refactoring.\n*/\n/* eslint-disable max-len */\nvar Wikifier = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Wikifier call depth.\n\tlet _callDepth = 0;\n\n\n\t/*******************************************************************************************************************\n\t\tWikifier Class.\n\t*******************************************************************************************************************/\n\tclass Wikifier {\n\t\tconstructor(destination, source, options) {\n\t\t\tif (Wikifier.Parser.Profile.isEmpty()) {\n\t\t\t\tWikifier.Parser.Profile.compile();\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// General Wikifier properties.\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : String(source)\n\t\t\t\t},\n\n\t\t\t\toptions : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : Object.assign({\n\t\t\t\t\t\tprofile : 'all'\n\t\t\t\t\t}, options)\n\t\t\t\t},\n\n\t\t\t\tnextMatch : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\toutput : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t// Macro parser ('macro') related properties.\n\t\t\t\t_rawArgs : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : ''\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// No destination specified.  Create a fragment to act as the output buffer.\n\t\t\tif (destination == null) { // lazy equality for null\n\t\t\t\tthis.output = document.createDocumentFragment();\n\t\t\t}\n\n\t\t\t// jQuery-wrapped destination.  Grab the first element.\n\t\t\telse if (destination.jquery) { // cannot use `hasOwnProperty()` here as `jquery` is from jQuery's prototype\n\t\t\t\tthis.output = destination[0];\n\t\t\t}\n\n\t\t\t// Normal destination.\n\t\t\telse {\n\t\t\t\tthis.output = destination;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tWikify the source into the output buffer element, possibly converting line\n\t\t\t\tbreaks into paragraphs.\n\n\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\tto ensure that the call depth is properly restored in the event that an\n\t\t\t\tuncaught exception is thrown during the call to `subWikify()`.\n\t\t\t*/\n\t\t\ttry {\n\t\t\t\t++_callDepth;\n\n\t\t\t\tthis.subWikify(this.output);\n\n\t\t\t\t// Limit line break conversion to non-recursive calls.\n\t\t\t\tif (_callDepth === 1 && Config.cleanupWikifierOutput) {\n\t\t\t\t\tconvertBreaks(this.output);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\t--_callDepth;\n\t\t\t}\n\t\t}\n\n\t\tsubWikify(output, terminator, options) {\n\t\t\t// Cache and temporarily replace the current output buffer.\n\t\t\tconst oldOutput = this.output;\n\t\t\tthis.output = output;\n\n\t\t\tlet newOptions;\n\t\t\tlet oldOptions;\n\n\t\t\t// Parser option overrides.\n\t\t\tif (Wikifier.Option.length > 0) {\n\t\t\t\tnewOptions = Object.assign(newOptions || {}, Wikifier.Option.options);\n\t\t\t}\n\t\t\t// Local parameter option overrides.\n\t\t\tif (options !== null && typeof options === 'object') {\n\t\t\t\tnewOptions = Object.assign(newOptions || {}, options);\n\t\t\t}\n\t\t\t// If new options exist, cache and temporarily replace the current options.\n\t\t\tif (newOptions) {\n\t\t\t\toldOptions = this.options;\n\t\t\t\tthis.options = Object.assign({}, this.options, newOptions);\n\t\t\t}\n\n\t\t\tconst parsersProfile   = Wikifier.Parser.Profile.get(this.options.profile);\n\t\t\tconst terminatorRegExp = terminator\n\t\t\t\t? new RegExp(`(?:${terminator})`, this.options.ignoreTerminatorCase ? 'gim' : 'gm')\n\t\t\t\t: null;\n\t\t\tlet terminatorMatch;\n\t\t\tlet parserMatch;\n\n\t\t\tdo {\n\t\t\t\t// Prepare the RegExp match positions.\n\t\t\t\tparsersProfile.parserRegExp.lastIndex = this.nextMatch;\n\n\t\t\t\tif (terminatorRegExp) {\n\t\t\t\t\tterminatorRegExp.lastIndex = this.nextMatch;\n\t\t\t\t}\n\n\t\t\t\t// Get the first matches.\n\t\t\t\tparserMatch     = parsersProfile.parserRegExp.exec(this.source);\n\t\t\t\tterminatorMatch = terminatorRegExp ? terminatorRegExp.exec(this.source) : null;\n\n\t\t\t\t// Try for a terminator match, unless there's a closer parser match.\n\t\t\t\tif (terminatorMatch && (!parserMatch || terminatorMatch.index <= parserMatch.index)) {\n\t\t\t\t\t// Output any text before the match.\n\t\t\t\t\tif (terminatorMatch.index > this.nextMatch) {\n\t\t\t\t\t\tthis.outputText(this.output, this.nextMatch, terminatorMatch.index);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set the match parameters.\n\t\t\t\t\tthis.matchStart  = terminatorMatch.index;\n\t\t\t\t\tthis.matchLength = terminatorMatch[0].length;\n\t\t\t\t\tthis.matchText   = terminatorMatch[0];\n\t\t\t\t\tthis.nextMatch   = terminatorRegExp.lastIndex;\n\n\t\t\t\t\t// Restore the original output buffer and options.\n\t\t\t\t\tthis.output = oldOutput;\n\n\t\t\t\t\tif (oldOptions) {\n\t\t\t\t\t\tthis.options = oldOptions;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Exit.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Try for a parser match.\n\t\t\t\telse if (parserMatch) {\n\t\t\t\t\t// Output any text before the match.\n\t\t\t\t\tif (parserMatch.index > this.nextMatch) {\n\t\t\t\t\t\tthis.outputText(this.output, this.nextMatch, parserMatch.index);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set the match parameters.\n\t\t\t\t\tthis.matchStart  = parserMatch.index;\n\t\t\t\t\tthis.matchLength = parserMatch[0].length;\n\t\t\t\t\tthis.matchText   = parserMatch[0];\n\t\t\t\t\tthis.nextMatch   = parsersProfile.parserRegExp.lastIndex;\n\n\t\t\t\t\t// Figure out which parser matched.\n\t\t\t\t\tlet matchingParser;\n\n\t\t\t\t\tfor (let i = 1, iend = parserMatch.length; i < iend; ++i) {\n\t\t\t\t\t\tif (parserMatch[i]) {\n\t\t\t\t\t\t\tmatchingParser = i - 1;\n\t\t\t\t\t\t\tbreak; // stop once we've found the matching parser\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Call the parser.\n\t\t\t\t\tparsersProfile.parsers[matchingParser].handler(this);\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} while (terminatorMatch || parserMatch);\n\n\t\t\t// Output any text after the last match.\n\t\t\tif (TempState.break == null) { // lazy equality for null\n\t\t\t\tif (this.nextMatch < this.source.length) {\n\t\t\t\t\tthis.outputText(this.output, this.nextMatch, this.source.length);\n\t\t\t\t\tthis.nextMatch = this.source.length;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// In case of <<break>>/<<continue>>, remove the last <br>.\n\t\t\telse if (\n\t\t\t\t   this.output.lastChild\n\t\t\t\t&& this.output.lastChild.nodeType === Node.ELEMENT_NODE\n\t\t\t\t&& this.output.lastChild.nodeName.toUpperCase() === 'BR'\n\t\t\t) {\n\t\t\t\tjQuery(this.output.lastChild).remove();\n\t\t\t}\n\n\t\t\t// Restore the original output buffer and options.\n\t\t\tthis.output = oldOutput;\n\n\t\t\tif (oldOptions) {\n\t\t\t\tthis.options = oldOptions;\n\t\t\t}\n\t\t}\n\n\t\toutputText(destination, startPos, endPos) {\n\t\t\tdestination.appendChild(document.createTextNode(this.source.substring(startPos, endPos)));\n\t\t}\n\n\t\t/*\n\t\t\t[DEPRECATED] Meant to be called by legacy macros, this returns the raw, unprocessed\n\t\t\ttext given to the currently executing macro.\n\t\t*/\n\t\trawArgs() {\n\t\t\treturn this._rawArgs;\n\t\t}\n\n\t\t/*\n\t\t\t[DEPRECATED] Meant to be called by legacy macros, this returns the text given to\n\t\t\tthe currently executing macro after doing TwineScript-to-JavaScript transformations.\n\t\t*/\n\t\tfullArgs() {\n\t\t\treturn Scripting.parse(this._rawArgs);\n\t\t}\n\n\t\t/*\n\t\t\tReturns the output generated by wikifying the given text, throwing if there were errors.\n\t\t*/\n\t\tstatic wikifyEval(text) {\n\t\t\tconst output = document.createDocumentFragment();\n\n\t\t\tnew Wikifier(output, text);\n\n\t\t\tconst errors = output.querySelector('.error');\n\n\t\t\tif (errors !== null) {\n\t\t\t\tthrow new Error(errors.textContent.replace(errorPrologRegExp, ''));\n\t\t\t}\n\n\t\t\treturn output;\n\t\t}\n\n\t\t/*\n\t\t\tCreate and return an internal link.\n\t\t*/\n\t\tstatic createInternalLink(destination, passage, text, callback) {\n\t\t\tconst $link = jQuery(document.createElement('a'));\n\n\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t$link.attr('data-passage', passage);\n\n\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t$link.addClass('link-internal');\n\n\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t$link.addClass('link-visited');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$link.addClass('link-broken');\n\t\t\t\t}\n\n\t\t\t\t$link.ariaClick({ one : true }, () => {\n\t\t\t\t\tif (typeof callback === 'function') {\n\t\t\t\t\t\tcallback();\n\t\t\t\t\t}\n\n\t\t\t\t\tEngine.play(passage);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (text) {\n\t\t\t\t$link.append(document.createTextNode(text));\n\t\t\t}\n\n\t\t\tif (destination) {\n\t\t\t\t$link.appendTo(destination);\n\t\t\t}\n\n\t\t\t// For legacy-compatibility we must return the DOM node.\n\t\t\treturn $link[0];\n\t\t}\n\n\t\t/*\n\t\t\tCreate and return an external link.\n\t\t*/\n\t\tstatic createExternalLink(destination, url, text) {\n\t\t\tconst $link = jQuery(document.createElement('a'))\n\t\t\t\t.attr('target', '_blank')\n\t\t\t\t.addClass('link-external')\n\t\t\t\t.text(text)\n\t\t\t\t.appendTo(destination);\n\n\t\t\tif (url != null) { // lazy equality for null\n\t\t\t\t$link.attr({\n\t\t\t\t\thref     : url,\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// For legacy-compatibility we must return the DOM node.\n\t\t\treturn $link[0];\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the given link source is external (probably).\n\t\t*/\n\t\tstatic isExternalLink(link) {\n\t\t\tif (Story.has(link)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst urlRegExp = new RegExp(`^${Patterns.url}`, 'gim');\n\t\t\treturn urlRegExp.test(link) || /[/.?#]/.test(link);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tOption Static Object.\n\t*******************************************************************************************************************/\n\tObject.defineProperty(Wikifier, 'Option', {\n\t\tvalue : (() => {\n\t\t\t// Options array (stack).\n\t\t\tlet _optionsStack = [];\n\n\n\t\t\t/*\n\t\t\t\tGlobalOption Functions.\n\t\t\t*/\n\t\t\tfunction optionLength() {\n\t\t\t\treturn _optionsStack.length;\n\t\t\t}\n\n\t\t\tfunction optionGetter() {\n\t\t\t\treturn Object.assign({}, ..._optionsStack);\n\t\t\t}\n\n\t\t\tfunction optionClear() {\n\t\t\t\t_optionsStack = [];\n\t\t\t}\n\n\t\t\tfunction optionGet(idx) {\n\t\t\t\treturn _optionsStack[idx];\n\t\t\t}\n\n\t\t\tfunction optionPop() {\n\t\t\t\treturn _optionsStack.pop();\n\t\t\t}\n\n\t\t\tfunction optionPush(options) {\n\t\t\t\tif (typeof options !== 'object' || options === null) {\n\t\t\t\t\tthrow new TypeError(`Wikifier.Option.push options parameter must be an object (received: ${Util.getType(options)})`);\n\t\t\t\t}\n\n\t\t\t\treturn _optionsStack.push(options);\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tExports.\n\t\t\t*/\n\t\t\treturn Object.freeze(Object.defineProperties({}, {\n\t\t\t\tlength  : { get : optionLength },\n\t\t\t\toptions : { get : optionGetter },\n\t\t\t\tclear   : { value : optionClear },\n\t\t\t\tget     : { value : optionGet },\n\t\t\t\tpop     : { value : optionPop },\n\t\t\t\tpush    : { value : optionPush }\n\t\t\t}));\n\t\t})()\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tParser Static Object.\n\t*******************************************************************************************************************/\n\tObject.defineProperty(Wikifier, 'Parser', {\n\t\tvalue : (() => {\n\t\t\t// Parser definition array.  Ordering matters, so this must be an ordered list.\n\t\t\tconst _parsers = [];\n\n\t\t\t// Parser profiles object.\n\t\t\tlet _profiles;\n\n\n\t\t\t/*\n\t\t\t\tParser Functions.\n\t\t\t*/\n\t\t\tfunction parsersGetter() {\n\t\t\t\treturn _parsers;\n\t\t\t}\n\n\t\t\tfunction parsersAdd(parser) {\n\t\t\t\t// Parser object sanity checks.\n\t\t\t\tif (typeof parser !== 'object') {\n\t\t\t\t\tthrow new Error('Wikifier.Parser.add parser parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('name')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"name\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.name !== 'string') {\n\t\t\t\t\tthrow new Error('parser object \"name\" property must be a string');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('match')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"match\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.match !== 'string') {\n\t\t\t\t\tthrow new Error('parser object \"match\" property must be a string');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('handler')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"handler\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.handler !== 'function') {\n\t\t\t\t\tthrow new Error('parser object \"handler\" property must be a function');\n\t\t\t\t}\n\n\t\t\t\tif (parser.hasOwnProperty('profiles') && !Array.isArray(parser.profiles)) {\n\t\t\t\t\tthrow new Error('parser object \"profiles\" property must be an array');\n\t\t\t\t}\n\n\t\t\t\t// Check for an existing parser with the same name.\n\t\t\t\tif (parsersHas(parser.name)) {\n\t\t\t\t\tthrow new Error(`cannot clobber existing parser \"${parser.name}\"`);\n\t\t\t\t}\n\n\t\t\t\t// Add the parser to the end of the array.\n\t\t\t\t_parsers.push(parser);\n\t\t\t}\n\n\t\t\tfunction parsersDelete(name) {\n\t\t\t\tconst parser = _parsers.find(parser => parser.name === name);\n\n\t\t\t\tif (parser) {\n\t\t\t\t\t_parsers.delete(parser);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction parsersIsEmpty() {\n\t\t\t\treturn _parsers.length === 0;\n\t\t\t}\n\n\t\t\tfunction parsersHas(name) {\n\t\t\t\treturn !!_parsers.find(parser => parser.name === name);\n\t\t\t}\n\n\t\t\tfunction parsersGet(name) {\n\t\t\t\treturn _parsers.find(parser => parser.name === name) || null;\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tParser Profile Functions.\n\t\t\t*/\n\t\t\tfunction profilesGetter() {\n\t\t\t\treturn _profiles;\n\t\t\t}\n\n\t\t\tfunction profilesCompile() {\n\t\t\t\tif (DEBUG) { console.log('[Wikifier.Parser/profilesCompile()]'); }\n\n\t\t\t\tconst all  = _parsers;\n\t\t\t\tconst core = all.filter(parser => !Array.isArray(parser.profiles) || parser.profiles.includes('core'));\n\n\t\t\t\t_profiles = Object.freeze({\n\t\t\t\t\tall : {\n\t\t\t\t\t\tparsers      : all,\n\t\t\t\t\t\tparserRegExp : new RegExp(all.map(parser => `(${parser.match})`).join('|'), 'gm')\n\t\t\t\t\t},\n\t\t\t\t\tcore : {\n\t\t\t\t\t\tparsers      : core,\n\t\t\t\t\t\tparserRegExp : new RegExp(core.map(parser => `(${parser.match})`).join('|'), 'gm')\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\treturn _profiles;\n\t\t\t}\n\n\t\t\tfunction profilesIsEmpty() {\n\t\t\t\treturn typeof _profiles !== 'object' || Object.keys(_profiles).length === 0;\n\t\t\t}\n\n\t\t\tfunction profilesGet(profile) {\n\t\t\t\tif (typeof _profiles !== 'object' || !_profiles.hasOwnProperty(profile)) {\n\t\t\t\t\tthrow new Error(`nonexistent parser profile \"${profile}\"`);\n\t\t\t\t}\n\n\t\t\t\treturn _profiles[profile];\n\t\t\t}\n\n\t\t\tfunction profilesHas(profile) {\n\t\t\t\treturn typeof _profiles === 'object' && _profiles.hasOwnProperty(profile);\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tExports.\n\t\t\t*/\n\t\t\treturn Object.freeze(Object.defineProperties({}, {\n\t\t\t\t/*\n\t\t\t\t\tParser Containers.\n\t\t\t\t*/\n\t\t\t\tparsers : { get : parsersGetter },\n\n\t\t\t\t/*\n\t\t\t\t\tParser Functions.\n\t\t\t\t*/\n\t\t\t\tadd     : { value : parsersAdd },\n\t\t\t\tdelete  : { value : parsersDelete },\n\t\t\t\tisEmpty : { value : parsersIsEmpty },\n\t\t\t\thas     : { value : parsersHas },\n\t\t\t\tget     : { value : parsersGet },\n\n\t\t\t\t/*\n\t\t\t\t\tParser Profile.\n\t\t\t\t*/\n\t\t\t\tProfile : {\n\t\t\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tProfiles Containers.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tprofiles : { get : profilesGetter },\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tProfiles Functions.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tcompile : { value : profilesCompile },\n\t\t\t\t\t\tisEmpty : { value : profilesIsEmpty },\n\t\t\t\t\t\thas     : { value : profilesHas },\n\t\t\t\t\t\tget     : { value : profilesGet }\n\t\t\t\t\t}))\n\t\t\t\t}\n\t\t\t}));\n\t\t})()\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAdditional Static Properties.\n\t*******************************************************************************************************************/\n\tObject.defineProperties(Wikifier, {\n\t\thelpers : { value : {} },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tgetValue       : { value : State.getVar },              // SEE: `state.js`.\n\t\tsetValue       : { value : State.setVar },              // SEE: `state.js`.\n\t\tparse          : { value : Scripting.parse },           // SEE: `markup/scripting.js`.\n\t\tevalExpression : { value : Scripting.evalTwineScript }, // SEE: `markup/scripting.js`.\n\t\tevalStatements : { value : Scripting.evalTwineScript }, // SEE: `markup/scripting.js`.\n\t\ttextPrimitives : { value : Patterns }                   // SEE: `lib/patterns.js`.\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tHelper Static Methods.\n\t*******************************************************************************************************************/\n\tObject.defineProperties(Wikifier.helpers, {\n\t\tinlineCss : {\n\t\t\tvalue : (() => {\n\t\t\t\tconst lookaheadRe = new RegExp(Patterns.inlineCss, 'gm');\n\t\t\t\tconst idOrClassRe = new RegExp(`(${Patterns.cssIdOrClassSigil})(${Patterns.anyLetter}+)`, 'g');\n\n\t\t\t\tfunction helperInlineCss(w) {\n\t\t\t\t\tconst css = { classes : [], id : '', styles : {} };\n\t\t\t\t\tlet matched;\n\n\t\t\t\t\tdo {\n\t\t\t\t\t\tlookaheadRe.lastIndex = w.nextMatch;\n\n\t\t\t\t\t\tconst match = lookaheadRe.exec(w.source);\n\n\t\t\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\t\t\tif (matched) {\n\t\t\t\t\t\t\tif (match[1]) {\n\t\t\t\t\t\t\t\tcss.styles[Util.fromCssProperty(match[1])] = match[2].trim();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (match[3]) {\n\t\t\t\t\t\t\t\tcss.styles[Util.fromCssProperty(match[3])] = match[4].trim();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (match[5]) {\n\t\t\t\t\t\t\t\tlet subMatch;\n\n\t\t\t\t\t\t\t\tidOrClassRe.lastIndex = 0; // NOTE: Guard against buggy implementations.\n\n\t\t\t\t\t\t\t\twhile ((subMatch = idOrClassRe.exec(match[5])) !== null) {\n\t\t\t\t\t\t\t\t\tif (subMatch[1] === '.') {\n\t\t\t\t\t\t\t\t\t\tcss.classes.push(subMatch[2]);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tcss.id = subMatch[2];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tw.nextMatch = lookaheadRe.lastIndex; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\t\t\t\t\t} while (matched);\n\n\t\t\t\t\treturn css;\n\t\t\t\t}\n\n\t\t\t\treturn helperInlineCss;\n\t\t\t})()\n\t\t},\n\n\t\tevalText : {\n\t\t\tvalue(text) {\n\t\t\t\tlet result;\n\n\t\t\t\ttry {\n\t\t\t\t\tresult = Scripting.evalTwineScript(text);\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAttempt to prevent the leakage of auto-globals by enforcing that\n\t\t\t\t\t\tthe resultant value be either a string or a number.\n\n\t\t\t\t\t\tNOTE: This is not a foolproof solution to the problem of auto-global\n\t\t\t\t\t\tleakage.  Various auto-globals, which return strings or numbers, can\n\t\t\t\t\t\tstill leak through—e.g. `window.status` → string.\n\t\t\t\t\t*/\n\t\t\t\t\tswitch (typeof result) {\n\t\t\t\t\tcase 'string':\n\t\t\t\t\t\tif (result.trim() === '') {\n\t\t\t\t\t\t\tresult = text;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'number':\n\t\t\t\t\t\tresult = String(result);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tresult = text;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\tresult = text;\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}\n\t\t},\n\n\t\tevalPassageId : {\n\t\t\tvalue(passage) {\n\t\t\t\tif (passage == null || Story.has(passage)) { // lazy equality for null; `0` is a valid name, so we cannot simply evaluate `passage`\n\t\t\t\t\treturn passage;\n\t\t\t\t}\n\n\t\t\t\treturn Wikifier.helpers.evalText(passage);\n\t\t\t}\n\t\t},\n\n\t\thasBlockContext : {\n\t\t\tvalue(nodes) {\n\t\t\t\tconst hasGCS = typeof window.getComputedStyle === 'function';\n\n\t\t\t\tfor (let i = nodes.length - 1; i >= 0; --i) {\n\t\t\t\t\tconst node = nodes[i];\n\n\t\t\t\t\tswitch (node.nodeType) {\n\t\t\t\t\tcase Node.ELEMENT_NODE:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst tagName = node.nodeName.toUpperCase();\n\n\t\t\t\t\t\t\tif (tagName === 'BR') {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst styles = hasGCS ? window.getComputedStyle(node, null) : node.currentStyle;\n\n\t\t\t\t\t\t\tif (styles && styles.display) {\n\t\t\t\t\t\t\t\tif (styles.display === 'none') {\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn styles.display === 'block';\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tWebKit/Blink-based browsers do not attach any computed style\n\t\t\t\t\t\t\t\tinformation to elements until they're inserted into the DOM\n\t\t\t\t\t\t\t\t(and probably visible), not even the default browser styles\n\t\t\t\t\t\t\t\tand any user styles.  So, we make an assumption based on the\n\t\t\t\t\t\t\t\telement.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tswitch (tagName) {\n\t\t\t\t\t\t\tcase 'ADDRESS':\n\t\t\t\t\t\t\tcase 'ARTICLE':\n\t\t\t\t\t\t\tcase 'ASIDE':\n\t\t\t\t\t\t\tcase 'BLOCKQUOTE':\n\t\t\t\t\t\t\tcase 'CENTER':\n\t\t\t\t\t\t\tcase 'DIV':\n\t\t\t\t\t\t\tcase 'DL':\n\t\t\t\t\t\t\tcase 'FIGURE':\n\t\t\t\t\t\t\tcase 'FOOTER':\n\t\t\t\t\t\t\tcase 'FORM':\n\t\t\t\t\t\t\tcase 'H1':\n\t\t\t\t\t\t\tcase 'H2':\n\t\t\t\t\t\t\tcase 'H3':\n\t\t\t\t\t\t\tcase 'H4':\n\t\t\t\t\t\t\tcase 'H5':\n\t\t\t\t\t\t\tcase 'H6':\n\t\t\t\t\t\t\tcase 'HEADER':\n\t\t\t\t\t\t\tcase 'HR':\n\t\t\t\t\t\t\tcase 'MAIN':\n\t\t\t\t\t\t\tcase 'NAV':\n\t\t\t\t\t\t\tcase 'OL':\n\t\t\t\t\t\t\tcase 'P':\n\t\t\t\t\t\t\tcase 'PRE':\n\t\t\t\t\t\t\tcase 'SECTION':\n\t\t\t\t\t\t\tcase 'TABLE':\n\t\t\t\t\t\t\tcase 'UL':\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn false;\n\n\t\t\t\t\tcase Node.COMMENT_NODE:\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t},\n\n\t\tcreateShadowSetterCallback : {\n\t\t\tvalue : (() => {\n\t\t\t\tlet macroParser = null;\n\n\t\t\t\tfunction cacheMacroParser() {\n\t\t\t\t\tif (!macroParser) {\n\t\t\t\t\t\tmacroParser = Wikifier.Parser.get('macro');\n\n\t\t\t\t\t\tif (!macroParser) {\n\t\t\t\t\t\t\tthrow new Error('cannot find \"macro\" parser');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn macroParser;\n\t\t\t\t}\n\n\t\t\t\tfunction getMacroContextShadowView() {\n\t\t\t\t\tconst macro = macroParser || cacheMacroParser();\n\t\t\t\t\tconst view  = new Set();\n\n\t\t\t\t\tfor (let context = macro.context; context !== null; context = context.parent) {\n\t\t\t\t\t\tif (context._shadows) {\n\t\t\t\t\t\t\tcontext._shadows.forEach(name => view.add(name));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn [...view];\n\t\t\t\t}\n\n\t\t\t\tfunction helperCreateShadowSetterCallback(code) {\n\t\t\t\t\tconst shadowStore = {};\n\n\t\t\t\t\tgetMacroContextShadowView().forEach(varName => {\n\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\t\t\t\t\t});\n\n\t\t\t\t\treturn function () {\n\t\t\t\t\t\tconst shadowNames = Object.keys(shadowStore);\n\t\t\t\t\t\tconst valueCache  = shadowNames.length > 0 ? {} : null;\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t\t\tevaluation.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tCache the existing values of the variables to be shadowed and assign the\n\t\t\t\t\t\t\t\tshadow values.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tstore[varKey] = shadowStore[varName];\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t// Evaluate the JavaScript.\n\t\t\t\t\t\t\treturn Scripting.evalJavaScript(code);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t// Revert the variable shadowing.\n\t\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tUpdate the shadow store with the variable's current value, in case it\n\t\t\t\t\t\t\t\t\twas modified during the callback.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\n\t\t\t\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn helperCreateShadowSetterCallback;\n\t\t\t})()\n\t\t},\n\n\t\tparseSquareBracketedMarkup : {\n\t\t\tvalue : (() => {\n\t\t\t\t/* eslint-disable no-param-reassign */\n\t\t\t\tconst Item = Lexer.enumFromNames([ // lex item types object (pseudo-enumeration)\n\t\t\t\t\t'Error',     // error\n\t\t\t\t\t'DelimLTR',  // '|' or '->'\n\t\t\t\t\t'DelimRTL',  // '<-'\n\t\t\t\t\t'InnerMeta', // ']['\n\t\t\t\t\t'ImageMeta', // '[img[', '[<img[', or '[>img['\n\t\t\t\t\t'LinkMeta',  // '[['\n\t\t\t\t\t'Link',      // link destination\n\t\t\t\t\t'RightMeta', // ']]'\n\t\t\t\t\t'Setter',    // setter expression\n\t\t\t\t\t'Source',    // image source\n\t\t\t\t\t'Text'       // link text or image alt text\n\t\t\t\t]);\n\t\t\t\tconst Delim = Lexer.enumFromNames([ // delimiter state object (pseudo-enumeration)\n\t\t\t\t\t'None', // no delimiter encountered\n\t\t\t\t\t'LTR',  // '|' or '->'\n\t\t\t\t\t'RTL'   // '<-'\n\t\t\t\t]);\n\n\t\t\t\t// Lexing functions.\n\t\t\t\tfunction slurpQuote(lexer, endQuote) {\n\t\t\t\t\tloop: for (;;) {\n\t\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/* falls through */\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn EOF;\n\n\t\t\t\t\t\tcase endQuote:\n\t\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t\t}\n\n\t\t\t\t\treturn lexer.pos;\n\t\t\t\t}\n\n\t\t\t\tfunction lexLeftMeta(lexer) {\n\t\t\t\t\tif (!lexer.accept('[')) {\n\t\t\t\t\t\treturn lexer.error(Item.Error, 'malformed square-bracketed markup');\n\t\t\t\t\t}\n\n\t\t\t\t\t// Is link markup.\n\t\t\t\t\tif (lexer.accept('[')) {\n\t\t\t\t\t\tlexer.data.isLink = true;\n\t\t\t\t\t\tlexer.emit(Item.LinkMeta);\n\t\t\t\t\t}\n\n\t\t\t\t\t// May be image markup.\n\t\t\t\t\telse {\n\t\t\t\t\t\tlexer.accept('<>'); // aligner syntax\n\n\t\t\t\t\t\tif (!lexer.accept('Ii') || !lexer.accept('Mm') || !lexer.accept('Gg') || !lexer.accept('[')) {\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, 'malformed square-bracketed markup');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlexer.data.isLink = false;\n\t\t\t\t\t\tlexer.emit(Item.ImageMeta);\n\t\t\t\t\t}\n\n\t\t\t\t\tlexer.depth = 2; // account for both initial left square brackets\n\t\t\t\t\treturn lexCoreComponents;\n\t\t\t\t}\n\n\t\t\t\tfunction lexCoreComponents(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\t\t\t\t\tlet delim = Delim.None;\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tThis is not entirely reliable within sections that allow raw strings, since\n\t\t\t\t\t\t\t\tit's possible, however unlikely, for a raw string to contain unpaired double\n\t\t\t\t\t\t\t\tquotes.  The likelihood is low enough, however, that I'm deeming the risk as\n\t\t\t\t\t\t\t\tacceptable—for now, at least.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '|': // possible pipe ('|') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None) {\n\t\t\t\t\t\t\t\tdelim = Delim.LTR;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\tlexer.forward();\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimLTR);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '-': // possible right arrow ('->') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None && lexer.peek() === '>') {\n\t\t\t\t\t\t\t\tdelim = Delim.LTR;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimLTR);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '<': // possible left arrow ('<-') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None && lexer.peek() === '-') {\n\t\t\t\t\t\t\t\tdelim = Delim.RTL;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimRTL);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tswitch (lexer.peek()) {\n\t\t\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\n\t\t\t\t\t\t\t\t\tif (delim === Delim.RTL) {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.InnerMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn lexer.data.isLink ? lexSetter : lexImageLink;\n\n\t\t\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\n\t\t\t\t\t\t\t\t\tif (delim === Delim.RTL) {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfunction lexImageLink(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tThis is not entirely reliable within sections that allow raw strings, since\n\t\t\t\t\t\t\t\tit's possible, however unlikely, for a raw string to contain unpaired double\n\t\t\t\t\t\t\t\tquotes.  The likelihood is low enough, however, that I'm deeming the risk as\n\t\t\t\t\t\t\t\tacceptable—for now, at least.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup link component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tswitch (lexer.peek()) {\n\t\t\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.Link);\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.InnerMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn lexSetter;\n\n\t\t\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.Link);\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfunction lexSetter(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup setter component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase \"'\":\n\t\t\t\t\t\t\tif (slurpQuote(lexer, \"'\") === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated single quoted string in ${what} markup setter component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tif (lexer.peek() !== ']') {\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Setter);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Parse function.\n\t\t\t\tfunction parseSquareBracketedMarkup(w) {\n\t\t\t\t\t// Initialize the lexer.\n\t\t\t\t\tconst lexer  = new Lexer(w.source, lexLeftMeta);\n\n\t\t\t\t\t// Set the initial positions within the source string.\n\t\t\t\t\tlexer.start = lexer.pos = w.matchStart;\n\n\t\t\t\t\t// Lex the raw argument string.\n\t\t\t\t\tconst markup = {};\n\t\t\t\t\tconst items  = lexer.run();\n\t\t\t\t\tconst last   = items.last();\n\n\t\t\t\t\tif (last && last.type === Item.Error) {\n\t\t\t\t\t\tmarkup.error = last.message;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\titems.forEach(item => {\n\t\t\t\t\t\t\tconst text = item.text.trim();\n\n\t\t\t\t\t\t\tswitch (item.type) {\n\t\t\t\t\t\t\tcase Item.ImageMeta:\n\t\t\t\t\t\t\t\tmarkup.isImage = true;\n\n\t\t\t\t\t\t\t\tif (text[1] === '<') {\n\t\t\t\t\t\t\t\t\tmarkup.align = 'left';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (text[1] === '>') {\n\t\t\t\t\t\t\t\t\tmarkup.align = 'right';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.LinkMeta:\n\t\t\t\t\t\t\t\tmarkup.isLink = true;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Link:\n\t\t\t\t\t\t\t\tif (text[0] === '~') {\n\t\t\t\t\t\t\t\t\tmarkup.forceInternal = true;\n\t\t\t\t\t\t\t\t\tmarkup.link = text.slice(1);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tmarkup.link = text;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Setter:\n\t\t\t\t\t\t\t\tmarkup.setter = text;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Source:\n\t\t\t\t\t\t\t\tmarkup.source = text;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Text:\n\t\t\t\t\t\t\t\tmarkup.text = text;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tmarkup.pos = lexer.pos;\n\t\t\t\t\treturn markup;\n\t\t\t\t}\n\n\t\t\t\treturn parseSquareBracketedMarkup;\n\t\t\t\t/* eslint-enable no-param-reassign */\n\t\t\t})()\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Wikifier;\n})();\n/* eslint-enable max-len */\n\n/***********************************************************************************************************************\n\n\tmarkup/parserlib.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, DebugView, EOF, Engine, Lexer, Macro, MacroContext, Patterns, Scripting, State, Story, Template,\n\t       Wikifier, toStringOrDefault, throwError\n*/\n/* eslint \"no-param-reassign\": [ 2, { \"props\" : false } ] */\n\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _verbatimTagHandler(w) {\n\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\tconst match = this.lookahead.exec(w.source);\n\n\t\tif (match && match.index === w.matchStart) {\n\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t.append(match[1])\n\t\t\t\t.appendTo(w.output);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tParsers.\n\t*******************************************************************************************************************/\n\tWikifier.Parser.add({\n\t\tname       : 'quoteByBlock',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^<<<\\\\n',\n\t\tterminator : '^<<<\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.subWikify(\n\t\t\t\tjQuery(document.createElement('blockquote'))\n\t\t\t\t\t.appendTo(w.output)\n\t\t\t\t\t.get(0),\n\t\t\t\tthis.terminator\n\t\t\t);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'quoteByLine',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^>+',\n\t\tlookahead  : /^>+/gm,\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst destStack = [w.output];\n\t\t\tlet curLevel = 0;\n\t\t\tlet newLevel = w.matchLength;\n\t\t\tlet matched;\n\t\t\tlet i;\n\n\t\t\tdo {\n\t\t\t\tif (newLevel > curLevel) {\n\t\t\t\t\tfor (i = curLevel; i < newLevel; ++i) {\n\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\tjQuery(document.createElement('blockquote'))\n\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (newLevel < curLevel) {\n\t\t\t\t\tfor (i = curLevel; i > newLevel; --i) {\n\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcurLevel = newLevel;\n\t\t\t\tw.subWikify(destStack[destStack.length - 1], this.terminator);\n\t\t\t\tjQuery(document.createElement('br')).appendTo(destStack[destStack.length - 1]);\n\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tnewLevel = match[0].length;\n\t\t\t\t\tw.nextMatch += match[0].length;\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'macro',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<<',\n\t\tlookahead : new RegExp(`<<(/?${Patterns.macroName})(?:\\\\s*)((?:(?:\\`(?:\\\\\\\\.|[^\\`\\\\\\\\])*\\`)|(?:\"(?:\\\\\\\\.|[^\"\\\\\\\\])*\")|(?:'(?:\\\\\\\\.|[^'\\\\\\\\])*')|(?:\\\\[(?:[<>]?[Ii][Mm][Gg])?\\\\[[^\\\\r\\\\n]*?\\\\]\\\\]+)|[^>]|(?:>(?!>)))*)>>`, 'gm'),\n\t\tworking   : { source : '', name : '', arguments : '', index : 0 }, // the working parse object\n\t\tcontext   : null, // last execution context object (top-level macros, hierarchically, have a null context)\n\n\t\thandler(w) {\n\t\t\tconst matchStart = this.lookahead.lastIndex = w.matchStart;\n\n\t\t\tif (this.parseTag(w)) {\n\t\t\t\t/*\n\t\t\t\t\tIf `parseBody()` is called below, it will modify the current working\n\t\t\t\t\tvalues, so we must cache them now.\n\t\t\t\t*/\n\t\t\t\tconst nextMatch = w.nextMatch;\n\t\t\t\tconst name      = this.working.name;\n\t\t\t\tconst rawArgs   = this.working.arguments;\n\t\t\t\tlet macro;\n\n\t\t\t\ttry {\n\t\t\t\t\tmacro = Macro.get(name);\n\n\t\t\t\t\tif (macro) {\n\t\t\t\t\t\tlet payload = null;\n\n\t\t\t\t\t\tif (macro.hasOwnProperty('tags')) {\n\t\t\t\t\t\t\tpayload = this.parseBody(w, macro);\n\n\t\t\t\t\t\t\tif (!payload) {\n\t\t\t\t\t\t\t\tw.nextMatch = nextMatch; // we must reset `w.nextMatch` here, as `parseBody()` modifies it\n\t\t\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t\t`cannot find a closing tag for macro <<${name}>>`,\n\t\t\t\t\t\t\t\t\t`${w.source.slice(matchStart, w.nextMatch)}\\u2026`\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (typeof macro.handler === 'function') {\n\t\t\t\t\t\t\tconst args = !payload\n\t\t\t\t\t\t\t\t? this.createArgs(rawArgs, this.skipArgs(macro, macro.name))\n\t\t\t\t\t\t\t\t: payload[0].args;\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tNew-style macros.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (macro.hasOwnProperty('_MACRO_API')) {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tAdd the macro's execution context to the context chain.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tthis.context = new MacroContext({\n\t\t\t\t\t\t\t\t\tmacro,\n\t\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\t\targs,\n\t\t\t\t\t\t\t\t\tpayload,\n\t\t\t\t\t\t\t\t\tsource : w.source.slice(matchStart, w.nextMatch),\n\t\t\t\t\t\t\t\t\tparent : this.context,\n\t\t\t\t\t\t\t\t\tparser : w\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tCall the handler.\n\n\t\t\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\t\t\t\t\t\tto ensure that the execution context is properly restored in the event\n\t\t\t\t\t\t\t\t\tthat an uncaught exception is thrown during the handler call.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tmacro.handler.call(this.context);\n\t\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\t\tQUESTION: Swap to the following, which passes macro arguments in\n\t\t\t\t\t\t\t\t\t\tas parameters to the handler function, in addition to them being\n\t\t\t\t\t\t\t\t\t\tavailable on its `this`?  If so, it might still be something to\n\t\t\t\t\t\t\t\t\t\thold off on until v3, when the legacy macro API is removed.\n\n\t\t\t\t\t\t\t\t\t\tmacro.handler.apply(this.context, this.context.args);\n\t\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t\tthis.context = this.context.parent;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t[DEPRECATED] Old-style/legacy macros.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tSet up the raw arguments string.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tconst prevRawArgs = w._rawArgs;\n\t\t\t\t\t\t\t\tw._rawArgs = rawArgs;\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tCall the handler.\n\n\t\t\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\t\t\t\t\t\tto ensure that the previous raw arguments string is properly restored in\n\t\t\t\t\t\t\t\t\tthe event that an uncaught exception is thrown during the handler call.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tmacro.handler(w.output, name, args, w, payload);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t\tw._rawArgs = prevRawArgs;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t`macro <<${name}>> handler function ${macro.hasOwnProperty('handler') ? 'is not a function' : 'does not exist'}`,\n\t\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (Macro.tags.has(name)) {\n\t\t\t\t\t\tconst tags = Macro.tags.get(name);\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`child tag <<${name}>> was found outside of a call to its parent macro${tags.length === 1 ? '' : 's'} <<${tags.join('>>, <<')}>>`,\n\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`macro <<${name}>> does not exist`,\n\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot execute ${macro && macro.isWidget ? 'widget' : 'macro'} <<${name}>>: ${ex.message}`,\n\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\tthis.working.source    = '';\n\t\t\t\t\tthis.working.name      = '';\n\t\t\t\t\tthis.working.arguments = '';\n\t\t\t\t\tthis.working.index     = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t}\n\t\t},\n\n\t\tparseTag(w) {\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart && match[1]) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tthis.working.source    = w.source.slice(match.index, this.lookahead.lastIndex);\n\t\t\t\tthis.working.name      = match[1];\n\t\t\t\tthis.working.arguments = match[2];\n\t\t\t\tthis.working.index     = match.index;\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t},\n\n\t\tparseBody(w, macro) {\n\t\t\tconst openTag  = this.working.name;\n\t\t\tconst closeTag = `/${openTag}`;\n\t\t\tconst closeAlt = `end${openTag}`;\n\t\t\tconst bodyTags = Array.isArray(macro.tags) ? macro.tags : false;\n\t\t\tconst payload  = [];\n\t\t\tlet end          = -1;\n\t\t\tlet opened       = 1;\n\t\t\tlet curSource    = this.working.source;\n\t\t\tlet curTag       = this.working.name;\n\t\t\tlet curArgument  = this.working.arguments;\n\t\t\tlet contentStart = w.nextMatch;\n\n\t\t\twhile ((w.matchStart = w.source.indexOf(this.match, w.nextMatch)) !== -1) {\n\t\t\t\tif (!this.parseTag(w)) {\n\t\t\t\t\tthis.lookahead.lastIndex = w.nextMatch = w.matchStart + this.match.length;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst tagSource = this.working.source;\n\t\t\t\tconst tagName   = this.working.name;\n\t\t\t\tconst tagArgs   = this.working.arguments;\n\t\t\t\tconst tagBegin  = this.working.index;\n\t\t\t\tconst tagEnd    = w.nextMatch;\n\n\t\t\t\tswitch (tagName) {\n\t\t\t\tcase openTag:\n\t\t\t\t\t++opened;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase closeAlt:\n\t\t\t\tcase closeTag:\n\t\t\t\t\t--opened;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tif (opened === 1 && bodyTags) {\n\t\t\t\t\t\tfor (let i = 0, iend = bodyTags.length; i < iend; ++i) {\n\t\t\t\t\t\t\tif (tagName === bodyTags[i]) {\n\t\t\t\t\t\t\t\tpayload.push({\n\t\t\t\t\t\t\t\t\tsource    : curSource,\n\t\t\t\t\t\t\t\t\tname      : curTag,\n\t\t\t\t\t\t\t\t\targuments : curArgument,\n\t\t\t\t\t\t\t\t\targs      : this.createArgs(curArgument, this.skipArgs(macro, curTag)),\n\t\t\t\t\t\t\t\t\tcontents  : w.source.slice(contentStart, tagBegin)\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tcurSource    = tagSource;\n\t\t\t\t\t\t\t\tcurTag       = tagName;\n\t\t\t\t\t\t\t\tcurArgument  = tagArgs;\n\t\t\t\t\t\t\t\tcontentStart = tagEnd;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (opened === 0) {\n\t\t\t\t\tpayload.push({\n\t\t\t\t\t\tsource    : curSource,\n\t\t\t\t\t\tname      : curTag,\n\t\t\t\t\t\targuments : curArgument,\n\t\t\t\t\t\targs      : this.createArgs(curArgument, this.skipArgs(macro, curTag)),\n\t\t\t\t\t\tcontents  : w.source.slice(contentStart, tagBegin)\n\t\t\t\t\t});\n\t\t\t\t\tend = tagEnd;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (end !== -1) {\n\t\t\t\tw.nextMatch = end;\n\t\t\t\treturn payload;\n\t\t\t}\n\n\t\t\treturn null;\n\t\t},\n\n\t\tcreateArgs(rawArgsString, skipArgs) {\n\t\t\tconst args = skipArgs ? [] : this.parseArgs(rawArgsString);\n\n\t\t\t// Extend the args array with the raw and full argument strings.\n\t\t\tObject.defineProperties(args, {\n\t\t\t\traw : {\n\t\t\t\t\tvalue : rawArgsString\n\t\t\t\t},\n\t\t\t\tfull : {\n\t\t\t\t\tvalue : Scripting.parse(rawArgsString)\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn args;\n\t\t},\n\n\t\tskipArgs(macro, tagName) {\n\t\t\tif (macro.hasOwnProperty('skipArgs')) {\n\t\t\t\tconst sa = macro.skipArgs;\n\n\t\t\t\treturn typeof sa === 'boolean' && sa || Array.isArray(sa) && sa.includes(tagName);\n\t\t\t}\n\t\t\t/* legacy */\n\t\t\telse if (macro.hasOwnProperty('skipArg0')) {\n\t\t\t\treturn macro.skipArg0 && macro.name === tagName;\n\t\t\t}\n\t\t\t/* /legacy */\n\n\t\t\treturn false;\n\t\t},\n\n\t\tparseArgs : (() => {\n\t\t\tconst Item = Lexer.enumFromNames([ // lex item types object (pseudo-enumeration)\n\t\t\t\t'Error',        // error\n\t\t\t\t'Bareword',     // bare identifier\n\t\t\t\t'Expression',   // expression (backquoted)\n\t\t\t\t'String',       // quoted string (single or double)\n\t\t\t\t'SquareBracket' // [[…]] or [img[…]]\n\t\t\t]);\n\t\t\tconst spaceRe    = new RegExp(Patterns.space);\n\t\t\tconst notSpaceRe = new RegExp(Patterns.notSpace);\n\t\t\tconst varTest    = new RegExp(`^${Patterns.variable}`);\n\n\t\t\t// Lexing functions.\n\t\t\tfunction slurpQuote(lexer, endQuote) {\n\t\t\t\tloop: for (;;) {\n\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* falls through */\n\t\t\t\t\tcase EOF:\n\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\treturn EOF;\n\n\t\t\t\t\tcase endQuote:\n\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t}\n\n\t\t\t\treturn lexer.pos;\n\t\t\t}\n\n\t\t\tfunction lexSpace(lexer) {\n\t\t\t\tconst offset = lexer.source.slice(lexer.pos).search(notSpaceRe);\n\n\t\t\t\tif (offset === EOF) {\n\t\t\t\t\t// no non-whitespace characters, so bail\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\telse if (offset !== 0) {\n\t\t\t\t\tlexer.pos += offset;\n\t\t\t\t\tlexer.ignore();\n\t\t\t\t}\n\n\t\t\t\t// determine what the next state is\n\t\t\t\tswitch (lexer.next()) {\n\t\t\t\tcase '`':\n\t\t\t\t\treturn lexExpression;\n\t\t\t\tcase '\"':\n\t\t\t\t\treturn lexDoubleQuote;\n\t\t\t\tcase \"'\":\n\t\t\t\t\treturn lexSingleQuote;\n\t\t\t\tcase '[':\n\t\t\t\t\treturn lexSquareBracket;\n\t\t\t\tdefault:\n\t\t\t\t\treturn lexBareword;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction lexExpression(lexer) {\n\t\t\t\tif (slurpQuote(lexer, '`') === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated backquote expression');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.Expression);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexDoubleQuote(lexer) {\n\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated double quoted string');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.String);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexSingleQuote(lexer) {\n\t\t\t\tif (slurpQuote(lexer, \"'\") === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated single quoted string');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.String);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexSquareBracket(lexer) {\n\t\t\t\tconst imgMeta = '<>IiMmGg';\n\t\t\t\tlet what;\n\n\t\t\t\tif (lexer.accept(imgMeta)) {\n\t\t\t\t\twhat = 'image';\n\t\t\t\t\tlexer.acceptRun(imgMeta);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\twhat = 'link';\n\t\t\t\t}\n\n\t\t\t\tif (!lexer.accept('[')) {\n\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t}\n\n\t\t\t\tlexer.depth = 2; // account for both initial left square brackets\n\n\t\t\t\tloop: for (;;) {\n\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* falls through */\n\t\t\t\t\tcase EOF:\n\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\tcase '[':\n\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase ']':\n\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\tif (lexer.depth < 0) {\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, \"unexpected right square bracket ']'\");\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\tif (lexer.next() === ']') {\n\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.SquareBracket);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexBareword(lexer) {\n\t\t\t\tconst offset = lexer.source.slice(lexer.pos).search(spaceRe);\n\t\t\t\tlexer.pos = offset === EOF ? lexer.source.length : lexer.pos + offset;\n\t\t\t\tlexer.emit(Item.Bareword);\n\t\t\t\treturn offset === EOF ? null : lexSpace;\n\t\t\t}\n\n\t\t\t// Parse function.\n\t\t\tfunction parseMacroArgs(rawArgsString) {\n\t\t\t\t// Initialize the lexer.\n\t\t\t\tconst lexer = new Lexer(rawArgsString, lexSpace);\n\t\t\t\tconst args  = [];\n\n\t\t\t\t// Lex the raw argument string.\n\t\t\t\tlexer.run().forEach(item => {\n\t\t\t\t\tlet arg = item.text;\n\n\t\t\t\t\tswitch (item.type) {\n\t\t\t\t\tcase Item.Error:\n\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${item.message}`);\n\n\t\t\t\t\tcase Item.Bareword:\n\t\t\t\t\t\t// A variable, so substitute its value.\n\t\t\t\t\t\tif (varTest.test(arg)) {\n\t\t\t\t\t\t\targ = State.getVar(arg);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Property access on the settings or setup objects, so try to evaluate it.\n\t\t\t\t\t\telse if (/^(?:settings|setup)[.[]/.test(arg)) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\targ = Scripting.evalTwineScript(arg);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Null literal, so convert it into null.\n\t\t\t\t\t\telse if (arg === 'null') {\n\t\t\t\t\t\t\targ = null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Undefined literal, so convert it into undefined.\n\t\t\t\t\t\telse if (arg === 'undefined') {\n\t\t\t\t\t\t\targ = undefined;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Boolean true literal, so convert it into true.\n\t\t\t\t\t\telse if (arg === 'true') {\n\t\t\t\t\t\t\targ = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Boolean false literal, so convert it into false.\n\t\t\t\t\t\telse if (arg === 'false') {\n\t\t\t\t\t\t\targ = false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// NaN literal, so convert it into NaN.\n\t\t\t\t\t\telse if (arg === 'NaN') {\n\t\t\t\t\t\t\targ = NaN;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Attempt to convert it into a number, in case it's a numeric literal.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst argAsNum = Number(arg);\n\n\t\t\t\t\t\t\tif (!Number.isNaN(argAsNum)) {\n\t\t\t\t\t\t\t\targ = argAsNum;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.Expression:\n\t\t\t\t\t\targ = arg.slice(1, -1).trim(); // remove the backquotes and trim the expression\n\n\t\t\t\t\t\t// Empty backquotes.\n\t\t\t\t\t\tif (arg === '') {\n\t\t\t\t\t\t\targ = undefined;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Evaluate the expression.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tThe enclosing parenthesis here are necessary to force a code string\n\t\t\t\t\t\t\t\t\tconsisting solely of an object literal to be evaluated as such, rather\n\t\t\t\t\t\t\t\t\tthan as a code block.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\targ = Scripting.evalTwineScript(`(${arg})`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument expression \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.String:\n\t\t\t\t\t\t// Evaluate the string to handle escaped characters.\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\targ = Scripting.evalJavaScript(arg);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument string \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.SquareBracket:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\t\t\tsource     : arg,\n\t\t\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${markup.error}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (markup.pos < arg.length) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": unexpected character(s) \"${arg.slice(markup.pos)}\" (pos: ${markup.pos})`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert to a link or image object.\n\t\t\t\t\t\t\tif (markup.isLink) {\n\t\t\t\t\t\t\t\t// .isLink, [.text], [.forceInternal], .link, [.setter]\n\t\t\t\t\t\t\t\targ = { isLink : true };\n\t\t\t\t\t\t\t\targ.count    = markup.hasOwnProperty('text') ? 2 : 1;\n\t\t\t\t\t\t\t\targ.link     = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\t\t\t\t\t\targ.text     = markup.hasOwnProperty('text') ? Wikifier.helpers.evalText(markup.text) : arg.link;\n\t\t\t\t\t\t\t\targ.external = !markup.forceInternal && Wikifier.isExternalLink(arg.link);\n\t\t\t\t\t\t\t\targ.setFn    = markup.hasOwnProperty('setter')\n\t\t\t\t\t\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (markup.isImage) {\n\t\t\t\t\t\t\t\t// .isImage, [.align], [.title], .source, [.forceInternal], [.link], [.setter]\n\t\t\t\t\t\t\t\targ = (source => {\n\t\t\t\t\t\t\t\t\tconst imgObj = {\n\t\t\t\t\t\t\t\t\t\tsource,\n\t\t\t\t\t\t\t\t\t\tisImage : true\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t\t// Check for Twine 1.4 Base64 image passage transclusion.\n\t\t\t\t\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t\t\t\t\timgObj.source  = passage.text;\n\t\t\t\t\t\t\t\t\t\t\timgObj.passage = passage.title;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturn imgObj;\n\t\t\t\t\t\t\t\t})(Wikifier.helpers.evalPassageId(markup.source));\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('align')) {\n\t\t\t\t\t\t\t\t\targ.align = markup.align;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('text')) {\n\t\t\t\t\t\t\t\t\targ.title = Wikifier.helpers.evalText(markup.text);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('link')) {\n\t\t\t\t\t\t\t\t\targ.link     = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\t\t\t\t\t\t\targ.external = !markup.forceInternal && Wikifier.isExternalLink(arg.link);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\targ.setFn = markup.hasOwnProperty('setter')\n\t\t\t\t\t\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\targs.push(arg);\n\t\t\t\t});\n\n\t\t\t\treturn args;\n\t\t\t}\n\n\t\t\treturn parseMacroArgs;\n\t\t})()\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'link',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\[\\\\[[^[]',\n\n\t\thandler(w) {\n\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup(w);\n\n\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = markup.pos;\n\n\t\t\t// text=(text), forceInternal=(~), link=link, setter=(setter)\n\t\t\tconst link  = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\tconst text  = markup.hasOwnProperty('text') ? Wikifier.helpers.evalText(markup.text) : link;\n\t\t\tconst setFn = markup.hasOwnProperty('setter')\n\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t: null;\n\n\t\t\t// Debug view setup.\n\t\t\tconst output = (Config.debug\n\t\t\t\t? new DebugView(w.output, 'link-markup', '[[link]]', w.source.slice(w.matchStart, w.nextMatch))\n\t\t\t\t: w\n\t\t\t).output;\n\n\t\t\tif (markup.forceInternal || !Wikifier.isExternalLink(link)) {\n\t\t\t\tWikifier.createInternalLink(output, link, text, setFn);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tWikifier.createExternalLink(output, link, text);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'urlLink',\n\t\tprofiles : ['core'],\n\t\tmatch    : Patterns.url,\n\n\t\thandler(w) {\n\t\t\tw.outputText(Wikifier.createExternalLink(w.output, w.matchText), w.matchStart, w.nextMatch);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'image',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\[[<>]?[Ii][Mm][Gg]\\\\[',\n\n\t\thandler(w) {\n\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup(w);\n\n\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = markup.pos;\n\n\t\t\t// Debug view setup.\n\t\t\tlet debugView;\n\n\t\t\tif (Config.debug) {\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tw.output,\n\t\t\t\t\t'image-markup',\n\t\t\t\t\tmarkup.hasOwnProperty('link') ? '[img[][link]]' : '[img[]]',\n\t\t\t\t\tw.source.slice(w.matchStart, w.nextMatch)\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ block : true });\n\t\t\t}\n\n\t\t\t// align=(left|right), title=(title), source=source, forceInternal=(~), link=(link), setter=(setter)\n\t\t\tconst setFn = markup.hasOwnProperty('setter')\n\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t: null;\n\t\t\tlet el     = (Config.debug ? debugView : w).output;\n\t\t\tlet source;\n\n\t\t\tif (markup.hasOwnProperty('link')) {\n\t\t\t\tconst link = Wikifier.helpers.evalPassageId(markup.link);\n\n\t\t\t\tif (markup.forceInternal || !Wikifier.isExternalLink(link)) {\n\t\t\t\t\tel = Wikifier.createInternalLink(el, link, null, setFn);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tel = Wikifier.createExternalLink(el, link);\n\t\t\t\t}\n\n\t\t\t\tel.classList.add('link-image');\n\t\t\t}\n\n\t\t\tel = jQuery(document.createElement('img'))\n\t\t\t\t.appendTo(el)\n\t\t\t\t.get(0);\n\t\t\tsource = Wikifier.helpers.evalPassageId(markup.source);\n\n\t\t\t// Check for image passage transclusion.\n\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\tel.setAttribute('data-passage', passage.title);\n\t\t\t\t\tsource = passage.text.trim();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tel.src = source;\n\n\t\t\tif (markup.hasOwnProperty('text')) {\n\t\t\t\tel.title = Wikifier.helpers.evalText(markup.text);\n\t\t\t}\n\n\t\t\tif (markup.hasOwnProperty('align')) {\n\t\t\t\tel.align = markup.align;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'monospacedByBlock',\n\t\tprofiles  : ['block'],\n\t\tmatch     : '^\\\\{\\\\{\\\\{\\\\n',\n\t\tlookahead : /^\\{\\{\\{\\n((?:^[^\\n]*\\n)+?)(^\\}\\}\\}$\\n?)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tconst pre = jQuery(document.createElement('pre'));\n\t\t\t\tjQuery(document.createElement('code'))\n\t\t\t\t\t.text(match[1])\n\t\t\t\t\t.appendTo(pre);\n\t\t\t\tpre.appendTo(w.output);\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'formatByChar',\n\t\tprofiles : ['core'],\n\t\tmatch    : \"''|//|__|\\\\^\\\\^|~~|==|\\\\{\\\\{\\\\{\",\n\n\t\thandler(w) {\n\t\t\tswitch (w.matchText) {\n\t\t\tcase \"''\":\n\t\t\t\tw.subWikify(jQuery(document.createElement('strong')).appendTo(w.output).get(0), \"''\");\n\t\t\t\tbreak;\n\n\t\t\tcase '//':\n\t\t\t\tw.subWikify(jQuery(document.createElement('em')).appendTo(w.output).get(0), '//');\n\t\t\t\tbreak;\n\n\t\t\tcase '__':\n\t\t\t\tw.subWikify(jQuery(document.createElement('u')).appendTo(w.output).get(0), '__');\n\t\t\t\tbreak;\n\n\t\t\tcase '^^':\n\t\t\t\tw.subWikify(jQuery(document.createElement('sup')).appendTo(w.output).get(0), '\\\\^\\\\^');\n\t\t\t\tbreak;\n\n\t\t\tcase '~~':\n\t\t\t\tw.subWikify(jQuery(document.createElement('sub')).appendTo(w.output).get(0), '~~');\n\t\t\t\tbreak;\n\n\t\t\tcase '==':\n\t\t\t\tw.subWikify(jQuery(document.createElement('s')).appendTo(w.output).get(0), '==');\n\t\t\t\tbreak;\n\n\t\t\tcase '{{{':\n\t\t\t\t{\n\t\t\t\t\tconst lookahead = /\\{\\{\\{((?:.|\\n)*?)\\}\\}\\}/gm;\n\n\t\t\t\t\tlookahead.lastIndex = w.matchStart;\n\n\t\t\t\t\tconst match = lookahead.exec(w.source);\n\n\t\t\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\t\t\tjQuery(document.createElement('code'))\n\t\t\t\t\t\t\t.text(match[1])\n\t\t\t\t\t\t\t.appendTo(w.output);\n\t\t\t\t\t\tw.nextMatch = lookahead.lastIndex;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'customStyle',\n\t\tprofiles   : ['core'],\n\t\tmatch      : '@@',\n\t\tterminator : '@@',\n\t\tblockRe    : /\\s*\\n/gm,\n\n\t\thandler(w) {\n\t\t\tconst css = Wikifier.helpers.inlineCss(w);\n\n\t\t\tthis.blockRe.lastIndex = w.nextMatch; // must follow the call to `inlineCss()`\n\n\t\t\tconst blockMatch = this.blockRe.exec(w.source);\n\t\t\tconst blockLevel = blockMatch && blockMatch.index === w.nextMatch;\n\t\t\tconst $el        = jQuery(document.createElement(blockLevel ? 'div' : 'span'))\n\t\t\t\t.appendTo(w.output);\n\n\t\t\tif (css.classes.length === 0 && css.id === '' && Object.keys(css.styles).length === 0) {\n\t\t\t\t$el.addClass('marked');\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcss.classes.forEach(className => $el.addClass(className));\n\n\t\t\t\tif (css.id !== '') {\n\t\t\t\t\t$el.attr('id', css.id);\n\t\t\t\t}\n\n\t\t\t\t$el.css(css.styles);\n\t\t\t}\n\n\t\t\tif (blockLevel) {\n\t\t\t\t// Skip the leading and, if it exists, trailing newlines.\n\t\t\t\tw.nextMatch += blockMatch[0].length;\n\t\t\t\tw.subWikify($el[0], `\\\\n?${this.terminator}`);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tw.subWikify($el[0], this.terminator);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimText',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '\"{3}|<[Nn][Oo][Ww][Ii][Kk][Ii]>',\n\t\tlookahead : /(?:\"{3}((?:.|\\n)*?)\"{3})|(?:<[Nn][Oo][Ww][Ii][Kk][Ii]>((?:.|\\n)*?)<\\/[Nn][Oo][Ww][Ii][Kk][Ii]>)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tjQuery(document.createElement('span'))\n\t\t\t\t\t.addClass('verbatim')\n\t\t\t\t\t.text(match[1] || match[2])\n\t\t\t\t\t.appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'horizontalRule',\n\t\tprofiles : ['core'],\n\t\tmatch    : '^----+$\\\\n?|<[Hh][Rr]\\\\s*/?>\\\\n?',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createElement('hr')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'emdash',\n\t\tprofiles : ['core'],\n\t\tmatch    : '--',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createTextNode('\\u2014')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'doubleDollarSign',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\${2}', // eslint-disable-line no-template-curly-in-string\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createTextNode('$')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\t/*\n\t\t\tSupported syntax:\n\t\t\t\t$variable\n\t\t\t\t$variable.property\n\t\t\t\t$variable[numericIndex]\n\t\t\t\t$variable[\"property\"]\n\t\t\t\t$variable['property']\n\t\t\t\t$variable[$indexOrPropertyVariable]\n\t\t*/\n\t\tname     : 'nakedVariable',\n\t\tprofiles : ['core'],\n\t\tmatch    : `${Patterns.variable}(?:(?:\\\\.${Patterns.identifier})|(?:\\\\[\\\\d+\\\\])|(?:\\\\[\"(?:\\\\\\\\.|[^\"\\\\\\\\])+\"\\\\])|(?:\\\\['(?:\\\\\\\\.|[^'\\\\\\\\])+'\\\\])|(?:\\\\[${Patterns.variable}\\\\]))*`,\n\n\t\thandler(w) {\n\t\t\tconst result = toStringOrDefault(State.getVar(w.matchText), null);\n\n\t\t\tif (result === null) {\n\t\t\t\tjQuery(document.createTextNode(w.matchText)).appendTo(w.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnew Wikifier(\n\t\t\t\t\t(Config.debug\n\t\t\t\t\t\t? new DebugView(w.output, 'variable', w.matchText, w.matchText) // Debug view setup.\n\t\t\t\t\t\t: w\n\t\t\t\t\t).output,\n\t\t\t\t\tresult\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'template',\n\t\tprofiles : ['core'],\n\t\tmatch    : `\\\\?${Patterns.templateName}`,\n\n\t\thandler(w) {\n\t\t\tconst name = w.matchText.slice(1);\n\t\t\tlet template = Template.get(name);\n\t\t\tlet result   = null;\n\n\t\t\t// If we have an array of templates, randomly choose one.\n\t\t\tif (template instanceof Array) {\n\t\t\t\ttemplate = template.random();\n\t\t\t}\n\n\t\t\tswitch (typeof template) {\n\t\t\tcase 'function':\n\t\t\t\ttry {\n\t\t\t\t\tresult = toStringOrDefault(template.call({ name }), null);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot execute function template ?${name}: ${ex.message}`,\n\t\t\t\t\t\tw.source.slice(w.matchStart, w.nextMatch)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'string':\n\t\t\t\tresult = template;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (result === null) {\n\t\t\t\tjQuery(document.createTextNode(w.matchText)).appendTo(w.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnew Wikifier(\n\t\t\t\t\t(Config.debug\n\t\t\t\t\t\t? new DebugView(w.output, 'template', w.matchText, w.matchText) // Debug view setup.\n\t\t\t\t\t\t: w\n\t\t\t\t\t).output,\n\t\t\t\t\tresult\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'heading',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^!{1,6}',\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.subWikify(\n\t\t\t\tjQuery(document.createElement(`h${w.matchLength}`)).appendTo(w.output).get(0),\n\t\t\t\tthis.terminator\n\t\t\t);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname           : 'table',\n\t\tprofiles       : ['block'],\n\t\tmatch          : '^\\\\|(?:[^\\\\n]*)\\\\|(?:[fhck]?)$',\n\t\tlookahead      : /^\\|([^\\n]*)\\|([fhck]?)$/gm,\n\t\trowTerminator  : '\\\\|(?:[cfhk]?)$\\\\n?',\n\t\tcellPattern    : '(?:\\\\|([^\\\\n\\\\|]*)\\\\|)|(\\\\|[cfhk]?$\\\\n?)',\n\t\tcellTerminator : '(?:\\\\u0020*)\\\\|',\n\t\trowTypes       : { c : 'caption', f : 'tfoot', h : 'thead', '' : 'tbody' }, // eslint-disable-line id-length\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst table       = jQuery(document.createElement('table')).appendTo(w.output).get(0);\n\t\t\tconst prevColumns = [];\n\t\t\tlet curRowType    = null;\n\t\t\tlet $rowContainer = null;\n\t\t\tlet rowCount      = 0;\n\t\t\tlet matched;\n\n\t\t\tw.nextMatch = w.matchStart;\n\n\t\t\tdo {\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tconst nextRowType = match[2];\n\n\t\t\t\t\tif (nextRowType === 'k') {\n\t\t\t\t\t\ttable.className = match[1];\n\t\t\t\t\t\tw.nextMatch += match[0].length + 1;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (nextRowType !== curRowType) {\n\t\t\t\t\t\t\tcurRowType = nextRowType;\n\t\t\t\t\t\t\t$rowContainer = jQuery(document.createElement(this.rowTypes[nextRowType]))\n\t\t\t\t\t\t\t\t.appendTo(table);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (curRowType === 'c') {\n\t\t\t\t\t\t\t$rowContainer.css('caption-side', rowCount === 0 ? 'top' : 'bottom');\n\t\t\t\t\t\t\tw.nextMatch += 1;\n\t\t\t\t\t\t\tw.subWikify($rowContainer[0], this.rowTerminator);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tthis.rowHandler(\n\t\t\t\t\t\t\t\tw,\n\t\t\t\t\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t\t\t\t\t.appendTo($rowContainer)\n\t\t\t\t\t\t\t\t\t.get(0),\n\t\t\t\t\t\t\t\tprevColumns\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t++rowCount;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t},\n\n\t\trowHandler(w, rowEl, prevColumns) {\n\t\t\tconst cellRe = new RegExp(this.cellPattern, 'gm');\n\t\t\tlet col         = 0;\n\t\t\tlet curColCount = 1;\n\t\t\tlet matched;\n\n\t\t\tdo {\n\t\t\t\tcellRe.lastIndex = w.nextMatch;\n\n\t\t\t\tconst cellMatch = cellRe.exec(w.source);\n\n\t\t\t\tmatched = cellMatch && cellMatch.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tif (cellMatch[1] === '~') {\n\t\t\t\t\t\tconst last = prevColumns[col];\n\n\t\t\t\t\t\tif (last) {\n\t\t\t\t\t\t\t++last.rowCount;\n\t\t\t\t\t\t\tlast.$element\n\t\t\t\t\t\t\t\t.attr('rowspan', last.rowCount)\n\t\t\t\t\t\t\t\t.css('vertical-align', 'middle');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length - 1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (cellMatch[1] === '>') {\n\t\t\t\t\t\t++curColCount;\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length - 1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (cellMatch[2]) {\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t++w.nextMatch;\n\n\t\t\t\t\t\tconst css = Wikifier.helpers.inlineCss(w);\n\t\t\t\t\t\tlet spaceLeft  = false;\n\t\t\t\t\t\tlet spaceRight = false;\n\t\t\t\t\t\tlet $cell;\n\n\t\t\t\t\t\twhile (w.source.substr(w.nextMatch, 1) === ' ') {\n\t\t\t\t\t\t\tspaceLeft = true;\n\t\t\t\t\t\t\t++w.nextMatch;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (w.source.substr(w.nextMatch, 1) === '!') {\n\t\t\t\t\t\t\t$cell = jQuery(document.createElement('th')).appendTo(rowEl);\n\t\t\t\t\t\t\t++w.nextMatch;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t$cell = jQuery(document.createElement('td')).appendTo(rowEl);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tprevColumns[col] = {\n\t\t\t\t\t\t\trowCount : 1,\n\t\t\t\t\t\t\t$element : $cell\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (curColCount > 1) {\n\t\t\t\t\t\t\t$cell.attr('colspan', curColCount);\n\t\t\t\t\t\t\tcurColCount = 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tw.subWikify($cell[0], this.cellTerminator);\n\n\t\t\t\t\t\tif (w.matchText.substr(w.matchText.length - 2, 1) === ' ') {\n\t\t\t\t\t\t\tspaceRight = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcss.classes.forEach(className => $cell.addClass(className));\n\n\t\t\t\t\t\tif (css.id !== '') {\n\t\t\t\t\t\t\t$cell.attr('id', css.id);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (spaceLeft && spaceRight) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'center';\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (spaceLeft) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'right';\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (spaceRight) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'left';\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$cell.css(css.styles);\n\n\t\t\t\t\t\tw.nextMatch = w.nextMatch - 1;\n\t\t\t\t\t}\n\n\t\t\t\t\t++col;\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'list',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^(?:(?:\\\\*+)|(?:#+))',\n\t\tlookahead  : /^(?:(\\*+)|(#+))/gm,\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = w.matchStart;\n\n\t\t\tconst destStack = [w.output];\n\t\t\tlet curType  = null;\n\t\t\tlet curLevel = 0;\n\t\t\tlet matched;\n\t\t\tlet i;\n\n\t\t\tdo {\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tconst newType  = match[2] ? 'ol' : 'ul';\n\t\t\t\t\tconst newLevel = match[0].length;\n\n\t\t\t\t\tw.nextMatch += match[0].length;\n\n\t\t\t\t\tif (newLevel > curLevel) {\n\t\t\t\t\t\tfor (i = curLevel; i < newLevel; ++i) {\n\t\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\t\tjQuery(document.createElement(newType))\n\t\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (newLevel < curLevel) {\n\t\t\t\t\t\tfor (i = curLevel; i > newLevel; --i) {\n\t\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (newLevel === curLevel && newType !== curType) {\n\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\tjQuery(document.createElement(newType))\n\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tcurLevel = newLevel;\n\t\t\t\t\tcurType = newType;\n\t\t\t\t\tw.subWikify(\n\t\t\t\t\t\tjQuery(document.createElement('li'))\n\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t.get(0),\n\t\t\t\t\t\tthis.terminator\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'commentByBlock',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '(?:/(?:%|\\\\*))|(?:<!--)',\n\t\tlookahead : /(?:\\/(%|\\*)(?:(?:.|\\n)*?)\\1\\/)|(?:<!--(?:(?:.|\\n)*?)-->)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'lineContinuation',\n\t\tprofiles : ['core'],\n\n\t\t// WARNING: The ordering here is important: end-of-line, start-of-line, end-of-string, start-of-string.\n\t\tmatch : `\\\\\\\\${Patterns.spaceNoTerminator}*\\\\n|\\\\n${Patterns.spaceNoTerminator}*\\\\\\\\|\\\\n?\\\\\\\\${Patterns.spaceNoTerminator}*$|^${Patterns.spaceNoTerminator}*\\\\\\\\\\\\n?`,\n\n\t\thandler(w) {\n\t\t\tw.nextMatch = w.matchStart + w.matchLength;\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'lineBreak',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\n|<[Bb][Rr]\\\\s*/?>',\n\n\t\thandler(w) {\n\t\t\tif (!w.options.nobr) {\n\t\t\t\tjQuery(document.createElement('br')).appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'htmlCharacterReference',\n\t\tprofiles : ['core'],\n\t\tmatch    : '(?:(?:&#?[0-9A-Za-z]{2,8};|.)(?:&#?(?:x0*(?:3[0-6][0-9A-Fa-f]|1D[C-Fc-f][0-9A-Fa-f]|20[D-Fd-f][0-9A-Fa-f]|FE2[0-9A-Fa-f])|0*(?:76[89]|7[7-9][0-9]|8[0-7][0-9]|761[6-9]|76[2-7][0-9]|84[0-3][0-9]|844[0-7]|6505[6-9]|6506[0-9]|6507[0-1]));)+|&#?[0-9A-Za-z]{2,8};)',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t.append(w.matchText)\n\t\t\t\t.appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'xmlProlog',\n\t\tprofiles : ['core'],\n\t\tmatch    : '<\\\\?[Xx][Mm][Ll][^>]*\\\\?>',\n\n\t\thandler(w) {\n\t\t\tw.nextMatch = w.matchStart + w.matchLength;\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimHtml',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Hh][Tt][Mm][Ll]>',\n\t\tlookahead : /<[Hh][Tt][Mm][Ll]>((?:.|\\n)*?)<\\/[Hh][Tt][Mm][Ll]>/gm,\n\t\thandler   : _verbatimTagHandler\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimScriptTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Ss][Cc][Rr][Ii][Pp][Tt][^>]*>',\n\t\tlookahead : /(<[Ss][Cc][Rr][Ii][Pp][Tt]*>(?:.|\\n)*?<\\/[Ss][Cc][Rr][Ii][Pp][Tt]>)/gm,\n\t\thandler   : _verbatimTagHandler\n\t});\n\n\tWikifier.Parser.add({\n\t\tname           : 'styleTag',\n\t\tprofiles       : ['core'],\n\t\tmatch          : '<[Ss][Tt][Yy][Ll][Ee][^>]*>',\n\t\tlookahead      : /(<[Ss][Tt][Yy][Ll][Ee]*>)((?:.|\\n)*?)(<\\/[Ss][Tt][Yy][Ll][Ee]>)/gm,\n\t\timageMarkup    : new RegExp(Patterns.cssImage, 'g'),\n\t\thasImageMarkup : new RegExp(Patterns.cssImage),\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tlet css = match[2];\n\n\t\t\t\t// Check for wiki image transclusion.\n\t\t\t\tif (this.hasImageMarkup.test(css)) {\n\t\t\t\t\tthis.imageMarkup.lastIndex = 0;\n\n\t\t\t\t\tcss = css.replace(this.imageMarkup, wikiImage => {\n\t\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\t\tsource     : wikiImage,\n\t\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (markup.hasOwnProperty('error') || markup.pos < wikiImage.length) {\n\t\t\t\t\t\t\treturn wikiImage;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet source = markup.source;\n\n\t\t\t\t\t\t// Handle image passage transclusion.\n\t\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t\tsource = passage.text;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tThe source may be URI- or Base64-encoded, so we cannot use `encodeURIComponent()`\n\t\t\t\t\t\t\there.  Instead, we simply encode any double quotes, since the URI will be\n\t\t\t\t\t\t\tdelimited by them.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\treturn `url(\"${source.replace(/\"/g, '%22')}\")`;\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t\t.append(match[1] + css + match[3])\n\t\t\t\t\t.appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'svgTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Ss][Vv][Gg][^>]*>',\n\t\tlookahead : /(<[Ss][Vv][Gg][^>]*>(?:.|\\n)*?<\\/[Ss][Vv][Gg]>)/gm,\n\t\tnamespace : 'http://www.w3.org/2000/svg',\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tconst $frag = jQuery(document.createDocumentFragment()).append(match[1]);\n\n\t\t\t\t// Postprocess the relevant SVG element nodes.\n\t\t\t\t$frag.find('a[data-passage],image[data-passage]').each((_, el) => {\n\t\t\t\t\tconst tagName = el.tagName.toLowerCase();\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.processAttributeDirectives(el);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`svg|<${tagName}>: ${ex.message}`,\n\t\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (el.hasAttribute('data-passage')) {\n\t\t\t\t\t\tthis.processDataAttributes(el, tagName);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\t$frag.appendTo(w.output);\n\t\t\t}\n\t\t},\n\n\t\tprocessAttributeDirectives(el) {\n\t\t\t// NOTE: The `.attributes` property yields a live collection, so we\n\t\t\t// must make a non-live copy of it as we will be adding and removing\n\t\t\t// members of said collection if any directives are found.\n\t\t\t[...el.attributes].forEach(({ name, value }) => {\n\t\t\t\tconst evalShorthand = name[0] === '@';\n\n\t\t\t\tif (evalShorthand || name.startsWith('sc-eval:')) {\n\t\t\t\t\tconst newName = name.slice(evalShorthand ? 1 : 8); // Remove eval directive prefix.\n\n\t\t\t\t\tif (newName === 'data-setter') {\n\t\t\t\t\t\tthrow new Error(`evaluation directive is not allowed on the data-setter attribute: \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\t// Evaluate the value as TwineScript.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = Scripting.evalTwineScript(value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`bad evaluation from attribute directive \"${name}\": ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Assign the result to the new attribute and remove the old one.\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: Most browsers (ca. Nov 2017) have broken `setAttribute()`\n\t\t\t\t\t\t\tmethod implementations that throw on attribute names that start\n\t\t\t\t\t\t\twith, or contain, various symbols that are completely valid per\n\t\t\t\t\t\t\tthe specification.  Thus this code could fail if the user chooses\n\t\t\t\t\t\t\tattribute names that, after removing the directive prefix, are\n\t\t\t\t\t\t\tunpalatable to `setAttribute()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tel.setAttribute(newName, result);\n\t\t\t\t\t\tel.removeAttribute(name);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`cannot transform attribute directive \"${name}\" into attribute \"${newName}\"`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tprocessDataAttributes(el, tagName) {\n\t\t\tlet passage = el.getAttribute('data-passage');\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst evaluated = Wikifier.helpers.evalPassageId(passage);\n\n\t\t\tif (evaluated !== passage) {\n\t\t\t\tpassage = evaluated;\n\t\t\t\tel.setAttribute('data-passage', evaluated);\n\t\t\t}\n\n\t\t\tif (passage !== '') {\n\t\t\t\t// '<image>' element, so attempt media passage transclusion.\n\t\t\t\tif (tagName === 'image') {\n\t\t\t\t\tif (passage.slice(0, 5) !== 'data:' && Story.has(passage)) {\n\t\t\t\t\t\tpassage = Story.get(passage);\n\n\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t// NOTE: SVG `.href` IDL attribute is read-only,\n\t\t\t\t\t\t\t// so set its `href` content attribute instead.\n\t\t\t\t\t\t\tel.setAttribute('href', passage.text.trim());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Elsewise, assume a link element of some type—e.g., '<a>'.\n\t\t\t\telse {\n\t\t\t\t\tlet setter = el.getAttribute('data-setter');\n\t\t\t\t\tlet setFn;\n\n\t\t\t\t\tif (setter != null) { // lazy equality for null\n\t\t\t\t\t\tsetter = String(setter).trim();\n\n\t\t\t\t\t\tif (setter !== '') {\n\t\t\t\t\t\t\tsetFn = Wikifier.helpers.createShadowSetterCallback(Scripting.parse(setter));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tel.classList.add('link-internal');\n\n\t\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t\tel.classList.add('link-visited');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tel.classList.add('link-broken');\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery(el).ariaClick({ one : true }, function () {\n\t\t\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\t\t\tsetFn.call(this);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\t/*\n\t\t\tNOTE: This parser MUST come after any parser which handles HTML tag-\n\t\t\tlike constructs—e.g. 'verbatimText', 'horizontalRule', 'lineBreak',\n\t\t\t'xmlProlog', 'verbatimHtml', 'verbatimSvgTag', 'verbatimScriptTag',\n\t\t\tand 'styleTag'.\n\t\t*/\n\t\tname      : 'htmlTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<\\\\w+(?:\\\\s+[^\\\\u0000-\\\\u001F\\\\u007F-\\\\u009F\\\\s\"\\'>\\\\/=]+(?:\\\\s*=\\\\s*(?:\"[^\"]*?\"|\\'[^\\']*?\\'|[^\\\\s\"\\'=<>`]+))?)*\\\\s*\\\\/?>',\n\t\ttagRe     : /^<(\\w+)/,\n\t\tmediaTags : ['audio', 'img', 'source', 'track', 'video'], // NOTE: The `<picture>` element should not be in this list.\n\t\tnobrTags  : ['audio', 'colgroup', 'datalist', 'dl', 'figure', 'meter', 'ol', 'optgroup', 'picture', 'progress', 'ruby', 'select', 'table', 'tbody', 'tfoot', 'thead', 'tr', 'ul', 'video'],\n\t\tvoidTags  : ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'],\n\n\t\thandler(w) {\n\t\t\tconst tagMatch = this.tagRe.exec(w.matchText);\n\t\t\tconst tag      = tagMatch && tagMatch[1];\n\t\t\tconst tagName  = tag && tag.toLowerCase();\n\n\t\t\tif (tagName) {\n\t\t\t\tconst isVoid = this.voidTags.includes(tagName) || w.matchText.endsWith('/>');\n\t\t\t\tconst isNobr = this.nobrTags.includes(tagName);\n\t\t\t\tlet terminator;\n\t\t\t\tlet terminatorMatch;\n\n\t\t\t\tif (!isVoid) {\n\t\t\t\t\tterminator = `<\\\\/${tagName}\\\\s*>`;\n\n\t\t\t\t\tconst terminatorRe = new RegExp(terminator, 'gim'); // ignore case during match\n\n\t\t\t\t\tterminatorRe.lastIndex = w.matchStart;\n\t\t\t\t\tterminatorMatch = terminatorRe.exec(w.source);\n\t\t\t\t}\n\n\t\t\t\tif (isVoid || terminatorMatch) {\n\t\t\t\t\tlet output    = w.output;\n\t\t\t\t\tlet el        = document.createElement(w.output.tagName);\n\t\t\t\t\tlet debugView;\n\n\t\t\t\t\tel.innerHTML = w.matchText;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tNOTE: The use of a `while` statement here is curious, however,\n\t\t\t\t\t\tI'm hesitant to change it for fear of breaking some edge case.\n\t\t\t\t\t*/\n\t\t\t\t\twhile (el.firstChild) {\n\t\t\t\t\t\tel = el.firstChild;\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.processAttributeDirectives(el);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`<${tagName}>: ${ex.message}`,\n\t\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (el.hasAttribute('data-passage')) {\n\t\t\t\t\t\tthis.processDataAttributes(el, tagName);\n\n\t\t\t\t\t\t// Debug view setup.\n\t\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t`html-${tagName}`,\n\t\t\t\t\t\t\t\ttagName,\n\t\t\t\t\t\t\t\tw.matchText\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tdebugView.modes({\n\t\t\t\t\t\t\t\tblock   : tagName === 'img',\n\t\t\t\t\t\t\t\tnonvoid : terminatorMatch\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\toutput = debugView.output;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (terminatorMatch) {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists\n\t\t\t\t\t\t\tsolely to ensure that the options stack is properly restored in\n\t\t\t\t\t\t\tthe event that an uncaught exception is thrown during the call to\n\t\t\t\t\t\t\t`subWikify()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tWikifier.Option.push({ nobr : isNobr });\n\t\t\t\t\t\t\tw.subWikify(el, terminator, { ignoreTerminatorCase : true });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\tWikifier.Option.pop();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tDebug view modification.  If the current element has any debug\n\t\t\t\t\t\t\tview descendants who have \"block\" mode set, then set its debug\n\t\t\t\t\t\t\tview to the same.  It just makes things look a bit nicer.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tif (debugView && jQuery(el).find('.debug.block').length > 0) {\n\t\t\t\t\t\t\tdebugView.modes({ block : true });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tNOTE: The use of `cloneNode(true)` here for `<track>` elements\n\t\t\t\t\t\tis necessary to workaround a poorly understood rehoming issue.\n\t\t\t\t\t*/\n\t\t\t\t\toutput.appendChild(tagName === 'track' ? el.cloneNode(true) : el);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot find a closing tag for HTML <${tag}>`,\n\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tprocessAttributeDirectives(el) {\n\t\t\t// NOTE: The `.attributes` property yields a live collection, so we\n\t\t\t// must make a non-live copy of it as we will be adding and removing\n\t\t\t// members of said collection if any directives are found.\n\t\t\t[...el.attributes].forEach(({ name, value }) => {\n\t\t\t\tconst evalShorthand = name[0] === '@';\n\n\t\t\t\tif (evalShorthand || name.startsWith('sc-eval:')) {\n\t\t\t\t\tconst newName = name.slice(evalShorthand ? 1 : 8); // Remove eval directive prefix.\n\n\t\t\t\t\tif (newName === 'data-setter') {\n\t\t\t\t\t\tthrow new Error(`evaluation directive is not allowed on the data-setter attribute: \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\t// Evaluate the value as TwineScript.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = Scripting.evalTwineScript(value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`bad evaluation from attribute directive \"${name}\": ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Assign the result to the new attribute and remove the old one.\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: Most browsers (ca. Nov 2017) have broken `setAttribute()`\n\t\t\t\t\t\t\tmethod implementations that throw on attribute names that start\n\t\t\t\t\t\t\twith, or contain, various symbols that are completely valid per\n\t\t\t\t\t\t\tthe specification.  Thus this code could fail if the user chooses\n\t\t\t\t\t\t\tattribute names that, after removing the directive prefix, are\n\t\t\t\t\t\t\tunpalatable to `setAttribute()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tel.setAttribute(newName, result);\n\t\t\t\t\t\tel.removeAttribute(name);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`cannot transform attribute directive \"${name}\" into attribute \"${newName}\"`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tprocessDataAttributes(el, tagName) {\n\t\t\tlet passage = el.getAttribute('data-passage');\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst evaluated = Wikifier.helpers.evalPassageId(passage);\n\n\t\t\tif (evaluated !== passage) {\n\t\t\t\tpassage = evaluated;\n\t\t\t\tel.setAttribute('data-passage', evaluated);\n\t\t\t}\n\n\t\t\tif (passage !== '') {\n\t\t\t\t// Media element, so attempt media passage transclusion.\n\t\t\t\tif (this.mediaTags.includes(tagName)) {\n\t\t\t\t\tif (passage.slice(0, 5) !== 'data:' && Story.has(passage)) {\n\t\t\t\t\t\tpassage = Story.get(passage);\n\n\t\t\t\t\t\tlet parentName;\n\t\t\t\t\t\tlet twineTag;\n\n\t\t\t\t\t\tswitch (tagName) {\n\t\t\t\t\t\tcase 'audio':\n\t\t\t\t\t\tcase 'video':\n\t\t\t\t\t\t\ttwineTag = `Twine.${tagName}`;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'img':\n\t\t\t\t\t\t\ttwineTag = 'Twine.image';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'track':\n\t\t\t\t\t\t\ttwineTag = 'Twine.vtt';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'source':\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst $parent = $(el).closest('audio,picture,video');\n\n\t\t\t\t\t\t\t\tif ($parent.length) {\n\t\t\t\t\t\t\t\t\tparentName = $parent.get(0).tagName.toLowerCase();\n\t\t\t\t\t\t\t\t\ttwineTag = `Twine.${parentName === 'picture' ? 'image' : parentName}`;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (passage.tags.includes(twineTag)) {\n\t\t\t\t\t\t\tel[parentName === 'picture' ? 'srcset' : 'src'] = passage.text.trim();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Elsewise, assume a link element of some type—e.g., '<a>', '<area>', '<button>', etc.\n\t\t\t\telse {\n\t\t\t\t\tlet setter = el.getAttribute('data-setter');\n\t\t\t\t\tlet setFn;\n\n\t\t\t\t\tif (setter != null) { // lazy equality for null\n\t\t\t\t\t\tsetter = String(setter).trim();\n\n\t\t\t\t\t\tif (setter !== '') {\n\t\t\t\t\t\t\tsetFn = Wikifier.helpers.createShadowSetterCallback(Scripting.parse(setter));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tel.classList.add('link-internal');\n\n\t\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t\tel.classList.add('link-visited');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tel.classList.add('link-broken');\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery(el).ariaClick({ one : true }, function () {\n\t\t\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\t\t\tsetFn.call(this);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/template.js\n\n\tCopyright © 2019–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns */\n\nvar Template = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Template definitions.\n\tconst _templates = new Map();\n\n\t// Valid template name regular expression.\n\tconst _validNameRe = new RegExp(`^(?:${Patterns.templateName})$`);\n\n\t// Valid template type predicate.\n\tconst _validType = template => {\n\t\tconst templateType = typeof template;\n\t\treturn templateType === 'function' || templateType === 'string';\n\t};\n\n\n\t/*******************************************************************************\n\t\tTemplate Functions.\n\t*******************************************************************************/\n\n\tfunction templateAdd(name, template) {\n\t\tif (\n\t\t\t   !_validType(template)\n\t\t\t&& !(template instanceof Array && template.length > 0 && template.every(_validType))\n\t\t) {\n\t\t\tthrow new TypeError(`invalid template type (${name}); templates must be: functions, strings, or an array of either`);\n\t\t}\n\n\t\t(name instanceof Array ? name : [name]).forEach(name => {\n\t\t\tif (!_validNameRe.test(name)) {\n\t\t\t\tthrow new Error(`invalid template name \"${name}\"`);\n\t\t\t}\n\t\t\tif (_templates.has(name)) {\n\t\t\t\tthrow new Error(`cannot clobber existing template ?${name}`);\n\t\t\t}\n\n\t\t\t_templates.set(name, template);\n\t\t});\n\t}\n\n\tfunction templateDelete(name) {\n\t\t(name instanceof Array ? name : [name]).forEach(name => _templates.delete(name));\n\t}\n\n\tfunction templateGet(name) {\n\t\treturn _templates.has(name) ? _templates.get(name) : null;\n\t}\n\n\tfunction templateHas(name) {\n\t\treturn _templates.has(name);\n\t}\n\n\tfunction templateSize() {\n\t\treturn _templates.size;\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tadd    : { value : templateAdd },\n\t\tdelete : { value : templateDelete },\n\t\tget    : { value : templateGet },\n\t\thas    : { value : templateHas },\n\t\tsize   : { get : templateSize }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macro.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns, Scripting, clone, macros */\n\nvar Macro = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Macro definitions.\n\tconst _macros = {};\n\n\t// Map of all macro tags and their parents (key: 'tag name' => value: ['list of parent names']).\n\tconst _tags = {};\n\n\t// Valid macro name regular expression.\n\tconst _validNameRe = new RegExp(`^(?:${Patterns.macroName})$`);\n\n\n\t/*******************************************************************************************************************\n\t\tMacros Functions.\n\t*******************************************************************************************************************/\n\tfunction macrosAdd(name, def, deep) {\n\t\tif (Array.isArray(name)) {\n\t\t\tname.forEach(name => macrosAdd(name, def, deep));\n\t\t\treturn;\n\t\t}\n\n\t\tif (!_validNameRe.test(name)) {\n\t\t\tthrow new Error(`invalid macro name \"${name}\"`);\n\t\t}\n\n\t\tif (macrosHas(name)) {\n\t\t\tthrow new Error(`cannot clobber existing macro <<${name}>>`);\n\t\t}\n\t\telse if (tagsHas(name)) {\n\t\t\tthrow new Error(`cannot clobber child tag <<${name}>> of parent macro${_tags[name].length === 1 ? '' : 's'} <<${_tags[name].join('>>, <<')}>>`);\n\t\t}\n\n\t\ttry {\n\t\t\tif (typeof def === 'object') {\n\t\t\t\t// Add the macro definition.\n\t\t\t\t_macros[name] = deep ? clone(def) : def;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Add the macro alias.\n\t\t\t\tif (macrosHas(def)) {\n\t\t\t\t\t_macros[name] = deep ? clone(_macros[def]) : _macros[def];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new Error(`cannot create alias of nonexistent macro <<${def}>>`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tObject.defineProperty(_macros, name, { writable : false });\n\n\t\t\t/* legacy */\n\t\t\t/*\n\t\t\t\tSince `macrosGet()` may return legacy macros, we have to add a flag to (modern)\n\t\t\t\tAPI macros, so that the macro formatter will know how to call the macro.\n\t\t\t*/\n\t\t\t_macros[name]._MACRO_API = true;\n\t\t\t/* /legacy */\n\t\t}\n\t\tcatch (ex) {\n\t\t\tif (ex.name === 'TypeError') {\n\t\t\t\tthrow new Error(`cannot clobber protected macro <<${name}>>`);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error(`unknown error when attempting to add macro <<${name}>>: [${ex.name}] ${ex.message}`);\n\t\t\t}\n\t\t}\n\n\t\t// Tags post-processing.\n\t\tif (_macros[name].hasOwnProperty('tags')) {\n\t\t\tif (_macros[name].tags == null) { // lazy equality for null\n\t\t\t\ttagsRegister(name);\n\t\t\t}\n\t\t\telse if (Array.isArray(_macros[name].tags)) {\n\t\t\t\ttagsRegister(name, _macros[name].tags);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error(`bad value for \"tags\" property of macro <<${name}>>`);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction macrosDelete(name) {\n\t\tif (Array.isArray(name)) {\n\t\t\tname.forEach(name => macrosDelete(name));\n\t\t\treturn;\n\t\t}\n\n\t\tif (macrosHas(name)) {\n\t\t\t// Tags pre-processing.\n\t\t\tif (_macros[name].hasOwnProperty('tags')) {\n\t\t\t\ttagsUnregister(name);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t// Remove the macro definition.\n\t\t\t\tObject.defineProperty(_macros, name, { writable : true });\n\t\t\t\tdelete _macros[name];\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tthrow new Error(`unknown error removing macro <<${name}>>: ${ex.message}`);\n\t\t\t}\n\t\t}\n\t\telse if (tagsHas(name)) {\n\t\t\tthrow new Error(`cannot remove child tag <<${name}>> of parent macro <<${_tags[name]}>>`);\n\t\t}\n\t}\n\n\tfunction macrosIsEmpty() {\n\t\treturn Object.keys(_macros).length === 0;\n\t}\n\n\tfunction macrosHas(name) {\n\t\treturn _macros.hasOwnProperty(name);\n\t}\n\n\tfunction macrosGet(name) {\n\t\tlet macro = null;\n\n\t\tif (macrosHas(name) && typeof _macros[name].handler === 'function') {\n\t\t\tmacro = _macros[name];\n\t\t}\n\t\t/* legacy macro support */\n\t\telse if (macros.hasOwnProperty(name) && typeof macros[name].handler === 'function') {\n\t\t\tmacro = macros[name];\n\t\t}\n\t\t/* /legacy macro support */\n\n\t\treturn macro;\n\t}\n\n\tfunction macrosInit(handler = 'init') { // eslint-disable-line no-unused-vars\n\t\tObject.keys(_macros).forEach(name => {\n\t\t\tif (typeof _macros[name][handler] === 'function') {\n\t\t\t\t_macros[name][handler](name);\n\t\t\t}\n\t\t});\n\n\t\t/* legacy macro support */\n\t\tObject.keys(macros).forEach(name => {\n\t\t\tif (typeof macros[name][handler] === 'function') {\n\t\t\t\tmacros[name][handler](name);\n\t\t\t}\n\t\t});\n\t\t/* /legacy macro support */\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTags Functions.\n\t*******************************************************************************************************************/\n\tfunction tagsRegister(parent, bodyTags) {\n\t\tif (!parent) {\n\t\t\tthrow new Error('no parent specified');\n\t\t}\n\n\t\tconst endTags = [`/${parent}`, `end${parent}`]; // automatically create the closing tags\n\t\tconst allTags = [].concat(endTags, Array.isArray(bodyTags) ? bodyTags : []);\n\n\t\tfor (let i = 0; i < allTags.length; ++i) {\n\t\t\tconst tag = allTags[i];\n\n\t\t\tif (macrosHas(tag)) {\n\t\t\t\tthrow new Error('cannot register tag for an existing macro');\n\t\t\t}\n\n\t\t\tif (tagsHas(tag)) {\n\t\t\t\tif (!_tags[tag].includes(parent)) {\n\t\t\t\t\t_tags[tag].push(parent);\n\t\t\t\t\t_tags[tag].sort();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_tags[tag] = [parent];\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction tagsUnregister(parent) {\n\t\tif (!parent) {\n\t\t\tthrow new Error('no parent specified');\n\t\t}\n\n\t\tObject.keys(_tags).forEach(tag => {\n\t\t\tconst i = _tags[tag].indexOf(parent);\n\n\t\t\tif (i !== -1) {\n\t\t\t\tif (_tags[tag].length === 1) {\n\t\t\t\t\tdelete _tags[tag];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_tags[tag].splice(i, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction tagsHas(name) {\n\t\treturn _tags.hasOwnProperty(name);\n\t}\n\n\tfunction tagsGet(name) {\n\t\treturn tagsHas(name) ? _tags[name] : null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tMacro Functions.\n\t\t*/\n\t\tadd     : { value : macrosAdd },\n\t\tdelete  : { value : macrosDelete },\n\t\tisEmpty : { value : macrosIsEmpty },\n\t\thas     : { value : macrosHas },\n\t\tget     : { value : macrosGet },\n\t\tinit    : { value : macrosInit },\n\n\t\t/*\n\t\t\tTags Functions.\n\t\t*/\n\t\ttags : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tregister   : { value : tagsRegister },\n\t\t\t\tunregister : { value : tagsUnregister },\n\t\t\t\thas        : { value : tagsHas },\n\t\t\t\tget        : { value : tagsGet }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tevalStatements : { value : (...args) => Scripting.evalJavaScript(...args) } // SEE: `markup/scripting.js`.\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macrocontext.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, DebugView, Patterns, State, Wikifier, throwError */\n\nvar MacroContext = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tMacroContext Class.\n\t*******************************************************************************************************************/\n\tclass MacroContext {\n\t\tconstructor(contextData) {\n\t\t\tconst context = Object.assign({\n\t\t\t\tparent  : null,\n\t\t\t\tmacro   : null,\n\t\t\t\tname    : '',\n\t\t\t\targs    : null,\n\t\t\t\tpayload : null,\n\t\t\t\tparser  : null,\n\t\t\t\tsource  : ''\n\t\t\t}, contextData);\n\n\t\t\tif (context.macro === null || context.name === '' || context.parser === null) {\n\t\t\t\tthrow new TypeError('context object missing required properties');\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tself : {\n\t\t\t\t\tvalue : context.macro\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : context.name\n\t\t\t\t},\n\n\t\t\t\targs : {\n\t\t\t\t\tvalue : context.args\n\t\t\t\t},\n\n\t\t\t\tpayload : {\n\t\t\t\t\tvalue : context.payload\n\t\t\t\t},\n\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : context.source\n\t\t\t\t},\n\n\t\t\t\tparent : {\n\t\t\t\t\tvalue : context.parent\n\t\t\t\t},\n\n\t\t\t\tparser : {\n\t\t\t\t\tvalue : context.parser\n\t\t\t\t},\n\n\t\t\t\t_output : {\n\t\t\t\t\tvalue : context.parser.output\n\t\t\t\t},\n\n\t\t\t\t_shadows : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_debugView : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_debugViewEnabled : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : Config.debug\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tget output() {\n\t\t\treturn this._debugViewEnabled ? this.debugView.output : this._output;\n\t\t}\n\n\t\tget shadows() {\n\t\t\treturn [...this._shadows];\n\t\t}\n\n\t\tget shadowView() {\n\t\t\tconst view = new Set();\n\t\t\tthis.contextSelectAll(ctx => ctx._shadows)\n\t\t\t\t.forEach(ctx => ctx._shadows.forEach(name => view.add(name)));\n\t\t\treturn [...view];\n\t\t}\n\n\t\tget debugView() {\n\t\t\tif (this._debugViewEnabled) {\n\t\t\t\treturn this._debugView !== null ? this._debugView : this.createDebugView();\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tcontextHas(filter) {\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tcontextSelect(filter) {\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\treturn context;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tcontextSelectAll(filter) {\n\t\t\tconst result = [];\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\tresult.push(context);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\taddShadow(...names) {\n\t\t\tif (!this._shadows) {\n\t\t\t\tthis._shadows = new Set();\n\t\t\t}\n\n\t\t\tconst varRe = new RegExp(`^${Patterns.variable}$`);\n\n\t\t\tnames\n\t\t\t\t.flat(Infinity)\n\t\t\t\t.forEach(name => {\n\t\t\t\t\tif (typeof name !== 'string') {\n\t\t\t\t\t\tthrow new TypeError(`variable name must be a string; type: ${typeof name}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!varRe.test(name)) {\n\t\t\t\t\t\tthrow new Error(`invalid variable name \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._shadows.add(name);\n\t\t\t\t});\n\t\t}\n\n\t\tcreateShadowWrapper(callback, doneCallback, startCallback) {\n\t\t\tconst shadowContext = this;\n\t\t\tlet shadowStore;\n\n\t\t\tif (typeof callback === 'function') {\n\t\t\t\tshadowStore = {};\n\t\t\t\tthis.shadowView.forEach(varName => {\n\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\t\t\tshadowStore[varName] = store[varKey];\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn function (...args) {\n\t\t\t\tif (typeof startCallback === 'function') {\n\t\t\t\t\tstartCallback.apply(this, args);\n\t\t\t\t}\n\n\t\t\t\tif (typeof callback === 'function') {\n\t\t\t\t\tconst shadowNames = Object.keys(shadowStore);\n\t\t\t\t\tconst valueCache  = shadowNames.length > 0 ? {} : null;\n\t\t\t\t\tconst macroParser = Wikifier.Parser.get('macro');\n\t\t\t\t\tlet contextCache;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t\tcallback.\n\t\t\t\t\t*/\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tCache the existing values of the variables to be shadowed and assign the\n\t\t\t\t\t\t\tshadow values.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tstore[varKey] = shadowStore[varName];\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Cache the existing macro execution context and assign the shadow context.\n\t\t\t\t\t\tcontextCache = macroParser.context;\n\t\t\t\t\t\tmacroParser.context = shadowContext;\n\n\t\t\t\t\t\t// Call the callback function.\n\t\t\t\t\t\tcallback.apply(this, args);\n\t\t\t\t\t}\n\t\t\t\t\tfinally {\n\t\t\t\t\t\t// Revert the macro execution context shadowing.\n\t\t\t\t\t\tif (contextCache !== undefined) {\n\t\t\t\t\t\t\tmacroParser.context = contextCache;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Revert the variable shadowing.\n\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tUpdate the shadow store with the variable's current value, in case it\n\t\t\t\t\t\t\t\twas modified during the callback.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\n\t\t\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (typeof doneCallback === 'function') {\n\t\t\t\t\tdoneCallback.apply(this, args);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tcreateDebugView(name, title) {\n\t\t\tthis._debugView = new DebugView(\n\t\t\t\tthis._output,\n\t\t\t\t'macro',\n\t\t\t\tname ? name : this.name,\n\t\t\t\ttitle ? title : this.source\n\t\t\t);\n\n\t\t\tif (this.payload !== null && this.payload.length > 0) {\n\t\t\t\tthis._debugView.modes({ nonvoid : true });\n\t\t\t}\n\n\t\t\tthis._debugViewEnabled = true;\n\t\t\treturn this._debugView;\n\t\t}\n\n\t\tremoveDebugView() {\n\t\t\tif (this._debugView !== null) {\n\t\t\t\tthis._debugView.remove();\n\t\t\t\tthis._debugView = null;\n\t\t\t}\n\n\t\t\tthis._debugViewEnabled = false;\n\t\t}\n\n\t\terror(message, source, stack) {\n\t\t\treturn throwError(this._output, `<<${this.name}>>: ${message}`, source ? source : this.source, stack);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn MacroContext;\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macrolib.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, DebugView, Engine, Has, L10n, Macro, Patterns, Scripting, SimpleAudio, State, Story,\n\t       TempState, Util, Wikifier, postdisplay, prehistory, storage, toStringOrDefault\n*/\n\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tVariables Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<capture>>\n\t*/\n\tMacro.add('capture', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tif (this.args.raw.length === 0) {\n\t\t\t\treturn this.error('no story/temporary variable list specified');\n\t\t\t}\n\n\t\t\tconst valueCache = {};\n\n\t\t\t/*\n\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t`Wikifier` call.\n\t\t\t*/\n\t\t\ttry {\n\t\t\t\tconst varRe = new RegExp(`(${Patterns.variable})`,'g');\n\t\t\t\tlet match;\n\n\t\t\t\t/*\n\t\t\t\t\tCache the existing values of the variables and add a shadow.\n\t\t\t\t*/\n\t\t\t\twhile ((match = varRe.exec(this.args.raw)) !== null) {\n\t\t\t\t\tconst varName = match[1];\n\t\t\t\t\tconst varKey  = varName.slice(1);\n\t\t\t\t\tconst store   = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.addShadow(varName);\n\t\t\t\t}\n\n\t\t\t\tnew Wikifier(this.output, this.payload[0].contents);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\t// Revert the variable shadowing.\n\t\t\t\tthis.shadows.forEach(varName => {\n\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<set>>\n\t*/\n\tMacro.add('set', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<unset>>\n\t*/\n\tMacro.add('unset', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no story/temporary variable list specified');\n\t\t\t}\n\n\t\t\tconst re = new RegExp(\n\t\t\t\t`State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})`,\n\t\t\t\t'g'\n\t\t\t);\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst store = State[match[1]];\n\t\t\t\tconst name  = match[2];\n\n\t\t\t\tif (store.hasOwnProperty(name)) {\n\t\t\t\t\tdelete store[name];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<remember>>\n\t*/\n\tMacro.add('remember', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\tconst remember = storage.get('remember') || {};\n\t\t\tconst re       = new RegExp(`State\\\\.variables\\\\.(${Patterns.identifier})`, 'g');\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst name = match[1];\n\t\t\t\tremember[name] = State.variables[name];\n\t\t\t}\n\n\t\t\tif (!storage.set('remember', remember)) {\n\t\t\t\treturn this.error(`unknown error, cannot remember: ${this.args.raw}`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t},\n\n\t\tinit() {\n\t\t\tconst remember = storage.get('remember');\n\n\t\t\tif (remember) {\n\t\t\t\tObject.keys(remember).forEach(name => State.variables[name] = remember[name]);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<forget>>\n\t*/\n\tMacro.add('forget', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no story variable list specified');\n\t\t\t}\n\n\t\t\tconst remember = storage.get('remember');\n\t\t\tconst re       = new RegExp(`State\\\\.variables\\\\.(${Patterns.identifier})`, 'g');\n\t\t\tlet match;\n\t\t\tlet needStore = false;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst name = match[1];\n\n\t\t\t\tif (State.variables.hasOwnProperty(name)) {\n\t\t\t\t\tdelete State.variables[name];\n\t\t\t\t}\n\n\t\t\t\tif (remember && remember.hasOwnProperty(name)) {\n\t\t\t\t\tneedStore = true;\n\t\t\t\t\tdelete remember[name];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (needStore) {\n\t\t\t\tif (Object.keys(remember).length === 0) {\n\t\t\t\t\tif (!storage.delete('remember')) {\n\t\t\t\t\t\treturn this.error('unknown error, cannot update remember store');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (!storage.set('remember', remember)) {\n\t\t\t\t\treturn this.error('unknown error, cannot update remember store');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tScripting Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<run>>\n\t*/\n\tMacro.add('run', 'set'); // add <<run>> as an alias of <<set>>\n\n\t/*\n\t\t<<script>>\n\t*/\n\tMacro.add('script', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tconst output = document.createDocumentFragment();\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.payload[0].contents, output);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.createDebugView();\n\t\t\t}\n\n\t\t\tif (output.hasChildNodes()) {\n\t\t\t\tthis.output.appendChild(output);\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tDisplay Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<include>>\n\t*/\n\tMacro.add('include', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = this.args[0].link;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the passage name.\n\t\t\t\tpassage = this.args[0];\n\t\t\t}\n\n\t\t\tif (!Story.has(passage)) {\n\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tpassage = Story.get(passage);\n\t\t\tlet $el;\n\n\t\t\tif (this.args[1]) {\n\t\t\t\t$el = jQuery(document.createElement(this.args[1]))\n\t\t\t\t\t.addClass(`${passage.domId} macro-${this.name}`)\n\t\t\t\t\t.attr('data-passage', passage.title)\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$el = jQuery(this.output);\n\t\t\t}\n\n\t\t\t$el.wiki(passage.processText());\n\t\t}\n\t});\n\n\t/*\n\t\t<<nobr>>\n\t*/\n\tMacro.add('nobr', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\t/*\n\t\t\t\tWikify the contents, after removing all leading & trailing newlines and compacting\n\t\t\t\tall internal sequences of newlines into single spaces.\n\t\t\t*/\n\t\t\tnew Wikifier(this.output, this.payload[0].contents.replace(/^\\n+|\\n+$/g, '').replace(/\\n+/g, ' '));\n\t\t}\n\t});\n\n\t/*\n\t\t<<print>>, <<=>>, & <<->>\n\t*/\n\tMacro.add(['print', '=', '-'], {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = toStringOrDefault(Scripting.evalJavaScript(this.args.full), null);\n\n\t\t\t\tif (result !== null) {\n\t\t\t\t\tnew Wikifier(this.output, this.name === '-' ? Util.escape(result) : result);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<silently>>\n\t*/\n\tMacro.add('silently', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, this.payload[0].contents.trim());\n\n\t\t\tif (Config.debug) {\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tthis.debugView.modes({ block : true, hidden : true });\n\t\t\t\tthis.output.appendChild(frag);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Discard the output, unless there were errors.\n\t\t\t\tconst errList = [...frag.querySelectorAll('.error')].map(errEl => errEl.textContent);\n\n\t\t\t\tif (errList.length > 0) {\n\t\t\t\t\treturn this.error(`error${errList.length === 1 ? '' : 's'} within contents (${errList.join('; ')})`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] <<display>>\n\t*/\n\tMacro.add('display', 'include'); // add <<display>> as an alias of <<include>>\n\n\n\t/*******************************************************************************************************************\n\t\tControl Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<if>>, <<elseif>>, & <<else>>\n\t*/\n\tMacro.add('if', {\n\t\tskipArgs : true,\n\t\ttags     : ['elseif', 'else'],\n\n\t\thandler() {\n\t\t\tlet i;\n\n\t\t\ttry {\n\t\t\t\tconst len = this.payload.length;\n\n\t\t\t\t// Sanity checks.\n\t\t\t\tfor (/* declared previously */ i = 0; i < len; ++i) {\n\t\t\t\t\t/* eslint-disable prefer-template */\n\t\t\t\t\tswitch (this.payload[i].name) {\n\t\t\t\t\tcase 'else':\n\t\t\t\t\t\tif (this.payload[i].args.raw.length > 0) {\n\t\t\t\t\t\t\tif (/^\\s*if\\b/i.test(this.payload[i].args.raw)) {\n\t\t\t\t\t\t\t\treturn this.error(`whitespace is not allowed between the \"else\" and \"if\" in <<elseif>> clause${i > 0 ? ' (#' + i + ')' : ''}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn this.error(`<<else>> does not accept a conditional expression (perhaps you meant to use <<elseif>>), invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (i + 1 !== len) {\n\t\t\t\t\t\t\treturn this.error('<<else>> must be the final clause');\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif (this.payload[i].args.full.length === 0) {\n\t\t\t\t\t\t\treturn this.error(`no conditional expression specified for <<${this.payload[i].name}>> clause${i > 0 ? ' (#' + i + ')' : ''}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (\n\t\t\t\t\t\t\t   Config.macros.ifAssignmentError\n\t\t\t\t\t\t\t&& /[^!=&^|<>*/%+-]=[^=>]/.test(this.payload[i].args.full)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn this.error(`assignment operator found within <<${this.payload[i].name}>> clause${i > 0 ? ' (#' + i + ')' : ''} (perhaps you meant to use an equality operator: ==, ===, eq, is), invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable prefer-template */\n\t\t\t\t}\n\n\t\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\t\tlet success = false;\n\n\t\t\t\t// Evaluate the clauses.\n\t\t\t\tfor (/* declared previously */ i = 0; i < len; ++i) {\n\t\t\t\t\t// Custom debug view setup for the current clause.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({ nonvoid : false });\n\t\t\t\t\t}\n\n\t\t\t\t\t// Conditional test.\n\t\t\t\t\tif (this.payload[i].name === 'else' || !!evalJavaScript(this.payload[i].args.full)) {\n\t\t\t\t\t\tsuccess = true;\n\t\t\t\t\t\tnew Wikifier(this.output, this.payload[i].contents);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse if (Config.debug) {\n\t\t\t\t\t\t// Custom debug view setup for a failed conditional.\n\t\t\t\t\t\tthis.debugView.modes({\n\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup for the remaining clauses.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tfor (++i; i < len; ++i) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tFake a debug view for `<</if>>`.  We do this to aid the checking of nesting\n\t\t\t\t\t\tand as a quick indicator of if any of the clauses matched.\n\t\t\t\t\t*/\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : !success,\n\t\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad conditional expression in <<${i === 0 ? 'if' : 'elseif'}>> clause${i > 0 ? ' (#' + i + ')' : ''}: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack); // eslint-disable-line prefer-template\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<switch>>, <<case>>, & <<default>>\n\t*/\n\tMacro.add('switch', {\n\t\tskipArgs : ['switch'],\n\t\ttags     : ['case', 'default'],\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\tconst len = this.payload.length;\n\n\t\t\t// if (len === 1 || !this.payload.some(p => p.name === 'case')) {\n\t\t\tif (len === 1) {\n\t\t\t\treturn this.error('no cases specified');\n\t\t\t}\n\n\t\t\tlet i;\n\n\t\t\t// Sanity checks.\n\t\t\tfor (/* declared previously */ i = 1; i < len; ++i) {\n\t\t\t\tswitch (this.payload[i].name) {\n\t\t\t\tcase 'default':\n\t\t\t\t\tif (this.payload[i].args.length > 0) {\n\t\t\t\t\t\treturn this.error(`<<default>> does not accept values, invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (i + 1 !== len) {\n\t\t\t\t\t\treturn this.error('<<default>> must be the final case');\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tif (this.payload[i].args.length === 0) {\n\t\t\t\t\t\treturn this.error(`no value(s) specified for <<${this.payload[i].name}>> (#${i})`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet result;\n\n\t\t\ttry {\n\t\t\t\tresult = Scripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\tconst debugView = this.debugView; // cache it now, to be modified later\n\t\t\tlet success = false;\n\n\t\t\t// Initial debug view setup for `<<switch>>`.\n\t\t\tif (Config.debug) {\n\t\t\t\tdebugView\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true\n\t\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Evaluate the clauses.\n\t\t\tfor (/* declared previously */ i = 1; i < len; ++i) {\n\t\t\t\t// Custom debug view setup for the current case.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t.modes({ nonvoid : false });\n\t\t\t\t}\n\n\t\t\t\t// Case test(s).\n\t\t\t\tif (this.payload[i].name === 'default' || this.payload[i].args.some(val => val === result)) {\n\t\t\t\t\tsuccess = true;\n\t\t\t\t\tnew Wikifier(this.output, this.payload[i].contents);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (Config.debug) {\n\t\t\t\t\t// Custom debug view setup for a failed case.\n\t\t\t\t\tthis.debugView.modes({\n\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup for the remaining cases.\n\t\t\tif (Config.debug) {\n\t\t\t\tfor (++i; i < len; ++i) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t/*\n\t\t\t\t\tFinalize the debug view for `<<switch>>` and fake a debug view for `<</switch>>`.\n\t\t\t\t\tWe do both as a quick indicator of if any of the cases matched and the latter\n\t\t\t\t\tto aid the checking of nesting.\n\t\t\t\t*/\n\t\t\t\tdebugView\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true, // !success,\n\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t});\n\t\t\t\tthis\n\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true, // !success,\n\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<for>>, <<break>>, & <<continue>>\n\t*/\n\tMacro.add('for', {\n\t\t/* eslint-disable max-len */\n\t\tskipArgs    : true,\n\t\ttags        : null,\n\t\t_hasRangeRe : new RegExp(`^\\\\S${Patterns.anyChar}*?\\\\s+range\\\\s+\\\\S${Patterns.anyChar}*?$`),\n\t\t_rangeRe    : new RegExp(`^(?:State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})\\\\s*,\\\\s*)?State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})\\\\s+range\\\\s+(\\\\S${Patterns.anyChar}*?)$`),\n\t\t_3PartRe    : /^([^;]*?)\\s*;\\s*([^;]*?)\\s*;\\s*([^;]*?)$/,\n\t\t/* eslint-enable max-len */\n\n\t\thandler() {\n\t\t\tconst argsStr = this.args.full.trim();\n\t\t\tconst payload = this.payload[0].contents.replace(/\\n$/, '');\n\n\t\t\t// Empty form.\n\t\t\tif (argsStr.length === 0) {\n\t\t\t\tthis.self._handleFor.call(this, payload, null, true, null);\n\t\t\t}\n\n\t\t\t// Range form.\n\t\t\telse if (this.self._hasRangeRe.test(argsStr)) {\n\t\t\t\tconst parts = argsStr.match(this.self._rangeRe);\n\n\t\t\t\tif (parts === null) {\n\t\t\t\t\treturn this.error('invalid range form syntax, format: [index ,] value range collection');\n\t\t\t\t}\n\n\t\t\t\tthis.self._handleForRange.call(\n\t\t\t\t\tthis,\n\t\t\t\t\tpayload,\n\t\t\t\t\t{ type : parts[1], name : parts[2] },\n\t\t\t\t\t{ type : parts[3], name : parts[4] },\n\t\t\t\t\tparts[5]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Conditional forms.\n\t\t\telse {\n\t\t\t\tlet init;\n\t\t\t\tlet condition;\n\t\t\t\tlet post;\n\n\t\t\t\t// Conditional-only form.\n\t\t\t\tif (argsStr.indexOf(';') === -1) {\n\t\t\t\t\t// Sanity checks.\n\t\t\t\t\tif (/^\\S+\\s+in\\s+\\S+/i.test(argsStr)) {\n\t\t\t\t\t\treturn this.error('invalid syntax, for…in is not supported; see: for…range');\n\t\t\t\t\t}\n\t\t\t\t\telse if (/^\\S+\\s+of\\s+\\S+/i.test(argsStr)) {\n\t\t\t\t\t\treturn this.error('invalid syntax, for…of is not supported; see: for…range');\n\t\t\t\t\t}\n\n\t\t\t\t\tcondition = argsStr;\n\t\t\t\t}\n\n\t\t\t\t// 3-part conditional form.\n\t\t\t\telse {\n\t\t\t\t\tconst parts = argsStr.match(this.self._3PartRe);\n\n\t\t\t\t\tif (parts === null) {\n\t\t\t\t\t\treturn this.error('invalid 3-part conditional form syntax, format: [init] ; [condition] ; [post]');\n\t\t\t\t\t}\n\n\t\t\t\t\tinit      = parts[1];\n\t\t\t\t\tcondition = parts[2].trim();\n\t\t\t\t\tpost      = parts[3];\n\n\t\t\t\t\tif (condition.length === 0) {\n\t\t\t\t\t\tcondition = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis.self._handleFor.call(this, payload, init, condition, post);\n\t\t\t}\n\t\t},\n\n\t\t_handleFor(payload, init, condition, post) {\n\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\tlet first  = true;\n\t\t\tlet safety = Config.macros.maxLoopIterations;\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tTempState.break = null;\n\n\t\t\t\tif (init) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tevalJavaScript(init);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn this.error(`bad init expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\twhile (evalJavaScript(condition)) {\n\t\t\t\t\tif (--safety < 0) {\n\t\t\t\t\t\treturn this.error(`exceeded configured maximum loop iterations (${Config.macros.maxLoopIterations})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tnew Wikifier(this.output, first ? payload.replace(/^\\n/, '') : payload);\n\n\t\t\t\t\tif (first) {\n\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tif (TempState.break === 1) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (TempState.break === 2) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (post) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tevalJavaScript(post);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\treturn this.error(`bad post expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad conditional expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tTempState.break = null;\n\t\t\t}\n\t\t},\n\n\t\t_handleForRange(payload, indexVar, valueVar, rangeExp) {\n\t\t\tlet first     = true;\n\t\t\tlet rangeList;\n\n\t\t\ttry {\n\t\t\t\trangeList = this.self._toRangeList(rangeExp);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(ex.message);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tTempState.break = null;\n\n\t\t\t\tfor (let i = 0; i < rangeList.length; ++i) {\n\t\t\t\t\tif (indexVar.name) {\n\t\t\t\t\t\tState[indexVar.type][indexVar.name] = rangeList[i][0];\n\t\t\t\t\t}\n\n\t\t\t\t\tState[valueVar.type][valueVar.name] = rangeList[i][1];\n\n\t\t\t\t\tnew Wikifier(this.output, first ? payload.replace(/^\\n/, '') : payload);\n\n\t\t\t\t\tif (first) {\n\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tif (TempState.break === 1) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (TempState.break === 2) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tTempState.break = null;\n\t\t\t}\n\t\t},\n\n\t\t_toRangeList(rangeExp) {\n\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\tlet value;\n\n\t\t\ttry {\n\t\t\t\t/*\n\t\t\t\t\tNOTE: If the first character is the left curly brace, then we\n\t\t\t\t\tassume that it's part of an object literal and wrap it within\n\t\t\t\t\tparenthesis to ensure that it is not mistaken for a block\n\t\t\t\t\tduring evaluation—which would cause an error.\n\t\t\t\t*/\n\t\t\t\tvalue = evalJavaScript(rangeExp[0] === '{' ? `(${rangeExp})` : rangeExp);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tif (typeof ex !== 'object') {\n\t\t\t\t\tthrow new Error(`bad range expression: ${ex}`);\n\t\t\t\t}\n\n\t\t\t\tex.message = `bad range expression: ${ex.message}`;\n\t\t\t\tthrow ex;\n\t\t\t}\n\n\t\t\tlet list;\n\n\t\t\tswitch (typeof value) {\n\t\t\tcase 'string':\n\t\t\t\tlist = [];\n\t\t\t\tfor (let i = 0; i < value.length; /* empty */) {\n\t\t\t\t\tconst obj = Util.charAndPosAt(value, i);\n\t\t\t\t\tlist.push([i, obj.char]);\n\t\t\t\t\ti = 1 + obj.end;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'object':\n\t\t\t\tif (Array.isArray(value)) {\n\t\t\t\t\tlist = value.map((val, i) => [i, val]);\n\t\t\t\t}\n\t\t\t\telse if (value instanceof Set) {\n\t\t\t\t\tlist = [...value].map((val, i) => [i, val]);\n\t\t\t\t}\n\t\t\t\telse if (value instanceof Map) {\n\t\t\t\t\tlist = [...value.entries()];\n\t\t\t\t}\n\t\t\t\telse if (Util.toStringTag(value) === 'Object') {\n\t\t\t\t\tlist = Object.keys(value).map(key => [key, value[key]]);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new Error(`unsupported range expression type: ${Util.toStringTag(value)}`);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unsupported range expression type: ${typeof value}`);\n\t\t\t}\n\n\t\t\treturn list;\n\t\t}\n\t});\n\tMacro.add(['break', 'continue'], {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.contextHas(ctx => ctx.name === 'for')) {\n\t\t\t\tTempState.break = this.name === 'continue' ? 1 : 2;\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn this.error('must only be used in conjunction with its parent macro <<for>>');\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tInteractive Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<button>> & <<link>>\n\t*/\n\tMacro.add(['button', 'link'], {\n\t\tisAsync : true,\n\t\ttags    : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error(`no ${this.name === 'button' ? 'button' : 'link'} text specified`);\n\t\t\t}\n\n\t\t\tconst $link = jQuery(document.createElement(this.name === 'button' ? 'button' : 'a'));\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\tconst $image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t.attr('src', this.args[0].source)\n\t\t\t\t\t\t.appendTo($link);\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t}\n\n\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t$link.append(document.createTextNode(this.args[0].text));\n\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the link text.\n\t\t\t\t$link.wikiWithOptions({ profile : 'core' }, this.args[0]);\n\t\t\t\tpassage = this.args.length > 1 ? this.args[1] : undefined;\n\t\t\t}\n\n\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t$link.attr('data-passage', passage);\n\n\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t$link.addClass('link-internal');\n\n\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t$link.addClass('link-visited');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$link.addClass('link-broken');\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$link.addClass('link-internal');\n\t\t\t}\n\n\t\t\t$link\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tnamespace : '.macros',\n\t\t\t\t\tone       : passage != null // lazy equality for null\n\t\t\t\t}, this.createShadowWrapper(\n\t\t\t\t\tthis.payload[0].contents !== ''\n\t\t\t\t\t\t? () => Wikifier.wikifyEval(this.payload[0].contents.trim())\n\t\t\t\t\t\t: null,\n\t\t\t\t\tpassage != null // lazy equality for null\n\t\t\t\t\t\t? () => Engine.play(passage)\n\t\t\t\t\t\t: null\n\t\t\t\t))\n\t\t\t\t.appendTo(this.output);\n\t\t}\n\t});\n\n\t/*\n\t\t<<checkbox>>\n\t*/\n\tMacro.add('checkbox', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 3) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('unchecked value'); }\n\t\t\t\tif (this.args.length < 3) { errors.push('checked value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst uncheckValue = this.args[1];\n\t\t\tconst checkValue   = this.args[2];\n\t\t\tconst el           = document.createElement('input');\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'checkbox',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.checked ? checkValue : uncheckValue);\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and input element to the appropriate value and state, as requested.\n\t\t\t*/\n\t\t\tif (this.args.length > 3 && this.args[3] === 'checked') {\n\t\t\t\tel.checked = true;\n\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tState.setVar(varName, uncheckValue);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<cycle>>, <<listbox>>, <<option>>, & <<optionsfrom>>\n\t*/\n\tMacro.add(['cycle', 'listbox'], {\n\t\tisAsync  : true,\n\t\tskipArgs : ['optionsfrom'],\n\t\ttags     : ['option', 'optionsfrom'],\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no variable name specified');\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId = Util.slugify(varName);\n\t\t\tconst len   = this.payload.length;\n\n\t\t\tif (len === 1) {\n\t\t\t\treturn this.error('no options specified');\n\t\t\t}\n\n\t\t\tconst autoselect = this.args.length > 1 && this.args[1] === 'autoselect';\n\t\t\tconst options    = [];\n\t\t\tconst tagCount   = { option : 0, optionsfrom : 0 };\n\t\t\tlet selectedIdx = -1;\n\n\t\t\t// Get the options and selected index, if any.\n\t\t\tfor (let i = 1; i < len; ++i) {\n\t\t\t\tconst payload = this.payload[i];\n\n\t\t\t\t// <<option label value [selected]>>\n\t\t\t\tif (payload.name === 'option') {\n\t\t\t\t\t++tagCount.option;\n\n\t\t\t\t\tif (payload.args.length === 0) {\n\t\t\t\t\t\treturn this.error(`no arguments specified for <<${payload.name}>> (#${tagCount.option})`);\n\t\t\t\t\t}\n\n\t\t\t\t\toptions.push({\n\t\t\t\t\t\tlabel : String(payload.args[0]),\n\t\t\t\t\t\tvalue : payload.args.length === 1 ? payload.args[0] : payload.args[1]\n\t\t\t\t\t});\n\n\t\t\t\t\tif (payload.args.length > 2 && payload.args[2] === 'selected') {\n\t\t\t\t\t\tif (autoselect) {\n\t\t\t\t\t\t\treturn this.error('cannot specify both the autoselect and selected keywords');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (selectedIdx !== -1) {\n\t\t\t\t\t\t\treturn this.error(`multiple selected keywords specified for <<${payload.name}>> (#${selectedIdx + 1} & #${tagCount.option})`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tselectedIdx = options.length - 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// <<optionsfrom expression>>\n\t\t\t\telse {\n\t\t\t\t\t++tagCount.optionsfrom;\n\n\t\t\t\t\tif (payload.args.full.length === 0) {\n\t\t\t\t\t\treturn this.error(`no expression specified for <<${payload.name}>> (#${tagCount.optionsfrom})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: If the first character is the left curly brace, then we\n\t\t\t\t\t\t\tassume that it's part of an object literal and wrap it within\n\t\t\t\t\t\t\tparenthesis to ensure that it is not mistaken for a block\n\t\t\t\t\t\t\tduring evaluation—which would cause an error.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tconst exp = payload.args.full;\n\t\t\t\t\t\tresult = Scripting.evalJavaScript(exp[0] === '{' ? `(${exp})` : exp);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (typeof result !== 'object' || result === null) {\n\t\t\t\t\t\treturn this.error(`expression must yield a supported collection or generic object (type: ${result === null ? 'null' : typeof result})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (result instanceof Array || result instanceof Set) {\n\t\t\t\t\t\tresult.forEach(val => options.push({ label : String(val), value : val }));\n\t\t\t\t\t}\n\t\t\t\t\telse if (result instanceof Map) {\n\t\t\t\t\t\tresult.forEach((val, key) => options.push({ label : String(key), value : val }));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tconst oType = Util.toStringTag(result);\n\n\t\t\t\t\t\tif (oType !== 'Object') {\n\t\t\t\t\t\t\treturn this.error(`expression must yield a supported collection or generic object (object type: ${oType})`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tObject.keys(result).forEach(key => options.push({ label : key, value : result[key] }));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// No options were selected by the user, so we must select one.\n\t\t\tif (selectedIdx === -1) {\n\t\t\t\t// Attempt to automatically select an option by matching the variable's current value.\n\t\t\t\tif (autoselect) {\n\t\t\t\t\t// NOTE: This will usually fail for objects due to a variety of reasons.\n\t\t\t\t\tconst sameValueZero = Util.sameValueZero;\n\t\t\t\t\tconst curValue      = State.getVar(varName);\n\t\t\t\t\tconst curValueIdx   = options.findIndex(opt => sameValueZero(opt.value, curValue));\n\t\t\t\t\tselectedIdx = curValueIdx === -1 ? 0 : curValueIdx;\n\t\t\t\t}\n\n\t\t\t\t// Simply select the first option.\n\t\t\t\telse {\n\t\t\t\t\tselectedIdx = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set up and append the appropriate element to the output buffer.\n\t\t\tif (this.name === 'cycle') {\n\t\t\t\tlet cycleIdx = selectedIdx;\n\t\t\t\tjQuery(document.createElement('a'))\n\t\t\t\t\t.wikiWithOptions({ profile : 'core' }, options[selectedIdx].label)\n\t\t\t\t\t.attr('id', `${this.name}-${varId}`)\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.ariaClick({ namespace : '.macros' }, this.createShadowWrapper(function () {\n\t\t\t\t\t\tcycleIdx = (cycleIdx + 1) % options.length;\n\t\t\t\t\t\t$(this).empty().wikiWithOptions({ profile : 'core' }, options[cycleIdx].label);\n\t\t\t\t\t\tState.setVar(varName, options[cycleIdx].value);\n\t\t\t\t\t}))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\t\t\telse { // this.name === 'listbox'\n\t\t\t\tconst $select = jQuery(document.createElement('select'));\n\n\t\t\t\toptions.forEach((opt, i) => {\n\t\t\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t\t\t.val(i)\n\t\t\t\t\t\t.text(opt.label)\n\t\t\t\t\t\t.appendTo($select);\n\t\t\t\t});\n\n\t\t\t\t$select\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t\t})\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.val(selectedIdx)\n\t\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\t\tState.setVar(varName, options[Number(this.value)].value);\n\t\t\t\t\t}))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\n\t\t\t// Set the variable to the appropriate value, as requested.\n\t\t\tState.setVar(varName, options[selectedIdx].value);\n\t\t}\n\t});\n\n\t/*\n\t\t<<linkappend>>, <<linkprepend>>, & <<linkreplace>>\n\t*/\n\tMacro.add(['linkappend', 'linkprepend', 'linkreplace'], {\n\t\tisAsync : true,\n\t\ttags    : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no link text specified');\n\t\t\t}\n\n\t\t\tconst $link      = jQuery(document.createElement('a'));\n\t\t\tconst $insert    = jQuery(document.createElement('span'));\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\n\t\t\t$link\n\t\t\t\t.wikiWithOptions({ profile : 'core' }, this.args[0])\n\t\t\t\t.addClass(`link-internal macro-${this.name}`)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tnamespace : '.macros',\n\t\t\t\t\tone       : true\n\t\t\t\t}, this.createShadowWrapper(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tif (this.name === 'linkreplace') {\n\t\t\t\t\t\t\t$link.remove();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t$link\n\t\t\t\t\t\t\t\t.wrap(`<span class=\"macro-${this.name}\"></span>`)\n\t\t\t\t\t\t\t\t.replaceWith(() => $link.html());\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.payload[0].contents !== '') {\n\t\t\t\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\t\t\t\tnew Wikifier(frag, this.payload[0].contents);\n\t\t\t\t\t\t\t$insert.append(frag);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (transition) {\n\t\t\t\t\t\t\tsetTimeout(() => $insert.removeClass(`macro-${this.name}-in`), Engine.minDomActionDelay);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t$insert.addClass(`macro-${this.name}-insert`);\n\n\t\t\tif (transition) {\n\t\t\t\t$insert.addClass(`macro-${this.name}-in`);\n\t\t\t}\n\n\t\t\tif (this.name === 'linkprepend') {\n\t\t\t\t$insert.insertBefore($link);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$insert.insertAfter($link);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<radiobutton>>\n\t*/\n\tMacro.add('radiobutton', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('checked value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId      = Util.slugify(varName);\n\t\t\tconst checkValue = this.args[1];\n\t\t\tconst el         = document.createElement('input');\n\n\t\t\t/*\n\t\t\t\tSet up and initialize the group counter.\n\t\t\t*/\n\t\t\tif (!TempState.hasOwnProperty(this.name)) {\n\t\t\t\tTempState[this.name] = {};\n\t\t\t}\n\n\t\t\tif (!TempState[this.name].hasOwnProperty(varId)) {\n\t\t\t\tTempState[this.name][varId] = 0;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}-${TempState[this.name][varId]++}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'radio',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tif (this.checked) {\n\t\t\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable to the checked value and the input element to checked, if requested.\n\t\t\t*/\n\t\t\tif (this.args.length > 2 && this.args[2] === 'checked') {\n\t\t\t\tel.checked = true;\n\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<textarea>>\n\t*/\n\tMacro.add('textarea', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('default value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst defaultValue = this.args[1];\n\t\t\tconst autofocus    = this.args[2] === 'autofocus';\n\t\t\tconst el           = document.createElement('textarea');\n\n\t\t\t/*\n\t\t\t\tSet up and append the textarea element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\trows     : 4,\n\t\t\t\t\t// cols     : 68, // instead of setting \"cols\" we set the `min-width` in CSS\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.value);\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and textarea element to the default value.\n\t\t\t*/\n\t\t\tState.setVar(varName, defaultValue);\n\t\t\t// Ideally, we should be setting `.defaultValue` here, but IE doesn't support it,\n\t\t\t// so we have to use `.textContent`, which is equivalent.\n\t\t\tel.textContent = defaultValue;\n\n\t\t\t/*\n\t\t\t\tAutofocus the textarea element, if requested.\n\t\t\t*/\n\t\t\tif (autofocus) {\n\t\t\t\t// Set the element's \"autofocus\" attribute.\n\t\t\t\tel.setAttribute('autofocus', 'autofocus');\n\n\t\t\t\t// Set up a single-use post-display task to autofocus the element.\n\t\t\t\tpostdisplay[`#autofocus:${el.id}`] = task => {\n\t\t\t\t\tdelete postdisplay[task]; // single-use task\n\t\t\t\t\tsetTimeout(() => el.focus(), Engine.minDomActionDelay);\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<textbox>>\n\t*/\n\tMacro.add('textbox', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('default value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst defaultValue = this.args[1];\n\t\t\tconst el           = document.createElement('input');\n\t\t\tlet autofocus = false;\n\t\t\tlet passage;\n\n\t\t\tif (this.args.length > 3) {\n\t\t\t\tpassage   = this.args[2];\n\t\t\t\tautofocus = this.args[3] === 'autofocus';\n\t\t\t}\n\t\t\telse if (this.args.length > 2) {\n\t\t\t\tif (this.args[2] === 'autofocus') {\n\t\t\t\t\tautofocus = true;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tpassage = this.args[2];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (typeof passage === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = passage.link;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'text',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.value);\n\t\t\t\t}))\n\t\t\t\t.on('keypress.macros', this.createShadowWrapper(function (ev) {\n\t\t\t\t\t// If Return/Enter is pressed, set the variable and, optionally, forward to another passage.\n\t\t\t\t\tif (ev.which === 13) { // 13 is Return/Enter\n\t\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t\tState.setVar(varName, this.value);\n\n\t\t\t\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and input element to the default value.\n\t\t\t*/\n\t\t\tState.setVar(varName, defaultValue);\n\t\t\tel.value = defaultValue;\n\n\t\t\t/*\n\t\t\t\tAutofocus the input element, if requested.\n\t\t\t*/\n\t\t\tif (autofocus) {\n\t\t\t\t// Set the element's \"autofocus\" attribute.\n\t\t\t\tel.setAttribute('autofocus', 'autofocus');\n\n\t\t\t\t// Set up a single-use post-display task to autofocus the element.\n\t\t\t\tpostdisplay[`#autofocus:${el.id}`] = task => {\n\t\t\t\t\tdelete postdisplay[task]; // single-use task\n\t\t\t\t\tsetTimeout(() => el.focus(), Engine.minDomActionDelay);\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] <<click>>\n\t*/\n\tMacro.add('click', 'link'); // add <<click>> as an alias of <<link>>\n\n\n\t/*******************************************************************************************************************\n\t\tLinks Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<actions>>\n\t*/\n\tMacro.add('actions', {\n\t\thandler() {\n\t\t\tconst $list = jQuery(document.createElement('ul'))\n\t\t\t\t.addClass(this.name)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\tfor (let i = 0; i < this.args.length; ++i) {\n\t\t\t\tlet passage;\n\t\t\t\tlet text;\n\t\t\t\tlet $image;\n\t\t\t\tlet setFn;\n\n\t\t\t\tif (typeof this.args[i] === 'object') {\n\t\t\t\t\tif (this.args[i].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[i].source);\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[i].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[i].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[i].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tpassage = this.args[i].link;\n\t\t\t\t\t\tsetFn   = this.args[i].setFn;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\ttext    = this.args[i].text;\n\t\t\t\t\t\tpassage = this.args[i].link;\n\t\t\t\t\t\tsetFn   = this.args[i].setFn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\ttext = passage = this.args[i];\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\t   State.variables.hasOwnProperty('#actions')\n\t\t\t\t\t&& State.variables['#actions'].hasOwnProperty(passage)\n\t\t\t\t\t&& State.variables['#actions'][passage]\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tjQuery(Wikifier.createInternalLink(\n\t\t\t\t\tjQuery(document.createElement('li')).appendTo($list),\n\t\t\t\t\tpassage,\n\t\t\t\t\tnull,\n\t\t\t\t\t((passage, fn) => () => {\n\t\t\t\t\t\tif (!State.variables.hasOwnProperty('#actions')) {\n\t\t\t\t\t\t\tState.variables['#actions'] = {};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tState.variables['#actions'][passage] = true;\n\n\t\t\t\t\t\tif (typeof fn === 'function') {\n\t\t\t\t\t\t\tfn();\n\t\t\t\t\t\t}\n\t\t\t\t\t})(passage, setFn)\n\t\t\t\t))\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.append($image || document.createTextNode(text));\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<back>> & <<return>>\n\t*/\n\tMacro.add(['back', 'return'], {\n\t\thandler() {\n\t\t\t/* legacy */\n\t\t\tif (this.args.length > 1) {\n\t\t\t\treturn this.error('too many arguments specified, check the documentation for details');\n\t\t\t}\n\t\t\t/* /legacy */\n\n\t\t\tlet momentIndex = -1;\n\t\t\tlet passage;\n\t\t\tlet text;\n\t\t\tlet $image;\n\n\t\t\tif (this.args.length === 1) {\n\t\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[0].source);\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('link')) {\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\tif (this.args[0].count === 1) {\n\t\t\t\t\t\t\t// Simple link syntax: `[[...]]`.\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Pretty link syntax: `[[...|...]]`.\n\t\t\t\t\t\t\ttext    = this.args[0].text;\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (this.args.length === 1) {\n\t\t\t\t\t// Argument was simply the link text.\n\t\t\t\t\ttext = this.args[0];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\t/*\n\t\t\t\t\tFind the index and title of the most recent moment whose title does not match\n\t\t\t\t\tthat of the active (present) moment's.\n\t\t\t\t*/\n\t\t\t\tfor (let i = State.length - 2; i >= 0; --i) {\n\t\t\t\t\tif (State.history[i].title !== State.passage) {\n\t\t\t\t\t\tmomentIndex = i;\n\t\t\t\t\t\tpassage = State.history[i].title;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If we failed to find a passage and we're `<<return>>`, fallback to `State.expired`.\n\t\t\t\tif (passage == null && this.name === 'return') { // lazy equality for null\n\t\t\t\t\tfor (let i = State.expired.length - 1; i >= 0; --i) {\n\t\t\t\t\t\tif (State.expired[i] !== State.passage) {\n\t\t\t\t\t\t\tpassage = State.expired[i];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (!Story.has(passage)) {\n\t\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tif (this.name === 'back') {\n\t\t\t\t\t/*\n\t\t\t\t\t\tFind the index of the most recent moment whose title matches that of the\n\t\t\t\t\t\tspecified passage.\n\t\t\t\t\t*/\n\t\t\t\t\tfor (let i = State.length - 2; i >= 0; --i) {\n\t\t\t\t\t\tif (State.history[i].title === passage) {\n\t\t\t\t\t\t\tmomentIndex = i;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (momentIndex === -1) {\n\t\t\t\t\t\treturn this.error(`cannot find passage \"${passage}\" in the current story history`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn this.error('cannot find passage');\n\t\t\t}\n\n\t\t\t// if (this.name === \"back\" && momentIndex === -1) {\n\t\t\t// \t// no-op; we're already at the first passage in the current story history\n\t\t\t// \treturn;\n\t\t\t// }\n\n\t\t\tlet $el;\n\n\t\t\tif (this.name !== 'back' || momentIndex !== -1) {\n\t\t\t\t$el = jQuery(document.createElement('a'))\n\t\t\t\t\t.addClass('link-internal')\n\t\t\t\t\t.ariaClick(\n\t\t\t\t\t\t{ one : true },\n\t\t\t\t\t\tthis.name === 'return'\n\t\t\t\t\t\t\t? () => Engine.play(passage)\n\t\t\t\t\t\t\t: () => Engine.goTo(momentIndex)\n\t\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$el = jQuery(document.createElement('span'))\n\t\t\t\t\t.addClass('link-disabled');\n\t\t\t}\n\n\t\t\t$el\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.append($image || document.createTextNode(text || L10n.get(`macro${this.name.toUpperFirst()}Text`)))\n\t\t\t\t.appendTo(this.output);\n\t\t}\n\t});\n\n\t/*\n\t\t<<choice>>\n\t*/\n\tMacro.add('choice', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tconst choiceId = State.passage;\n\t\t\tlet passage;\n\t\t\tlet text;\n\t\t\tlet $image;\n\t\t\tlet setFn;\n\n\t\t\tif (this.args.length === 1) {\n\t\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[0].source);\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\tsetFn   = this.args[0].setFn;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\ttext    = this.args[0].text;\n\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\tsetFn   = this.args[0].setFn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\ttext = passage = this.args[0];\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// NOTE: The arguments here are backwards.\n\t\t\t\tpassage = this.args[0];\n\t\t\t\ttext    = this.args[1];\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t   State.variables.hasOwnProperty('#choice')\n\t\t\t\t&& State.variables['#choice'].hasOwnProperty(choiceId)\n\t\t\t\t&& State.variables['#choice'][choiceId]\n\t\t\t) {\n\t\t\t\tjQuery(document.createElement('span'))\n\t\t\t\t\t.addClass(`link-disabled macro-${this.name}`)\n\t\t\t\t\t.attr('tabindex', -1)\n\t\t\t\t\t.append($image || document.createTextNode(text))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tjQuery(Wikifier.createInternalLink(this.output, passage, null, () => {\n\t\t\t\tif (!State.variables.hasOwnProperty('#choice')) {\n\t\t\t\t\tState.variables['#choice'] = {};\n\t\t\t\t}\n\n\t\t\t\tState.variables['#choice'][choiceId] = true;\n\n\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\tsetFn();\n\t\t\t\t}\n\t\t\t}))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.append($image || document.createTextNode(text));\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tDOM Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<addclass>> & <<toggleclass>>\n\t*/\n\tMacro.add(['addclass', 'toggleclass'], {\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('selector'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('class names'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tswitch (this.name) {\n\t\t\tcase 'addclass':\n\t\t\t\t$targets.addClass(this.args[1].trim());\n\t\t\t\tbreak;\n\n\t\t\tcase 'toggleclass':\n\t\t\t\t$targets.toggleClass(this.args[1].trim());\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<removeclass>>\n\t*/\n\tMacro.add('removeclass', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tif (this.args.length > 1) {\n\t\t\t\t$targets.removeClass(this.args[1].trim());\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$targets.removeClass();\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<copy>>\n\t*/\n\tMacro.add('copy', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tjQuery(this.output).append($targets.html());\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<append>>, <<prepend>>, & <<replace>>\n\t*/\n\tMacro.add(['append', 'prepend', 'replace'], {\n\t\ttags : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tif (this.payload[0].contents !== '') {\n\t\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\t\tlet $insert;\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$insert = jQuery(document.createElement('span'));\n\t\t\t\t\t$insert.addClass(`macro-${this.name}-insert macro-${this.name}-in`);\n\t\t\t\t\tsetTimeout(() => $insert.removeClass(`macro-${this.name}-in`), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$insert = jQuery(document.createDocumentFragment());\n\t\t\t\t}\n\n\t\t\t\t$insert.wiki(this.payload[0].contents);\n\n\t\t\t\tswitch (this.name) {\n\t\t\t\tcase 'replace':\n\t\t\t\t\t$targets.empty();\n\t\t\t\t\t/* falls through */\n\n\t\t\t\tcase 'append':\n\t\t\t\t\t$targets.append($insert);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'prepend':\n\t\t\t\t\t$targets.prepend($insert);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (this.name === 'replace') {\n\t\t\t\t$targets.empty();\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<remove>>\n\t*/\n\tMacro.add('remove', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\t$targets.remove();\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAudio Macros.\n\t*******************************************************************************************************************/\n\tif (Has.audio) {\n\t\tconst errorOnePlaybackAction = (cur, prev) => `only one playback action allowed per invocation, \"${cur}\" cannot be combined with \"${prev}\"`;\n\n\t\t/*\n\t\t\t<<audio>>\n\t\t*/\n\t\tMacro.add('audio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\tconst errors = [];\n\t\t\t\t\tif (this.args.length < 1) { errors.push('track and/or group IDs'); }\n\t\t\t\t\tif (this.args.length < 2) { errors.push('actions'); }\n\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t}\n\n\t\t\t\tlet selected;\n\n\t\t\t\t// Process the track and/or group IDs.\n\t\t\t\ttry {\n\t\t\t\t\tselected = SimpleAudio.select(this.args[0]);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\tconst args = this.args.slice(1);\n\t\t\t\tlet action;\n\t\t\t\tlet fadeOver = 5;\n\t\t\t\tlet fadeTo;\n\t\t\t\tlet loop;\n\t\t\t\tlet mute;\n\t\t\t\tlet passage;\n\t\t\t\tlet time;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\tcase 'play':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadein':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 1;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeout':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 0;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('fadeto missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeoverto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length < 2) {\n\t\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\t\tif (args.length < 1) { errors.push('seconds'); }\n\t\t\t\t\t\t\tif (args.length < 2) { errors.push('level'); }\n\t\t\t\t\t\t\treturn this.error(`fadeoverto missing required ${errors.join(' and ')} value${errors.length > 1 ? 's' : ''}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeOver = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeOver) || !Number.isFinite(fadeOver)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'time':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('time missing required seconds value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\ttime = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(time) || !Number.isFinite(time)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse time: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'loop':\n\t\t\t\t\tcase 'unloop':\n\t\t\t\t\t\tloop = arg === 'loop';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'goto':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('goto missing required passage title');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\n\t\t\t\t\t\tif (typeof raw === 'object') {\n\t\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\t\tpassage = raw.link;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\t\t\tpassage = raw;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!Story.has(passage)) {\n\t\t\t\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tselected.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (time != null) { // lazy equality for null\n\t\t\t\t\t\tselected.time(time);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tselected.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (loop != null) { // lazy equality for null\n\t\t\t\t\t\tselected.loop(loop);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t\t\tconst nsEnded = `ended.macros.macro-${this.name}_goto`;\n\t\t\t\t\t\tselected\n\t\t\t\t\t\t\t.off(nsEnded)\n\t\t\t\t\t\t\t.one(nsEnded, () => {\n\t\t\t\t\t\t\t\tselected.off(nsEnded);\n\t\t\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'fade':\n\t\t\t\t\t\tselected.fade(fadeOver, fadeTo);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tselected.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\t\tselected.pause();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'play':\n\t\t\t\t\t\tselected.playWhenAllowed();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tselected.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tselected.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<cacheaudio track_id source_list>>\n\t\t*/\n\t\tMacro.add('cacheaudio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\tconst errors = [];\n\t\t\t\t\tif (this.args.length < 1) { errors.push('track ID'); }\n\t\t\t\t\tif (this.args.length < 2) { errors.push('sources'); }\n\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t}\n\n\t\t\t\tconst id       = String(this.args[0]).trim();\n\t\t\t\tconst oldFmtRe = /^format:\\s*([\\w-]+)\\s*;\\s*/i;\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.tracks.add(id, this.args.slice(1).map(source => {\n\t\t\t\t\t\t/* legacy */\n\t\t\t\t\t\t// Transform an old format specifier into the new style.\n\t\t\t\t\t\tif (oldFmtRe.test(source)) {\n\t\t\t\t\t\t\t// If in Test Mode, return an error.\n\t\t\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\t\t\treturn this.error(`track ID \"${id}\": format specifier migration required, \"format:formatId;\" \\u2192 \"formatId|\"`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tsource = source.replace(oldFmtRe, '$1|'); // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn source;\n\t\t\t\t\t\t/* /legacy */\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// If in Test Mode and no supported sources were specified, return an error.\n\t\t\t\tif (Config.debug && !SimpleAudio.tracks.get(id).hasSource()) {\n\t\t\t\t\treturn this.error(`track ID \"${id}\": no supported audio sources found`);\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<createaudiogroup group_id>>\n\t\t\t\t<<track track_id>>\n\t\t\t\t…\n\t\t\t<</createaudiogroup>>\n\t\t*/\n\t\tMacro.add('createaudiogroup', {\n\t\t\ttags : ['track'],\n\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no group ID specified');\n\t\t\t\t}\n\n\t\t\t\tif (this.payload.length === 1) {\n\t\t\t\t\treturn this.error('no tracks defined via <<track>>');\n\t\t\t\t}\n\n\t\t\t\t// Initial debug view setup for `<<createaudiogroup>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst groupId  = String(this.args[0]).trim();\n\t\t\t\tconst trackIds = [];\n\n\t\t\t\tfor (let i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\tif (this.payload[i].args.length < 1) {\n\t\t\t\t\t\treturn this.error('no track ID specified');\n\t\t\t\t\t}\n\n\t\t\t\t\ttrackIds.push(String(this.payload[i].args[0]).trim());\n\n\t\t\t\t\t// Custom debug view setup for the current `<<track>>`.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.groups.add(groupId, trackIds);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Custom fake debug view setup for `<</createaudiogroup>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<createplaylist list_id>>\n\t\t\t\t<<track track_id action_list>>\n\t\t\t\t…\n\t\t\t<</createplaylist>>\n\t\t*/\n\t\tMacro.add('createplaylist', {\n\t\t\ttags : ['track'],\n\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no list ID specified');\n\t\t\t\t}\n\n\t\t\t\tif (this.payload.length === 1) {\n\t\t\t\t\treturn this.error('no tracks defined via <<track>>');\n\t\t\t\t}\n\n\t\t\t\tconst playlist = Macro.get('playlist');\n\n\t\t\t\tif (playlist.from !== null && playlist.from !== 'createplaylist') {\n\t\t\t\t\treturn this.error('a playlist has already been defined with <<setplaylist>>');\n\t\t\t\t}\n\n\t\t\t\t// Initial debug view setup for `<<createplaylist>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst listId    = String(this.args[0]).trim();\n\t\t\t\tconst trackObjs = [];\n\n\t\t\t\tfor (let i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\tif (this.payload[i].args.length === 0) {\n\t\t\t\t\t\treturn this.error('no track ID specified');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst trackObj = { id : String(this.payload[i].args[0]).trim() };\n\t\t\t\t\tconst args     = this.payload[i].args.slice(1);\n\n\t\t\t\t\t// Process arguments.\n\t\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\t\tlet raw;\n\t\t\t\t\t\tlet parsed;\n\n\t\t\t\t\t\tswitch (arg) {\n\t\t\t\t\t\tcase 'copy': // [DEPRECATED]\n\t\t\t\t\t\tcase 'own':\n\t\t\t\t\t\t\ttrackObj.own = true;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'rate':\n\t\t\t\t\t\t\t// if (args.length === 0) {\n\t\t\t\t\t\t\t// \treturn this.error('rate missing required speed value');\n\t\t\t\t\t\t\t// }\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// raw = args.shift();\n\t\t\t\t\t\t\t// parsed = Number.parseFloat(raw);\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// if (Number.isNaN(parsed) || !Number.isFinite(parsed)) {\n\t\t\t\t\t\t\t// \treturn this.error(`cannot parse rate: ${raw}`);\n\t\t\t\t\t\t\t// }\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// trackObj.rate = parsed;\n\t\t\t\t\t\t\tif (args.length > 0) {\n\t\t\t\t\t\t\t\targs.shift();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\t\tparsed = Number.parseFloat(raw);\n\n\t\t\t\t\t\t\tif (Number.isNaN(parsed) || !Number.isFinite(parsed)) {\n\t\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ttrackObj.volume = parsed;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\ttrackObjs.push(trackObj);\n\n\t\t\t\t\t// Custom debug view setup for the current `<<track>>`.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.lists.add(listId, trackObjs);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Lock `<<playlist>>` into our syntax.\n\t\t\t\tif (playlist.from === null) {\n\t\t\t\t\tplaylist.from = 'createplaylist';\n\t\t\t\t}\n\n\t\t\t\t// Custom fake debug view setup for `<</createplaylist>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<masteraudio action_list>>\n\t\t*/\n\t\tMacro.add('masteraudio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no actions specified');\n\t\t\t\t}\n\n\t\t\t\tconst args = this.args.slice(0);\n\t\t\t\tlet action;\n\t\t\t\tlet mute;\n\t\t\t\tlet muteOnHide;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'muteonhide':\n\t\t\t\t\tcase 'nomuteonhide':\n\t\t\t\t\t\tmuteOnHide = arg === 'muteonhide';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (muteOnHide != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.muteOnHidden(muteOnHide);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tSimpleAudio.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tSimpleAudio.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tSimpleAudio.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<playlist list_id action_list>>  ← <<createplaylist>> syntax\n\t\t\t<<playlist action_list>>          ← <<setplaylist>> syntax\n\t\t*/\n\t\tMacro.add('playlist', {\n\t\t\tfrom : null,\n\n\t\t\thandler() {\n\t\t\t\tconst from = this.self.from;\n\n\t\t\t\tif (from === null) {\n\t\t\t\t\treturn this.error('no playlists have been created');\n\t\t\t\t}\n\n\t\t\t\tlet list;\n\t\t\t\tlet args;\n\n\t\t\t\tif (from === 'createplaylist') {\n\t\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\tif (this.args.length < 1) { errors.push('list ID'); }\n\t\t\t\t\t\tif (this.args.length < 2) { errors.push('actions'); }\n\t\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\t\tif (!SimpleAudio.lists.has(id)) {\n\t\t\t\t\t\treturn this.error(`playlist \"${id}\" does not exist`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlist = SimpleAudio.lists.get(id);\n\t\t\t\t\targs = this.args.slice(1);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\t\treturn this.error('no actions specified');\n\t\t\t\t\t}\n\n\t\t\t\t\tlist = SimpleAudio.lists.get('setplaylist');\n\t\t\t\t\targs = this.args.slice(0);\n\t\t\t\t}\n\n\t\t\t\tlet action;\n\t\t\t\tlet fadeOver = 5;\n\t\t\t\tlet fadeTo;\n\t\t\t\tlet loop;\n\t\t\t\tlet mute;\n\t\t\t\tlet shuffle;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\tcase 'play':\n\t\t\t\t\tcase 'skip':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadein':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 1;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeout':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 0;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('fadeto missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeoverto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length < 2) {\n\t\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\t\tif (args.length < 1) { errors.push('seconds'); }\n\t\t\t\t\t\t\tif (args.length < 2) { errors.push('level'); }\n\t\t\t\t\t\t\treturn this.error(`fadeoverto missing required ${errors.join(' and ')} value${errors.length > 1 ? 's' : ''}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeOver = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeOver) || !Number.isFinite(fadeOver)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'loop':\n\t\t\t\t\tcase 'unloop':\n\t\t\t\t\t\tloop = arg === 'loop';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'shuffle':\n\t\t\t\t\tcase 'unshuffle':\n\t\t\t\t\t\tshuffle = arg === 'shuffle';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tlist.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tlist.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (loop != null) { // lazy equality for null\n\t\t\t\t\t\tlist.loop(loop);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (shuffle != null) { // lazy equality for null\n\t\t\t\t\t\tlist.shuffle(shuffle);\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'fade':\n\t\t\t\t\t\tlist.fade(fadeOver, fadeTo);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tlist.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\t\tlist.pause();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'play':\n\t\t\t\t\t\tlist.playWhenAllowed();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'skip':\n\t\t\t\t\t\tlist.skip();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tlist.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tlist.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<removeaudiogroup group_id>>\n\t\t*/\n\t\tMacro.add('removeaudiogroup', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no group ID specified');\n\t\t\t\t}\n\n\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\tif (!SimpleAudio.groups.has(id)) {\n\t\t\t\t\treturn this.error(`group \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tSimpleAudio.groups.delete(id);\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<removeplaylist list_id>>\n\t\t*/\n\t\tMacro.add('removeplaylist', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no list ID specified');\n\t\t\t\t}\n\n\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\tif (!SimpleAudio.lists.has(id)) {\n\t\t\t\t\treturn this.error(`playlist \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tSimpleAudio.lists.delete(id);\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<waitforaudio>>\n\t\t*/\n\t\tMacro.add('waitforaudio', {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\tSimpleAudio.loadWithScreen();\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t[DEPRECATED] <<setplaylist track_id_list>>\n\t\t*/\n\t\tMacro.add('setplaylist', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no track ID(s) specified');\n\t\t\t\t}\n\n\t\t\t\tconst playlist = Macro.get('playlist');\n\n\t\t\t\tif (playlist.from !== null && playlist.from !== 'setplaylist') {\n\t\t\t\t\treturn this.error('playlists have already been defined with <<createplaylist>>');\n\t\t\t\t}\n\n\t\t\t\t// Create the new playlist.\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.lists.add('setplaylist', this.args.slice(0));\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Lock `<<playlist>>` into our syntax.\n\t\t\t\tif (playlist.from === null) {\n\t\t\t\t\tplaylist.from = 'setplaylist';\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t[DEPRECATED] <<stopallaudio>>\n\t\t*/\n\t\tMacro.add('stopallaudio', {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\tSimpleAudio.select(':all').stop();\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\telse {\n\t\t/* The HTML5 <audio> API appears to be missing or disabled, set up no-op macros. */\n\t\tMacro.add([\n\t\t\t'audio',\n\t\t\t'cacheaudio',\n\t\t\t'createaudiogroup',\n\t\t\t'createplaylist',\n\t\t\t'masteraudio',\n\t\t\t'playlist',\n\t\t\t'removeaudiogroup',\n\t\t\t'removeplaylist',\n\t\t\t'waitforaudio',\n\n\t\t\t// Deprecated.\n\t\t\t'setplaylist',\n\t\t\t'stopallaudio'\n\t\t], {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\t/* no-op */\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMiscellaneous Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<goto>>\n\t*/\n\tMacro.add('goto', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = this.args[0].link;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the passage name.\n\t\t\t\tpassage = this.args[0];\n\t\t\t}\n\n\t\t\tif (!Story.has(passage)) {\n\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tCall `Engine.play()` asynchronously.\n\n\t\t\t\tNOTE: This does not terminate the current Wikifier call chain,\n\t\t\t\tthough, ideally, it should.  Doing so would not be trivial, however,\n\t\t\t\tand there's also the question of whether that behavior would be\n\t\t\t\tunwanted by users, who are used to the current behavior from\n\t\t\t\tsimilar macros and constructs.\n\t\t\t*/\n\t\t\tsetTimeout(() => Engine.play(passage), Engine.minDomActionDelay);\n\t\t}\n\t});\n\n\t/*\n\t\t<<repeat>> & <<stop>>\n\t*/\n\tMacro.add('repeat', {\n\t\tisAsync : true,\n\t\ttags    : null,\n\t\ttimers  : new Set(),\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no time value specified');\n\t\t\t}\n\n\t\t\tlet delay;\n\n\t\t\ttry {\n\t\t\t\tdelay = Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.args[0]));\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(ex.message);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\tconst $wrapper   = jQuery(document.createElement('span'))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t// Register the timer.\n\t\t\tthis.self.registerInterval(this.createShadowWrapper(() => {\n\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(frag, this.payload[0].contents);\n\n\t\t\t\tlet $output = $wrapper;\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$output = jQuery(document.createElement('span'))\n\t\t\t\t\t\t.addClass('macro-repeat-insert macro-repeat-in')\n\t\t\t\t\t\t.appendTo($output);\n\t\t\t\t}\n\n\t\t\t\t$output.append(frag);\n\n\t\t\t\tif (transition) {\n\t\t\t\t\tsetTimeout(() => $output.removeClass('macro-repeat-in'), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t}), delay);\n\t\t},\n\n\t\tregisterInterval(callback, delay) {\n\t\t\tif (typeof callback !== 'function') {\n\t\t\t\tthrow new TypeError('callback parameter must be a function');\n\t\t\t}\n\n\t\t\tconst turnId = State.turns;\n\t\t\tconst timers = this.timers;\n\t\t\tlet timerId = null;\n\n\t\t\t// Set up the interval.\n\t\t\ttimerId = setInterval(() => {\n\t\t\t\t// Terminate the timer if the turn IDs do not match.\n\t\t\t\tif (turnId !== State.turns) {\n\t\t\t\t\tclearInterval(timerId);\n\t\t\t\t\ttimers.delete(timerId);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet timerIdCache;\n\t\t\t\t/*\n\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t`Wikifier` call.\n\t\t\t\t*/\n\t\t\t\ttry {\n\t\t\t\t\tTempState.break = null;\n\n\t\t\t\t\t// Set up the `repeatTimerId` value, caching the existing value, if necessary.\n\t\t\t\t\tif (TempState.hasOwnProperty('repeatTimerId')) {\n\t\t\t\t\t\ttimerIdCache = TempState.repeatTimerId;\n\t\t\t\t\t}\n\n\t\t\t\t\tTempState.repeatTimerId = timerId;\n\n\t\t\t\t\t// Execute the callback.\n\t\t\t\t\tcallback.call(this);\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\t// Teardown the `repeatTimerId` property, restoring the cached value, if necessary.\n\t\t\t\t\tif (typeof timerIdCache !== 'undefined') {\n\t\t\t\t\t\tTempState.repeatTimerId = timerIdCache;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdelete TempState.repeatTimerId;\n\t\t\t\t\t}\n\n\t\t\t\t\tTempState.break = null;\n\t\t\t\t}\n\t\t\t}, delay);\n\t\t\ttimers.add(timerId);\n\n\t\t\t// Set up a single-use `prehistory` task to remove pending timers.\n\t\t\tif (!prehistory.hasOwnProperty('#repeat-timers-cleanup')) {\n\t\t\t\tprehistory['#repeat-timers-cleanup'] = task => {\n\t\t\t\t\tdelete prehistory[task]; // single-use task\n\t\t\t\t\ttimers.forEach(timerId => clearInterval(timerId));\n\t\t\t\t\ttimers.clear();\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\tMacro.add('stop', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (!TempState.hasOwnProperty('repeatTimerId')) {\n\t\t\t\treturn this.error('must only be used in conjunction with its parent macro <<repeat>>');\n\t\t\t}\n\n\t\t\tconst timers  = Macro.get('repeat').timers;\n\t\t\tconst timerId = TempState.repeatTimerId;\n\t\t\tclearInterval(timerId);\n\t\t\ttimers.delete(timerId);\n\t\t\tTempState.break = 2;\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<timed>> & <<next>>\n\t*/\n\tMacro.add('timed', {\n\t\tisAsync : true,\n\t\ttags    : ['next'],\n\t\ttimers  : new Set(),\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no time value specified in <<timed>>');\n\t\t\t}\n\n\t\t\tconst items = [];\n\n\t\t\ttry {\n\t\t\t\titems.push({\n\t\t\t\t\tname    : this.name,\n\t\t\t\t\tsource  : this.source,\n\t\t\t\t\tdelay   : Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.args[0])),\n\t\t\t\t\tcontent : this.payload[0].contents\n\t\t\t\t});\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`${ex.message} in <<timed>>`);\n\t\t\t}\n\n\t\t\tif (this.payload.length > 1) {\n\t\t\t\tlet i;\n\n\t\t\t\ttry {\n\t\t\t\t\tlet len;\n\n\t\t\t\t\tfor (i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\t\titems.push({\n\t\t\t\t\t\t\tname   : this.payload[i].name,\n\t\t\t\t\t\t\tsource : this.payload[i].source,\n\t\t\t\t\t\t\tdelay  : this.payload[i].args.length === 0\n\t\t\t\t\t\t\t\t? items[items.length - 1].delay\n\t\t\t\t\t\t\t\t: Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.payload[i].args[0])),\n\t\t\t\t\t\t\tcontent : this.payload[i].contents\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`${ex.message} in <<next>> (#${i})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\tconst $wrapper   = jQuery(document.createElement('span'))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t// Register the timer.\n\t\t\tthis.self.registerTimeout(this.createShadowWrapper(item => {\n\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(frag, item.content);\n\n\t\t\t\t// Output.\n\t\t\t\tlet $output = $wrapper;\n\n\t\t\t\t// Custom debug view setup for `<<next>>`.\n\t\t\t\tif (Config.debug && item.name === 'next') {\n\t\t\t\t\t$output = jQuery((new DebugView( // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t$output[0],\n\t\t\t\t\t\t'macro',\n\t\t\t\t\t\titem.name,\n\t\t\t\t\t\titem.source\n\t\t\t\t\t)).output);\n\t\t\t\t}\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$output = jQuery(document.createElement('span'))\n\t\t\t\t\t\t.addClass('macro-timed-insert macro-timed-in')\n\t\t\t\t\t\t.appendTo($output);\n\t\t\t\t}\n\n\t\t\t\t$output.append(frag);\n\n\t\t\t\tif (transition) {\n\t\t\t\t\tsetTimeout(() => $output.removeClass('macro-timed-in'), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t}), items);\n\t\t},\n\n\t\tregisterTimeout(callback, items) {\n\t\t\tif (typeof callback !== 'function') {\n\t\t\t\tthrow new TypeError('callback parameter must be a function');\n\t\t\t}\n\n\t\t\tconst turnId = State.turns;\n\t\t\tconst timers = this.timers;\n\t\t\tlet timerId  = null;\n\t\t\tlet nextItem = items.shift();\n\n\t\t\tconst worker = function () {\n\t\t\t\t// Bookkeeping.\n\t\t\t\ttimers.delete(timerId);\n\n\t\t\t\tif (turnId !== State.turns) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Set the current item and set up the next worker, if any.\n\t\t\t\tconst curItem = nextItem;\n\n\t\t\t\tif ((nextItem = items.shift()) != null) { // lazy equality for null\n\t\t\t\t\ttimerId = setTimeout(worker, nextItem.delay);\n\t\t\t\t\ttimers.add(timerId);\n\t\t\t\t}\n\n\t\t\t\t// Execute the callback.\n\t\t\t\tcallback.call(this, curItem);\n\t\t\t};\n\n\t\t\t// Setup the timeout.\n\t\t\ttimerId = setTimeout(worker, nextItem.delay);\n\t\t\ttimers.add(timerId);\n\n\t\t\t// Set up a single-use `prehistory` task to remove pending timers.\n\t\t\tif (!prehistory.hasOwnProperty('#timed-timers-cleanup')) {\n\t\t\t\tprehistory['#timed-timers-cleanup'] = task => {\n\t\t\t\t\tdelete prehistory[task]; // single-use task\n\t\t\t\t\ttimers.forEach(timerId => clearTimeout(timerId)); // eslint-disable-line no-shadow\n\t\t\t\t\ttimers.clear();\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<widget>>\n\t*/\n\tMacro.add('widget', {\n\t\ttags : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no widget name specified');\n\t\t\t}\n\n\t\t\tconst widgetName = this.args[0];\n\n\t\t\tif (Macro.has(widgetName)) {\n\t\t\t\tif (!Macro.get(widgetName).isWidget) {\n\t\t\t\t\treturn this.error(`cannot clobber existing macro \"${widgetName}\"`);\n\t\t\t\t}\n\n\t\t\t\t// Delete the existing widget.\n\t\t\t\tMacro.delete(widgetName);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tMacro.add(widgetName, {\n\t\t\t\t\tisWidget : true,\n\t\t\t\t\thandler  : (function (contents) {\n\t\t\t\t\t\treturn function () {\n\t\t\t\t\t\t\tlet argsCache;\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t// Cache the existing value of the `$args` variable, if necessary.\n\t\t\t\t\t\t\t\tif (State.variables.hasOwnProperty('args')) {\n\t\t\t\t\t\t\t\t\targsCache = State.variables.args;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Set up the widget `$args` variable and add a shadow.\n\t\t\t\t\t\t\t\tState.variables.args = [...this.args];\n\t\t\t\t\t\t\t\tState.variables.args.raw = this.args.raw;\n\t\t\t\t\t\t\t\tState.variables.args.full = this.args.full;\n\t\t\t\t\t\t\t\tthis.addShadow('$args');\n\n\t\t\t\t\t\t\t\t// Set up the error trapping variables.\n\t\t\t\t\t\t\t\tconst resFrag = document.createDocumentFragment();\n\t\t\t\t\t\t\t\tconst errList = [];\n\n\t\t\t\t\t\t\t\t// Wikify the widget contents.\n\t\t\t\t\t\t\t\tnew Wikifier(resFrag, contents);\n\n\t\t\t\t\t\t\t\t// Carry over the output, unless there were errors.\n\t\t\t\t\t\t\t\tArray.from(resFrag.querySelectorAll('.error')).forEach(errEl => {\n\t\t\t\t\t\t\t\t\terrList.push(errEl.textContent);\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tif (errList.length === 0) {\n\t\t\t\t\t\t\t\t\tthis.output.appendChild(resFrag);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\treturn this.error(`error${errList.length > 1 ? 's' : ''} within widget contents (${errList.join('; ')})`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\treturn this.error(`cannot execute widget: ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t// Revert the `$args` variable shadowing.\n\t\t\t\t\t\t\t\tif (typeof argsCache !== 'undefined') {\n\t\t\t\t\t\t\t\t\tState.variables.args = argsCache;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tdelete State.variables.args;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t})(this.payload[0].contents)\n\t\t\t\t});\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`cannot create widget macro \"${widgetName}\": ${ex.message}`);\n\t\t\t}\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tdialog.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Has, L10n, safeActiveElement */\n\nvar Dialog = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Dialog element caches.\n\tlet _$overlay       = null;\n\tlet _$dialog        = null;\n\tlet _$dialogTitle   = null;\n\tlet _$dialogBody    = null;\n\n\t// The last active/focused non-dialog element.\n\tlet _lastActive     = null;\n\n\t// The width of the browser's scrollbars.\n\tlet _scrollbarWidth = 0;\n\n\t// Dialog mutation resize handler.\n\tlet _dialogObserver = null;\n\n\n\t/*******************************************************************************\n\t\tDialog Functions.\n\t*******************************************************************************/\n\n\t/*\n\t\t[DEPRECATED] Adds a click hander to the target element(s) which opens the dialog modal.\n\t*/\n\tfunction dialogAddClickHandler(targets, options, startFn, doneFn, closeFn) {\n\t\treturn jQuery(targets).ariaClick(ev => {\n\t\t\tev.preventDefault();\n\n\t\t\t// Call the start function.\n\t\t\tif (typeof startFn === 'function') {\n\t\t\t\tstartFn(ev);\n\t\t\t}\n\n\t\t\t// Open the dialog.\n\t\t\tdialogOpen(options, closeFn);\n\n\t\t\t// Call the done function.\n\t\t\tif (typeof doneFn === 'function') {\n\t\t\t\tdoneFn(ev);\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction dialogBodyAppend(...args) {\n\t\t_$dialogBody.append(...args);\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogBody() {\n\t\treturn _$dialogBody.get(0);\n\t}\n\n\tfunction dialogClose(ev) {\n\t\t// Trigger a `:dialogclosing` event on the dialog body.\n\t\t_$dialogBody.trigger(':dialogclosing');\n\n\t\t// Largely reverse the actions taken in `dialogOpen()`.\n\t\tjQuery(document)\n\t\t\t.off('.dialog-close');\n\t\tif (_dialogObserver) {\n\t\t\t_dialogObserver.disconnect();\n\t\t\t_dialogObserver = null;\n\t\t}\n\t\telse {\n\t\t\t_$dialogBody\n\t\t\t\t.off('.dialog-resize');\n\t\t}\n\t\tjQuery(window)\n\t\t\t.off('.dialog-resize');\n\t\t_$dialog\n\t\t\t.removeClass('open')\n\t\t\t.css({ left : '', right : '', top : '', bottom : '' });\n\n\t\tjQuery('#ui-bar,#story')\n\t\t\t.find('[tabindex=-2]')\n\t\t\t.removeAttr('aria-hidden')\n\t\t\t.attr('tabindex', 0);\n\t\tjQuery('body>[tabindex=-3]')\n\t\t\t.removeAttr('aria-hidden')\n\t\t\t.removeAttr('tabindex');\n\n\t\t_$overlay\n\t\t\t.removeClass('open');\n\t\tjQuery(document.documentElement)\n\t\t\t.removeAttr('data-dialog');\n\n\t\t// Clear the dialog's content.\n\t\t_$dialogTitle\n\t\t\t.empty();\n\t\t_$dialogBody\n\t\t\t.empty()\n\t\t\t.removeClass();\n\n\t\t// Attempt to restore focus to whichever element had it prior to opening the dialog.\n\t\tif (_lastActive !== null) {\n\t\t\tjQuery(_lastActive).focus();\n\t\t\t_lastActive = null;\n\t\t}\n\n\t\t// Call the given \"on close\" callback function, if any.\n\t\tif (ev && ev.data && typeof ev.data.closeFn === 'function') {\n\t\t\tev.data.closeFn(ev);\n\t\t}\n\n\t\t// Trigger a `:dialogclosed` event on the dialog body.\n\t\t/* legacy */\n\t\t_$dialogBody.trigger(':dialogclose');\n\t\t/* /legacy */\n\t\t_$dialogBody.trigger(':dialogclosed');\n\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogInit() {\n\t\tif (DEBUG) { console.log('[Dialog/dialogInit()]'); }\n\n\t\tif (document.getElementById('ui-dialog')) {\n\t\t\treturn;\n\t\t}\n\n\t\t/*\n\t\t\tCalculate and cache the width of scrollbars.\n\t\t*/\n\t\t_scrollbarWidth = (() => {\n\t\t\tlet scrollbarWidth;\n\n\t\t\ttry {\n\t\t\t\tconst inner = document.createElement('p');\n\t\t\t\tconst outer = document.createElement('div');\n\n\t\t\t\tinner.style.width      = '100%';\n\t\t\t\tinner.style.height     = '200px';\n\t\t\t\touter.style.position   = 'absolute';\n\t\t\t\touter.style.left       = '0px';\n\t\t\t\touter.style.top        = '0px';\n\t\t\t\touter.style.width      = '100px';\n\t\t\t\touter.style.height     = '100px';\n\t\t\t\touter.style.visibility = 'hidden';\n\t\t\t\touter.style.overflow   = 'hidden';\n\n\t\t\t\touter.appendChild(inner);\n\t\t\t\tdocument.body.appendChild(outer);\n\n\t\t\t\tconst w1 = inner.offsetWidth;\n\t\t\t\t/*\n\t\t\t\t\tThe `overflow: scroll` style property value does not work consistently\n\t\t\t\t\twith scrollbars which are styled with `::-webkit-scrollbar`, so we use\n\t\t\t\t\t`overflow: auto` with dimensions guaranteed to force a scrollbar.\n\t\t\t\t*/\n\t\t\t\touter.style.overflow = 'auto';\n\t\t\t\tlet w2 = inner.offsetWidth;\n\n\t\t\t\tif (w1 === w2) {\n\t\t\t\t\tw2 = outer.clientWidth;\n\t\t\t\t}\n\n\t\t\t\tdocument.body.removeChild(outer);\n\n\t\t\t\tscrollbarWidth = w1 - w2;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn scrollbarWidth || 17; // 17px is a reasonable failover\n\t\t})();\n\n\t\t/*\n\t\t\tGenerate the dialog elements.\n\t\t*/\n\t\tconst $elems = jQuery(document.createDocumentFragment())\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  '<div id=\"ui-overlay\" class=\"ui-close\"></div>'\n\t\t\t\t+ '<div id=\"ui-dialog\" tabindex=\"0\" role=\"dialog\" aria-labelledby=\"ui-dialog-title\">'\n\t\t\t\t+     '<div id=\"ui-dialog-titlebar\">'\n\t\t\t\t+         '<h1 id=\"ui-dialog-title\"></h1>'\n\t\t\t\t+         `<button id=\"ui-dialog-close\" class=\"ui-close\" tabindex=\"0\" aria-label=\"${L10n.get('close')}\">\\uE804</button>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div id=\"ui-dialog-body\"></div>'\n\t\t\t\t+ '</div>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t);\n\n\t\t/*\n\t\t\tCache the dialog elements, since they're going to be used often.\n\n\t\t\tNOTE: We rewrap the elements themselves, rather than simply using\n\t\t\tthe results of `find()`, so that we cache uncluttered jQuery-wrappers\n\t\t\t(i.e. `context` refers to the elements and there is no `prevObject`).\n\t\t*/\n\t\t_$overlay     = jQuery($elems.find('#ui-overlay').get(0));\n\t\t_$dialog      = jQuery($elems.find('#ui-dialog').get(0));\n\t\t_$dialogTitle = jQuery($elems.find('#ui-dialog-title').get(0));\n\t\t_$dialogBody  = jQuery($elems.find('#ui-dialog-body').get(0));\n\n\t\t/*\n\t\t\tInsert the dialog elements into the page before the main script.\n\t\t*/\n\t\t$elems.insertBefore('body>script#script-sugarcube');\n\t}\n\n\tfunction dialogIsOpen(classNames) {\n\t\treturn _$dialog.hasClass('open')\n\t\t\t&& (classNames ? classNames.splitOrEmpty(/\\s+/).every(cn => _$dialogBody.hasClass(cn)) : true);\n\t}\n\n\tfunction dialogOpen(options, closeFn) {\n\t\t// Trigger a `:dialogopening` event on the dialog body.\n\t\t_$dialogBody.trigger(':dialogopening');\n\n\t\t// Grab the options we care about.\n\t\tconst { top } = jQuery.extend({ top : 50 }, options);\n\n\t\t// Record the last active/focused non-dialog element.\n\t\tif (!dialogIsOpen()) {\n\t\t\t_lastActive = safeActiveElement();\n\t\t}\n\n\t\t// Add the `data-dialog` attribute to <html> (mostly used to style <body>).\n\t\tjQuery(document.documentElement)\n\t\t\t.attr('data-dialog', 'open');\n\n\t\t// Display the overlay.\n\t\t_$overlay\n\t\t\t.addClass('open');\n\n\t\t/*\n\t\t\tAdd the imagesLoaded handler to the dialog body, if necessary.\n\n\t\t\tNOTE: We use `querySelector()` here as jQuery has no simple way to\n\t\t\tcheck if, and only if, at least one element of the specified type\n\t\t\texists.  The best that jQuery offers is analogous to `querySelectorAll()`,\n\t\t\twhich enumerates all elements of the specified type.\n\t\t*/\n\t\tif (_$dialogBody[0].querySelector('img') !== null) {\n\t\t\t_$dialogBody\n\t\t\t\t.imagesLoaded()\n\t\t\t\t.always(() => _resizeHandler({ data : { top } }));\n\t\t}\n\n\t\t// Add `aria-hidden=true` to all direct non-dialog-children of <body> to\n\t\t// hide the underlying page from screen readers while the dialog is open.\n\t\tjQuery('body>:not(script,#store-area,tw-storydata,#ui-bar,#ui-overlay,#ui-dialog)')\n\t\t\t.attr('tabindex', -3)\n\t\t\t.attr('aria-hidden', true);\n\t\tjQuery('#ui-bar,#story')\n\t\t\t.find('[tabindex]:not([tabindex^=-])')\n\t\t\t.attr('tabindex', -2)\n\t\t\t.attr('aria-hidden', true);\n\n\t\t// Display the dialog.\n\t\t_$dialog\n\t\t\t.css(_calcPosition(top))\n\t\t\t.addClass('open')\n\t\t\t.focus();\n\n\t\t// Add the UI resize handler.\n\t\tjQuery(window)\n\t\t\t.on('resize.dialog-resize', null, { top }, jQuery.throttle(40, _resizeHandler));\n\n\t\t// Add the dialog mutation resize handler.\n\t\tif (Has.mutationObserver) {\n\t\t\t_dialogObserver = new MutationObserver(mutations => {\n\t\t\t\tfor (let i = 0; i < mutations.length; ++i) {\n\t\t\t\t\tif (mutations[i].type === 'childList') {\n\t\t\t\t\t\t_resizeHandler({ data : { top } });\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t_dialogObserver.observe(_$dialogBody[0], {\n\t\t\t\tchildList : true,\n\t\t\t\tsubtree   : true\n\t\t\t});\n\t\t}\n\t\telse {\n\t\t\t_$dialogBody\n\t\t\t\t.on(\n\t\t\t\t\t'DOMNodeInserted.dialog-resize DOMNodeRemoved.dialog-resize',\n\t\t\t\t\tnull,\n\t\t\t\t\t{ top },\n\t\t\t\t\tjQuery.throttle(40, _resizeHandler)\n\t\t\t\t);\n\t\t}\n\n\t\t// Set up the delegated UI close handler.\n\t\tjQuery(document)\n\t\t\t.on('click.dialog-close', '.ui-close', { closeFn }, dialogClose)\n\t\t\t.on('keypress.dialog-close', '.ui-close', function (ev) {\n\t\t\t\t// 13 is Enter/Return, 32 is Space.\n\t\t\t\tif (ev.which === 13 || ev.which === 32) {\n\t\t\t\t\tjQuery(this).trigger('click');\n\t\t\t\t}\n\t\t\t});\n\n\t\t// Trigger a `:dialogopened` event on the dialog body.\n\t\t/* legacy */\n\t\t_$dialogBody.trigger(':dialogopen');\n\t\t/* /legacy */\n\t\t_$dialogBody.trigger(':dialogopened');\n\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogResize(data) {\n\t\treturn _resizeHandler(typeof data === 'object' ? { data } : undefined);\n\t}\n\n\tfunction dialogSetup(title, classNames) {\n\t\t_$dialogBody\n\t\t\t.empty()\n\t\t\t.removeClass();\n\n\t\tif (classNames != null) { // lazy equality for null\n\t\t\t_$dialogBody.addClass(classNames);\n\t\t}\n\n\t\t_$dialogTitle\n\t\t\t.empty()\n\t\t\t.append((title != null ? String(title) : '') || '\\u00A0'); // lazy equality for null\n\n\t\t// TODO: In v3 this should return `Dialog` for chaining.\n\t\treturn _$dialogBody.get(0);\n\t}\n\n\tfunction dialogBodyWiki(...args) {\n\t\t_$dialogBody.wiki(...args);\n\t\treturn Dialog;\n\t}\n\n\n\t/*******************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************/\n\n\tfunction _calcPosition(topPos) {\n\t\tconst top       = topPos != null ? topPos : 50; // lazy equality for null\n\t\tconst $parent   = jQuery(window);\n\t\tconst dialogPos = { left : '', right : '', top : '', bottom : '' };\n\n\t\t// Unset the dialog's positional properties before checking its dimensions.\n\t\t_$dialog.css(dialogPos);\n\n\t\tlet horzSpace = $parent.width() - _$dialog.outerWidth(true) - 1;   // -1 to address a Firefox issue\n\t\tlet vertSpace = $parent.height() - _$dialog.outerHeight(true) - 1; // -1 to address a Firefox issue\n\n\t\tif (horzSpace <= 32 + _scrollbarWidth) {\n\t\t\tvertSpace -= _scrollbarWidth;\n\t\t}\n\n\t\tif (vertSpace <= 32 + _scrollbarWidth) {\n\t\t\thorzSpace -= _scrollbarWidth;\n\t\t}\n\n\t\tif (horzSpace <= 32) {\n\t\t\tdialogPos.left = dialogPos.right = 16;\n\t\t}\n\t\telse {\n\t\t\tdialogPos.left = dialogPos.right = horzSpace / 2 >> 0;\n\t\t}\n\n\t\tif (vertSpace <= 32) {\n\t\t\tdialogPos.top = dialogPos.bottom = 16;\n\t\t}\n\t\telse {\n\t\t\tif (vertSpace / 2 > top) {\n\t\t\t\tdialogPos.top = top;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdialogPos.top = dialogPos.bottom = vertSpace / 2 >> 0;\n\t\t\t}\n\t\t}\n\n\t\tObject.keys(dialogPos).forEach(key => {\n\t\t\tif (dialogPos[key] !== '') {\n\t\t\t\tdialogPos[key] += 'px';\n\t\t\t}\n\t\t});\n\n\t\treturn dialogPos;\n\t}\n\n\tfunction _resizeHandler(ev) {\n\t\tconst top = ev && ev.data && typeof ev.data.top !== 'undefined' ? ev.data.top : 50;\n\n\t\tif (_$dialog.css('display') === 'block') {\n\t\t\t// Stow the dialog.\n\t\t\t_$dialog.css({ display : 'none' });\n\n\t\t\t// Restore the dialog with its new positional properties.\n\t\t\t_$dialog.css(jQuery.extend({ display : '' }, _calcPosition(top)));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tappend : { value : dialogBodyAppend },\n\t\tbody   : { value : dialogBody },\n\t\tclose  : { value : dialogClose },\n\t\tinit   : { value : dialogInit },\n\t\tisOpen : { value : dialogIsOpen },\n\t\topen   : { value : dialogOpen },\n\t\tresize : { value : dialogResize },\n\t\tsetup  : { value : dialogSetup },\n\t\twiki   : { value : dialogBodyWiki },\n\n\t\t// Legacy Functions.\n\t\taddClickHandler : { value : dialogAddClickHandler }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tengine.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Config, DebugView, Dialog, Has, LoadScreen, Save, State, Story, StyleWrapper, UI, UIBar, Util,\n\t       Wikifier, postdisplay, postrender, predisplay, prehistory, prerender, setDisplayTitle\n*/\n\nvar Engine = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Engine state types object (pseudo-enumeration).\n\tconst States = Util.toEnum({\n\t\tIdle      : 'idle',\n\t\tPlaying   : 'playing',\n\t\tRendering : 'rendering'\n\t});\n\n\t// Minimum delay for DOM actions (in milliseconds).\n\tconst minDomActionDelay = 40;\n\n\t// Current state of the engine (default: `Engine.States.Idle`).\n\tlet _state = States.Idle;\n\n\t// Last time `enginePlay()` was called (in milliseconds).\n\tlet _lastPlay = null;\n\n\t// Cache of the debug view for the StoryInit special passage.\n\tlet _storyInitDebugView = null;\n\n\t// Cache of the outline patching <style> element (`StyleWrapper`-wrapped).\n\tlet _outlinePatch = null;\n\n\t// List of objects describing `StoryInterface` elements to update via passages during navigation.\n\tlet _updating = null;\n\n\n\t/*******************************************************************************************************************\n\t\tEngine Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tInitialize the core story elements and perform some bookkeeping.\n\t*/\n\tfunction engineInit() {\n\t\tif (DEBUG) { console.log('[Engine/engineInit()]'); }\n\n\t\t/*\n\t\t\tRemove #init-no-js & #init-lacking from #init-screen.\n\t\t*/\n\t\tjQuery('#init-no-js,#init-lacking').remove();\n\n\t\t/*\n\t\t\tGenerate the core story elements and insert them into the page before the store area.\n\t\t*/\n\t\t(() => {\n\t\t\tconst $elems = jQuery(document.createDocumentFragment());\n\t\t\tconst markup = Story.has('StoryInterface') && Story.get('StoryInterface').text.trim();\n\n\t\t\tif (markup) {\n\t\t\t\t// Remove the UI bar, its styles, and events.\n\t\t\t\tUIBar.destroy();\n\n\t\t\t\t// Remove the core display area styles.\n\t\t\t\tjQuery(document.head).find('#style-core-display').remove();\n\n\t\t\t\t$elems.append(markup);\n\n\t\t\t\tif ($elems.find('#passages').length === 0) {\n\t\t\t\t\tthrow new Error('no element with ID \"passages\" found within \"StoryInterface\" special passage');\n\t\t\t\t}\n\n\t\t\t\tconst updating = [];\n\n\t\t\t\t$elems.find('[data-passage]').each((i, el) => {\n\t\t\t\t\tif (el.id === 'passages') {\n\t\t\t\t\t\tthrow new Error(`\"StoryInterface\" element <${el.nodeName.toLowerCase()} id=\"passages\"> must not contain a \"data-passage\" content attribute`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst passage = el.getAttribute('data-passage').trim();\n\n\t\t\t\t\tif (el.firstElementChild !== null) {\n\t\t\t\t\t\tthrow new Error(`\"StoryInterface\" element <${el.nodeName.toLowerCase()} data-passage=\"${passage}\"> contains child elements`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tupdating.push({\n\t\t\t\t\t\t\tpassage,\n\t\t\t\t\t\t\telement : el\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (updating.length > 0) {\n\t\t\t\t\t_updating = updating;\n\t\t\t\t}\n\n\t\t\t\tConfig.ui.updateStoryElements = false;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$elems.append('<div id=\"story\" role=\"main\"><div id=\"passages\"></div></div>');\n\t\t\t}\n\n\t\t\t// Insert the core UI elements into the page before the main script.\n\t\t\t$elems.insertBefore('body>script#script-sugarcube');\n\t\t})();\n\n\t\t/*\n\t\t\tGenerate and cache the ARIA outlines <style> element (`StyleWrapper`-wrapped)\n\t\t\tand set up the handler to manipulate the outlines.\n\n\t\t\tIDEA: http://www.paciellogroup.com/blog/2012/04/how-to-remove-css-outlines-in-an-accessible-manner/\n\t\t*/\n\t\t_outlinePatch = new StyleWrapper((\n\t\t\t() => jQuery(document.createElement('style'))\n\t\t\t\t.attr({\n\t\t\t\t\tid   : 'style-aria-outlines',\n\t\t\t\t\ttype : 'text/css'\n\t\t\t\t})\n\t\t\t\t.appendTo(document.head)\n\t\t\t\t.get(0) // return the <style> element itself\n\t\t)());\n\t\tlet _lastOutlineEvent;\n\t\tjQuery(document).on(\n\t\t\t'mousedown.aria-outlines keydown.aria-outlines',\n\t\t\tev => {\n\t\t\t\tif (ev.type !== _lastOutlineEvent) {\n\t\t\t\t\t_lastOutlineEvent = ev.type;\n\n\t\t\t\t\tif (ev.type === 'keydown') {\n\t\t\t\t\t\t_showOutlines();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t_hideOutlines();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\t/*\n\t\tStarts the story.\n\t*/\n\tfunction engineStart() {\n\t\tif (DEBUG) { console.log('[Engine/engineStart()]'); }\n\n\t\t/*\n\t\t\tExecute the StoryInit special passage.\n\t\t*/\n\t\tif (Story.has('StoryInit')) {\n\t\t\ttry {\n\t\t\t\tconst debugBuffer = Wikifier.wikifyEval(Story.get('StoryInit').text);\n\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tconst debugView = new DebugView(\n\t\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t\t'special',\n\t\t\t\t\t\t'StoryInit',\n\t\t\t\t\t\t'StoryInit'\n\t\t\t\t\t);\n\t\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\t\tdebugView.append(debugBuffer);\n\t\t\t\t\t_storyInitDebugView = debugView.output;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('StoryInit', ex.message);\n\t\t\t}\n\t\t}\n\n\t\t// Sanity checks.\n\t\tif (Config.passages.start == null) { // lazy equality for null\n\t\t\tthrow new Error('starting passage not selected');\n\t\t}\n\t\tif (!Story.has(Config.passages.start)) {\n\t\t\tthrow new Error(`starting passage (\"${Config.passages.start}\") not found`);\n\t\t}\n\n\t\t// Focus the document element initially.\n\t\tjQuery(document.documentElement).focus();\n\n\t\t/*\n\t\t\tAttempt to restore an active session.  Failing that, attempt to autoload the autosave,\n\t\t\tif requested.  Failing that, display the starting passage.\n\t\t*/\n\t\tif (State.restore()) {\n\t\t\tengineShow();\n\t\t}\n\t\telse {\n\t\t\tlet loadStart = true;\n\n\t\t\tswitch (typeof Config.saves.autoload) {\n\t\t\tcase 'boolean':\n\t\t\t\tif (Config.saves.autoload && Save.autosave.ok() && Save.autosave.has()) {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\t\tloadStart = !Save.autosave.load();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'string':\n\t\t\t\tif (Config.saves.autoload === 'prompt' && Save.autosave.ok() && Save.autosave.has()) {\n\t\t\t\t\tloadStart = false;\n\t\t\t\t\tUI.buildAutoload();\n\t\t\t\t\tDialog.open();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'function':\n\t\t\t\tif (Save.autosave.ok() && Save.autosave.has() && !!Config.saves.autoload()) {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\t\tloadStart = !Save.autosave.load();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (loadStart) {\n\t\t\t\tif (DEBUG) { console.log(`\\tstarting passage: \"${Config.passages.start}\"`); }\n\n\t\t\t\tenginePlay(Config.passages.start);\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t\tRestarts the story.\n\t*/\n\tfunction engineRestart() {\n\t\tif (DEBUG) { console.log('[Engine/engineRestart()]'); }\n\n\t\t/*\n\t\t\tShow the loading screen to hide any unsightly rendering shenanigans during the\n\t\t\tpage reload.\n\t\t*/\n\t\tLoadScreen.show();\n\n\t\t/*\n\t\t\tScroll the window to the top.\n\n\t\t\tThis is required by most browsers for the starting passage or it will remain at\n\t\t\twhatever its current scroll position is after the page reload.  We do it generally,\n\t\t\trather than only for the currently set starting passage, since the starting passage\n\t\t\tmay be dynamically manipulated.\n\t\t*/\n\t\twindow.scroll(0, 0);\n\n\t\t/*\n\t\t\tDelete the active session.\n\t\t*/\n\t\tState.reset();\n\n\t\t/*\n\t\t\tTrigger an ':enginerestart' event.\n\t\t*/\n\t\tjQuery.event.trigger(':enginerestart');\n\n\t\t/*\n\t\t\tReload the page.\n\t\t*/\n\t\twindow.location.reload();\n\t}\n\n\t/*\n\t\tReturns the current state of the engine.\n\t*/\n\tfunction engineState() {\n\t\treturn _state;\n\t}\n\n\t/*\n\t\tReturns whether the engine is idle.\n\t*/\n\tfunction engineIsIdle() {\n\t\treturn _state === States.Idle;\n\t}\n\n\t/*\n\t\tReturns whether the engine is playing.\n\t*/\n\tfunction engineIsPlaying() {\n\t\treturn _state !== States.Idle;\n\t}\n\n\t/*\n\t\tReturns whether the engine is rendering.\n\t*/\n\tfunction engineIsRendering() {\n\t\treturn _state === States.Rendering;\n\t}\n\n\t/*\n\t\tReturns a timestamp representing the last time `Engine.play()` was called.\n\t*/\n\tfunction engineLastPlay() {\n\t\treturn _lastPlay;\n\t}\n\n\t/*\n\t\tActivate the moment at the given index within the state history and show it.\n\t*/\n\tfunction engineGoTo(idx) {\n\t\tconst succeded = State.goTo(idx);\n\n\t\tif (succeded) {\n\t\t\tengineShow();\n\t\t}\n\n\t\treturn succeded;\n\t}\n\n\t/*\n\t\tActivate the moment at the given offset from the active moment within the state history\n\t\tand show it.\n\t*/\n\tfunction engineGo(offset) {\n\t\tconst succeded = State.go(offset);\n\n\t\tif (succeded) {\n\t\t\tengineShow();\n\t\t}\n\n\t\treturn succeded;\n\t}\n\n\t/*\n\t\tGo to the moment which directly precedes the active moment and show it.\n\t*/\n\tfunction engineBackward() {\n\t\treturn engineGo(-1);\n\t}\n\n\t/*\n\t\tGo to the moment which directly follows the active moment and show it.\n\t*/\n\tfunction engineForward() {\n\t\treturn engineGo(1);\n\t}\n\n\t/*\n\t\tRenders and displays the active (present) moment's associated passage without adding\n\t\ta new moment to the history.\n\t*/\n\tfunction engineShow() {\n\t\treturn enginePlay(State.passage, true);\n\t}\n\n\t/*\n\t\tRenders and displays the passage referenced by the given title, optionally without\n\t\tadding a new moment to the history.\n\t*/\n\tfunction enginePlay(title, noHistory) {\n\t\tif (DEBUG) { console.log(`[Engine/enginePlay(title: \"${title}\", noHistory: ${noHistory})]`); }\n\n\t\tlet passageTitle = title;\n\n\t\t// Update the engine state.\n\t\t_state = States.Playing;\n\n\t\t// Reset the temporary state and variables objects.\n\t\tTempState = {}; // eslint-disable-line no-undef\n\t\tState.clearTemporary();\n\n\t\t// Debug view setup.\n\t\tlet passageReadyOutput;\n\t\tlet passageDoneOutput;\n\n\t\t// Execute the navigation override callback.\n\t\tif (typeof Config.navigation.override === 'function') {\n\t\t\ttry {\n\t\t\t\tconst overrideTitle = Config.navigation.override(passageTitle);\n\n\t\t\t\tif (overrideTitle) {\n\t\t\t\t\tpassageTitle = overrideTitle;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\t\t}\n\n\t\t// Retrieve the passage by the given title.\n\t\t//\n\t\t// NOTE: The values of the `title` parameter and `passageTitle` variable\n\t\t// may be empty, strings, or numbers (though using a number as reference\n\t\t// to a numeric title should be discouraged), so after loading the passage,\n\t\t// always refer to `passage.title` and never to the others.\n\t\tconst passage = Story.get(passageTitle);\n\n\t\t// Execute the pre-history events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype : ':passageinit',\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(prehistory).forEach(task => {\n\t\t\tif (typeof prehistory[task] === 'function') {\n\t\t\t\tprehistory[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\t// Create a new entry in the history.\n\t\tif (!noHistory) {\n\t\t\tState.create(passage.title);\n\t\t}\n\n\t\t// Clear the document body's classes.\n\t\tif (document.body.className) {\n\t\t\tdocument.body.className = '';\n\t\t}\n\n\t\t// Update the last play time.\n\t\t//\n\t\t// NOTE: This is mostly for event, task, and special passage code,\n\t\t// though the likelihood of it being needed this early is low.  This\n\t\t// will be updated again later at the end.\n\t\t_lastPlay = Util.now();\n\n\t\t// Execute pre-display tasks and the `PassageReady` special passage.\n\t\tObject.keys(predisplay).forEach(task => {\n\t\t\tif (typeof predisplay[task] === 'function') {\n\t\t\t\tpredisplay[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\tif (Story.has('PassageReady')) {\n\t\t\ttry {\n\t\t\t\tpassageReadyOutput = Wikifier.wikifyEval(Story.get('PassageReady').text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('PassageReady', ex.message);\n\t\t\t}\n\t\t}\n\n\t\t// Update the engine state.\n\t\t_state = States.Rendering;\n\n\t\t// Get the passage's tags as a string, or `null` if there aren't any.\n\t\tconst dataTags = passage.tags.length > 0 ? passage.tags.join(' ') : null;\n\n\t\t// Create and set up the incoming passage element.\n\t\tconst passageEl = document.createElement('div');\n\t\tjQuery(passageEl)\n\t\t\t.attr({\n\t\t\t\tid             : passage.domId,\n\t\t\t\t'data-passage' : passage.title,\n\t\t\t\t'data-tags'    : dataTags\n\t\t\t})\n\t\t\t.addClass(`passage ${passage.className}`);\n\n\t\t// Add the passage's classes and tags to the document body.\n\t\tjQuery(document.body)\n\t\t\t.attr('data-tags', dataTags)\n\t\t\t.addClass(passage.className);\n\n\t\t// Add the passage's tags to the document element.\n\t\tjQuery(document.documentElement)\n\t\t\t.attr('data-tags', dataTags);\n\n\t\t// Execute pre-render events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagestart',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(prerender).forEach(task => {\n\t\t\tif (typeof prerender[task] === 'function') {\n\t\t\t\tprerender[task].call(passage, passageEl, task);\n\t\t\t}\n\t\t});\n\n\t\t// Render the `PassageHeader` passage, if it exists, into the passage element.\n\t\tif (Story.has('PassageHeader')) {\n\t\t\tnew Wikifier(passageEl, Story.get('PassageHeader').processText());\n\t\t}\n\n\t\t// Render the passage into its element.\n\t\tpassageEl.appendChild(passage.render());\n\n\t\t// Render the `PassageFooter` passage, if it exists, into the passage element.\n\t\tif (Story.has('PassageFooter')) {\n\t\t\tnew Wikifier(passageEl, Story.get('PassageFooter').processText());\n\t\t}\n\n\t\t// Execute post-render events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagerender',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(postrender).forEach(task => {\n\t\t\tif (typeof postrender[task] === 'function') {\n\t\t\t\tpostrender[task].call(passage, passageEl, task);\n\t\t\t}\n\t\t});\n\n\t\t// Cache the passage container.\n\t\tconst containerEl = document.getElementById('passages');\n\n\t\t// Empty the passage container.\n\t\tif (containerEl.hasChildNodes()) {\n\t\t\tif (\n\t\t\t\t   typeof Config.passages.transitionOut === 'number'\n\t\t\t\t|| typeof Config.passages.transitionOut === 'string'\n\t\t\t\t&& Config.passages.transitionOut !== ''\n\t\t\t\t&& Has.transitionEndEvent\n\t\t\t) {\n\t\t\t\t[...containerEl.childNodes].forEach(outgoing => {\n\t\t\t\t\tconst $outgoing = jQuery(outgoing);\n\n\t\t\t\t\tif (outgoing.nodeType === Node.ELEMENT_NODE && $outgoing.hasClass('passage')) {\n\t\t\t\t\t\tif ($outgoing.hasClass('passage-out')) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$outgoing\n\t\t\t\t\t\t\t.attr('id', `out-${$outgoing.attr('id')}`)\n\t\t\t\t\t\t\t.addClass('passage-out');\n\n\t\t\t\t\t\tif (typeof Config.passages.transitionOut === 'string') {\n\t\t\t\t\t\t\t$outgoing.on(Has.transitionEndEvent, ev => {\n\t\t\t\t\t\t\t\tif (ev.originalEvent.propertyName === Config.passages.transitionOut) {\n\t\t\t\t\t\t\t\t\t$outgoing.remove();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tsetTimeout(\n\t\t\t\t\t\t\t\t() => $outgoing.remove(),\n\t\t\t\t\t\t\t\tMath.max(minDomActionDelay, Config.passages.transitionOut)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t$outgoing.remove();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery(containerEl).empty();\n\t\t\t}\n\t\t}\n\n\t\t// Append the passage element to the passage container and set up its transition.\n\t\tjQuery(passageEl)\n\t\t\t.addClass('passage-in')\n\t\t\t.appendTo(containerEl);\n\t\tsetTimeout(() => jQuery(passageEl).removeClass('passage-in'), minDomActionDelay);\n\n\t\t// Update the story display title, if necessary.\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\t// NOTE: We don't have an `else` here because that case will be handled later (below).\n\t\t\tif (_updating !== null || !Config.ui.updateStoryElements) {\n\t\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t\t}\n\t\t}\n\t\telse if (Config.passages.displayTitles && passage.title !== Config.passages.start) {\n\t\t\tdocument.title = `${passage.title} | ${Story.title}`;\n\t\t}\n\n\t\t// Scroll the window to the top.\n\t\twindow.scroll(0, 0);\n\n\t\t// Update the engine state.\n\t\t_state = States.Playing;\n\n\t\t// Execute post-display events, tasks, and the `PassageDone` special passage.\n\t\tif (Story.has('PassageDone')) {\n\t\t\ttry {\n\t\t\t\tpassageDoneOutput = Wikifier.wikifyEval(Story.get('PassageDone').text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('PassageDone', ex.message);\n\t\t\t}\n\t\t}\n\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagedisplay',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(postdisplay).forEach(task => {\n\t\t\tif (typeof postdisplay[task] === 'function') {\n\t\t\t\tpostdisplay[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\t// Update the other interface elements, if necessary.\n\t\tif (_updating !== null) {\n\t\t\t_updating.forEach(pair => {\n\t\t\t\tjQuery(pair.element).empty();\n\t\t\t\tnew Wikifier(pair.element, Story.get(pair.passage).processText().trim());\n\t\t\t});\n\t\t}\n\t\telse if (Config.ui.updateStoryElements) {\n\t\t\tUIBar.update();\n\t\t}\n\n\t\t// Add the completed debug views for `StoryInit`, `PassageReady`, and `PassageDone`\n\t\t// to the incoming passage element.\n\t\tif (Config.debug) {\n\t\t\tlet debugView;\n\n\t\t\t// Prepend the `PassageReady` debug view.\n\t\t\tif (passageReadyOutput != null) { // lazy equality for null\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t'special',\n\t\t\t\t\t'PassageReady',\n\t\t\t\t\t'PassageReady'\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\tdebugView.append(passageReadyOutput);\n\t\t\t\tjQuery(passageEl).prepend(debugView.output);\n\t\t\t}\n\n\t\t\t// Append the `PassageDone` debug view.\n\t\t\tif (passageDoneOutput != null) { // lazy equality for null\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t'special',\n\t\t\t\t\t'PassageDone',\n\t\t\t\t\t'PassageDone'\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\tdebugView.append(passageDoneOutput);\n\t\t\t\tjQuery(passageEl).append(debugView.output);\n\t\t\t}\n\n\t\t\t// Prepend the cached `StoryInit` debug view, if we're showing the first moment/turn.\n\t\t\tif (State.turns === 1 && _storyInitDebugView != null) { // lazy equality for null\n\t\t\t\tjQuery(passageEl).prepend(_storyInitDebugView);\n\t\t\t}\n\t\t}\n\n\t\t// Last second post-processing for accessibility and other things.\n\t\t_hideOutlines(); // initially hide outlines\n\t\tjQuery('#story')\n\t\t\t// Add `link-external` to all `href` bearing `<a>` elements which don't have it.\n\t\t\t.find('a[href]:not(.link-external)')\n\t\t\t.addClass('link-external')\n\t\t\t.end()\n\t\t\t// Add `tabindex=0` to all interactive elements which don't have it.\n\t\t\t.find('a,link,button,input,select,textarea')\n\t\t\t.not('[tabindex]')\n\t\t\t.attr('tabindex', 0);\n\n\t\t// Handle autosaves.\n\t\tswitch (typeof Config.saves.autosave) {\n\t\tcase 'boolean':\n\t\t\tif (Config.saves.autosave) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'object':\n\t\t\tif (passage.tags.some(tag => Config.saves.autosave.includes(tag))) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'function':\n\t\t\tif (Config.saves.autosave()) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// Execute post-play events.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passageend',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\n\t\t// Reset the engine state.\n\t\t_state = States.Idle;\n\n\t\t// Update the last play time.\n\t\t_lastPlay = Util.now();\n\n\t\treturn passageEl;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tLegacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Play the given passage, optionally without altering the history.\n\t*/\n\tfunction engineDisplay(title, link, option) {\n\t\tif (DEBUG) { console.log('[Engine/engineDisplay()]'); }\n\n\t\tlet noHistory = false;\n\n\t\t// Process the option parameter.\n\t\tswitch (option) {\n\t\tcase undefined:\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'replace':\n\t\tcase 'back':\n\t\t\tnoHistory = true;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new Error(`Engine.display option parameter called with obsolete value \"${option}\"; please notify the developer`);\n\t\t}\n\n\t\tenginePlay(title, noHistory);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _hideOutlines() {\n\t\t_outlinePatch.set('*:focus{outline:none;}');\n\t}\n\n\tfunction _showOutlines() {\n\t\t_outlinePatch.clear();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tConstants.\n\t\t*/\n\t\tStates            : { value : States },\n\t\tminDomActionDelay : { value : minDomActionDelay },\n\n\t\t/*\n\t\t\tCore Functions.\n\t\t*/\n\t\tinit        : { value : engineInit },\n\t\tstart       : { value : engineStart },\n\t\trestart     : { value : engineRestart },\n\t\tstate       : { get : engineState },\n\t\tisIdle      : { value : engineIsIdle },\n\t\tisPlaying   : { value : engineIsPlaying },\n\t\tisRendering : { value : engineIsRendering },\n\t\tlastPlay    : { get : engineLastPlay },\n\t\tgoTo        : { value : engineGoTo },\n\t\tgo          : { value : engineGo },\n\t\tbackward    : { value : engineBackward },\n\t\tforward     : { value : engineForward },\n\t\tshow        : { value : engineShow },\n\t\tplay        : { value : enginePlay },\n\n\t\t/*\n\t\t\tLegacy Functions.\n\t\t*/\n\t\tdisplay : { value : engineDisplay }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tpassage.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, L10n, Util, Wikifier */\n\nvar Passage = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tlet _tagsToSkip;\n\tlet _twine1Unescape;\n\n\t/*\n\t\tTags which should not be transformed into classes:\n\t\t\tdebug      → special tag\n\t\t\tnobr       → special tag\n\t\t\tpassage    → the default class\n\t\t\tscript     → special tag (only in Twine 1)\n\t\t\tstylesheet → special tag (only in Twine 1)\n\t\t\ttwine.*    → special tag\n\t\t\twidget     → special tag\n\t*/\n\t// For Twine 1\n\tif (TWINE1) {\n\t\t_tagsToSkip = /^(?:debug|nobr|passage|script|stylesheet|widget|twine\\..*)$/i;\n\t}\n\t// For Twine 2\n\telse {\n\t\t_tagsToSkip = /^(?:debug|nobr|passage|widget|twine\\..*)$/i;\n\t}\n\n\t// For Twine 1\n\tif (TWINE1) {\n\t\t/*\n\t\t\tReturns a decoded version of the passed Twine 1 passage store encoded string.\n\t\t*/\n\t\tconst _twine1EscapesRe    = /(?:\\\\n|\\\\t|\\\\s|\\\\|\\r)/g;\n\t\tconst _hasTwine1EscapesRe = new RegExp(_twine1EscapesRe.source); // to drop the global flag\n\t\tconst _twine1EscapesMap   = Object.freeze({\n\t\t\t'\\\\n' : '\\n',\n\t\t\t'\\\\t' : '\\t',\n\t\t\t'\\\\s' : '\\\\',\n\t\t\t'\\\\'  : '\\\\',\n\t\t\t'\\r'  : ''\n\t\t});\n\n\t\t_twine1Unescape = function (str) {\n\t\t\tif (str == null) { // lazy equality for null\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tconst val = String(str);\n\t\t\treturn val && _hasTwine1EscapesRe.test(val)\n\t\t\t\t? val.replace(_twine1EscapesRe, esc => _twine1EscapesMap[esc])\n\t\t\t\t: val;\n\t\t};\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPassage Class.\n\t*******************************************************************************************************************/\n\tclass Passage {\n\t\tconstructor(title, el) {\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// Passage title/ID.\n\t\t\t\ttitle : {\n\t\t\t\t\tvalue : Util.unescape(title)\n\t\t\t\t},\n\n\t\t\t\t// Passage data element (within the story data element; i.e. T1: '[tiddler]', T2: 'tw-passagedata').\n\t\t\t\telement : {\n\t\t\t\t\tvalue : el || null\n\t\t\t\t},\n\n\t\t\t\t// Passage tags array (sorted and unique).\n\t\t\t\ttags : {\n\t\t\t\t\tvalue : Object.freeze(el && el.hasAttribute('tags')\n\t\t\t\t\t\t? el.getAttribute('tags')\n\t\t\t\t\t\t\t.trim()\n\t\t\t\t\t\t\t.splitOrEmpty(/\\s+/)\n\t\t\t\t\t\t\t.sort()\n\t\t\t\t\t\t\t.filter((tag, i, aref) => i === 0 || aref[i - 1] !== tag)\n\t\t\t\t\t\t: [])\n\t\t\t\t},\n\n\t\t\t\t// Passage excerpt.  Used by the `description()` method.\n\t\t\t\t_excerpt : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Properties dependant upon the above set.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// Passage DOM-compatible ID.\n\t\t\t\tdomId : {\n\t\t\t\t\tvalue : `passage-${Util.slugify(this.title)}`\n\t\t\t\t},\n\n\t\t\t\t// Passage classes array (sorted and unique).\n\t\t\t\tclasses : {\n\t\t\t\t\tvalue : Object.freeze(this.tags.length === 0 ? [] : (() =>\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tReturn the sorted list of unique classes.\n\n\t\t\t\t\t\t\tNOTE: The `this.tags` array is already sorted and unique,\n\t\t\t\t\t\t\tso we only need to filter and map here.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tthis.tags\n\t\t\t\t\t\t\t.filter(tag => !_tagsToSkip.test(tag))\n\t\t\t\t\t\t\t.map(tag => Util.slugify(tag))\n\t\t\t\t\t)())\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// Getters.\n\t\tget className() {\n\t\t\treturn this.classes.join(' ');\n\t\t}\n\n\t\t// TODO: (v3) This should be → `get source`.\n\t\tget text() {\n\t\t\tif (this.element == null) { // lazy equality for null\n\t\t\t\tconst passage = Util.escape(this.title);\n\t\t\t\tconst mesg    = `${L10n.get('errorTitle')}: ${L10n.get('errorNonexistentPassage', { passage })}`;\n\t\t\t\treturn `<div class=\"error-view\"><span class=\"error\">${mesg}</span></div>`;\n\t\t\t}\n\n\t\t\t// For Twine 1\n\t\t\tif (TWINE1) {\n\t\t\t\treturn _twine1Unescape(this.element.textContent);\n\t\t\t}\n\t\t\t// For Twine 2\n\t\t\telse { // eslint-disable-line no-else-return\n\t\t\t\treturn this.element.textContent.replace(/\\r/g, '');\n\t\t\t}\n\t\t}\n\n\t\tdescription() {\n\t\t\tconst descriptions = Config.passages.descriptions;\n\n\t\t\tif (descriptions != null) { // lazy equality for null\n\t\t\t\tswitch (typeof descriptions) {\n\t\t\t\tcase 'boolean':\n\t\t\t\t\tif (descriptions) {\n\t\t\t\t\t\treturn this.title;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\tif (descriptions instanceof Map && descriptions.has(this.title)) {\n\t\t\t\t\t\treturn descriptions.get(this.title);\n\t\t\t\t\t}\n\t\t\t\t\telse if (descriptions.hasOwnProperty(this.title)) {\n\t\t\t\t\t\treturn descriptions[this.title];\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'function':\n\t\t\t\t\t{\n\t\t\t\t\t\tconst result = descriptions.call(this);\n\n\t\t\t\t\t\tif (result) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new TypeError('Config.passages.descriptions must be a boolean, object, or function');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Initialize the excerpt cache from the raw passage text, if necessary.\n\t\t\tif (this._excerpt === null) {\n\t\t\t\tthis._excerpt = Passage.getExcerptFromText(this.text);\n\t\t\t}\n\n\t\t\treturn this._excerpt;\n\t\t}\n\n\t\t// TODO: (v3) This should be → `get text`.\n\t\tprocessText() {\n\t\t\tif (this.element == null) { // lazy equality for null\n\t\t\t\treturn this.text;\n\t\t\t}\n\n\t\t\t// Handle image passage transclusion.\n\t\t\tif (this.tags.includes('Twine.image')) {\n\t\t\t\treturn `[img[${this.text}]]`;\n\t\t\t}\n\n\t\t\tlet processed = this.text;\n\n\t\t\t// Handle `Config.passages.onProcess`.\n\t\t\tif (Config.passages.onProcess) {\n\t\t\t\tprocessed = Config.passages.onProcess.call(null, {\n\t\t\t\t\ttitle : this.title,\n\t\t\t\t\ttags  : this.tags,\n\t\t\t\t\ttext  : processed\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Handle `Config.passages.nobr` and the `nobr` tag.\n\t\t\tif (Config.passages.nobr || this.tags.includes('nobr')) {\n\t\t\t\t// Remove all leading & trailing newlines and compact all internal sequences\n\t\t\t\t// of newlines into single spaces.\n\t\t\t\tprocessed = processed.replace(/^\\n+|\\n+$/g, '').replace(/\\n+/g, ' ');\n\t\t\t}\n\n\t\t\treturn processed;\n\t\t}\n\n\t\trender(options) {\n\t\t\t// Wikify the passage into a document fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, this.processText(), options);\n\n\t\t\t// Update the excerpt cache to reflect the rendered text, if we need it for the passage description\n\t\t\tif (Config.passages.descriptions == null) {\n\t\t\t\tthis._excerpt = Passage.getExcerptFromNode(frag);\n\t\t\t}\n\n\t\t\treturn frag;\n\t\t}\n\n\t\tstatic getExcerptFromNode(node, count) {\n\t\t\tif (!node.hasChildNodes()) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tlet excerpt = node.textContent.trim();\n\n\t\t\tif (excerpt !== '') {\n\t\t\t\tconst excerptRe = new RegExp(`(\\\\S+(?:\\\\s+\\\\S+){0,${count > 0 ? count - 1 : 7}})`);\n\t\t\t\texcerpt = excerpt\n\t\t\t\t\t// Compact whitespace.\n\t\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t\t// Attempt to match the excerpt regexp.\n\t\t\t\t\t.match(excerptRe);\n\t\t\t}\n\n\t\t\treturn excerpt ? `${excerpt[1]}\\u2026` : '\\u2026'; // horizontal ellipsis\n\t\t}\n\n\t\tstatic getExcerptFromText(text, count) {\n\t\t\tif (text === '') {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tconst excerptRe = new RegExp(`(\\\\S+(?:\\\\s+\\\\S+){0,${count > 0 ? count - 1 : 7}})`);\n\t\t\tconst excerpt   = text\n\t\t\t\t// Strip macro tags (replace with a space).\n\t\t\t\t.replace(/<<.*?>>/g, ' ')\n\t\t\t\t// Strip html tags (replace with a space).\n\t\t\t\t.replace(/<.*?>/g, ' ')\n\t\t\t\t// The above might have left problematic whitespace, so trim.\n\t\t\t\t.trim()\n\t\t\t\t// Strip table markup.\n\t\t\t\t.replace(/^\\s*\\|.*\\|.*?$/gm, '')\n\t\t\t\t// Strip image markup.\n\t\t\t\t.replace(/\\[[<>]?img\\[[^\\]]*\\]\\]/g, '')\n\t\t\t\t// Clean link markup (remove all but the link text).\n\t\t\t\t.replace(/\\[\\[([^|\\]]*?)(?:(?:\\||->|<-)[^\\]]*)?\\]\\]/g, '$1')\n\t\t\t\t// Clean heading markup.\n\t\t\t\t.replace(/^\\s*!+(.*?)$/gm, '$1')\n\t\t\t\t// Clean bold/italic/underline/highlight styles.\n\t\t\t\t.replace(/'{2}|\\/{2}|_{2}|@{2}/g, '')\n\t\t\t\t// A final trim.\n\t\t\t\t.trim()\n\t\t\t\t// Compact whitespace.\n\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t// Attempt to match the excerpt regexp.\n\t\t\t\t.match(excerptRe);\n\t\t\treturn excerpt ? `${excerpt[1]}\\u2026` : '\\u2026'; // horizontal ellipsis\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Passage;\n})();\n\n/***********************************************************************************************************************\n\n\tsave.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Dialog, Engine, L10n, State, Story, UI, storage */\n\nvar Save = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// The upper bound of the saves slots.\n\tlet _slotsUBound = -1;\n\n\n\t/*******************************************************************************************************************\n\t\tSaves Functions.\n\t*******************************************************************************************************************/\n\tfunction savesInit() {\n\t\tif (DEBUG) { console.log('[Save/savesInit()]'); }\n\n\t\t// Disable save slots and the autosave when Web Storage is unavailable.\n\t\tif (storage.name === 'cookie') {\n\t\t\tsavesObjClear();\n\t\t\tConfig.saves.autoload = undefined;\n\t\t\tConfig.saves.autosave = undefined;\n\t\t\tConfig.saves.slots = 0;\n\t\t\treturn false;\n\t\t}\n\n\t\tlet saves   = savesObjGet();\n\t\tlet updated = false;\n\n\t\t/* legacy */\n\t\t// Convert an ancient saves array into a new saves object.\n\t\tif (Array.isArray(saves)) {\n\t\t\tsaves = {\n\t\t\t\tautosave : null,\n\t\t\t\tslots    : saves\n\t\t\t};\n\t\t\tupdated = true;\n\t\t}\n\t\t/* /legacy */\n\n\t\t// Handle the author changing the number of save slots.\n\t\tif (Config.saves.slots !== saves.slots.length) {\n\t\t\tif (Config.saves.slots < saves.slots.length) {\n\t\t\t\t// Attempt to decrease the number of slots; this will only compact\n\t\t\t\t// the slots array, by removing empty slots, no saves will be deleted.\n\t\t\t\tsaves.slots.reverse();\n\n\t\t\t\tsaves.slots = saves.slots.filter(function (val) {\n\t\t\t\t\tif (val === null && this.count > 0) {\n\t\t\t\t\t\t--this.count;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\t\t\t\t}, { count : saves.slots.length - Config.saves.slots });\n\n\t\t\t\tsaves.slots.reverse();\n\t\t\t}\n\t\t\telse if (Config.saves.slots > saves.slots.length) {\n\t\t\t\t// Attempt to increase the number of slots.\n\t\t\t\t_appendSlots(saves.slots, Config.saves.slots - saves.slots.length);\n\t\t\t}\n\n\t\t\tupdated = true;\n\t\t}\n\n\t\t/* legacy */\n\t\t// Update saves with old/obsolete properties.\n\t\tif (_savesObjUpdate(saves.autosave)) {\n\t\t\tupdated = true;\n\t\t}\n\n\t\tfor (let i = 0; i < saves.slots.length; ++i) {\n\t\t\tif (_savesObjUpdate(saves.slots[i])) {\n\t\t\t\tupdated = true;\n\t\t\t}\n\t\t}\n\n\t\t// Remove save stores which are empty.\n\t\tif (_savesObjIsEmpty(saves)) {\n\t\t\tstorage.delete('saves');\n\t\t\tupdated = false;\n\t\t}\n\t\t/* /legacy */\n\n\t\t// If the saves object was updated, then update the store.\n\t\tif (updated) {\n\t\t\t_savesObjSave(saves);\n\t\t}\n\n\t\t_slotsUBound = saves.slots.length - 1;\n\n\t\treturn true;\n\t}\n\n\tfunction savesObjCreate() {\n\t\treturn {\n\t\t\tautosave : null,\n\t\t\tslots    : _appendSlots([], Config.saves.slots)\n\t\t};\n\t}\n\n\tfunction savesObjGet() {\n\t\tconst saves = storage.get('saves');\n\t\treturn saves === null ? savesObjCreate() : saves;\n\t}\n\n\tfunction savesObjClear() {\n\t\tstorage.delete('saves');\n\t\treturn true;\n\t}\n\n\tfunction savesOk() {\n\t\treturn autosaveOk() || slotsOk();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAutosave Functions.\n\t*******************************************************************************************************************/\n\tfunction autosaveOk() {\n\t\treturn storage.name !== 'cookie' && typeof Config.saves.autosave !== 'undefined';\n\t}\n\n\tfunction autosaveHas() {\n\t\tconst saves = savesObjGet();\n\n\t\tif (saves.autosave === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction autosaveGet() {\n\t\tconst saves = savesObjGet();\n\t\treturn saves.autosave;\n\t}\n\n\tfunction autosaveLoad() {\n\t\tconst saves = savesObjGet();\n\n\t\tif (saves.autosave === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn _unmarshal(saves.autosave);\n\t}\n\n\tfunction autosaveSave(title, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves        = savesObjGet();\n\t\tconst supplemental = {\n\t\t\ttitle : title || Story.get(State.passage).description(),\n\t\t\tdate  : Date.now()\n\t\t};\n\n\t\tif (metadata != null) { // lazy equality for null\n\t\t\tsupplemental.metadata = metadata;\n\t\t}\n\n\t\tsaves.autosave = _marshal(supplemental);\n\n\t\treturn _savesObjSave(saves);\n\t}\n\n\tfunction autosaveDelete() {\n\t\tconst saves = savesObjGet();\n\t\tsaves.autosave = null;\n\t\treturn _savesObjSave(saves);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSlots Functions.\n\t*******************************************************************************************************************/\n\tfunction slotsOk() {\n\t\treturn storage.name !== 'cookie' && _slotsUBound !== -1;\n\t}\n\n\tfunction slotsLength() {\n\t\treturn _slotsUBound + 1;\n\t}\n\n\tfunction slotsCount() {\n\t\tif (!slotsOk()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\t\tlet count = 0;\n\n\t\tfor (let i = 0, iend = saves.slots.length; i < iend; ++i) {\n\t\t\tif (saves.slots[i] !== null) {\n\t\t\t\t++count;\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n\n\tfunction slotsIsEmpty() {\n\t\treturn slotsCount() === 0;\n\t}\n\n\tfunction slotsHas(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length || saves.slots[slot] === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction slotsGet(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn saves.slots[slot];\n\t}\n\n\tfunction slotsLoad(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length || saves.slots[slot] === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn _unmarshal(saves.slots[slot]);\n\t}\n\n\tfunction slotsSave(slot, title, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst supplemental = {\n\t\t\ttitle : title || Story.get(State.passage).description(),\n\t\t\tdate  : Date.now()\n\t\t};\n\n\t\tif (metadata != null) { // lazy equality for null\n\t\t\tsupplemental.metadata = metadata;\n\t\t}\n\n\t\tsaves.slots[slot] = _marshal(supplemental);\n\n\t\treturn _savesObjSave(saves);\n\t}\n\n\tfunction slotsDelete(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tsaves.slots[slot] = null;\n\t\treturn _savesObjSave(saves);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tDisk Import/Export Functions.\n\t*******************************************************************************************************************/\n\tfunction exportToDisk(filename, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tfunction datestamp() {\n\t\t\tconst now = new Date();\n\t\t\tlet MM = now.getMonth() + 1;\n\t\t\tlet DD = now.getDate();\n\t\t\tlet hh = now.getHours();\n\t\t\tlet mm = now.getMinutes();\n\t\t\tlet ss = now.getSeconds();\n\n\t\t\tif (MM < 10) { MM = `0${MM}`; }\n\t\t\tif (DD < 10) { DD = `0${DD}`; }\n\t\t\tif (hh < 10) { hh = `0${hh}`; }\n\t\t\tif (mm < 10) { mm = `0${mm}`; }\n\t\t\tif (ss < 10) { ss = `0${ss}`; }\n\n\t\t\treturn `${now.getFullYear()}${MM}${DD}-${hh}${mm}${ss}`;\n\t\t}\n\n\t\tfunction legalizeName(str) {\n\t\t\t/*\n\t\t\t\tNOTE: The range of illegal characters consists of: C0 controls, double quote,\n\t\t\t\tnumber, dollar, percent, ampersand, single quote, asterisk, plus, comma,\n\t\t\t\tforward slash, colon, semi-colon, less-than, equals, greater-than, question,\n\t\t\t\tbackslash, caret, backquote/grave, pipe/vertical-bar, delete, C1 controls.\n\t\t\t*/\n\t\t\treturn String(str).trim()\n\t\t\t\t.replace(/[\\x00-\\x1f\"#$%&'*+,/:;<=>?\\\\^`|\\x7f-\\x9f]+/g, '') // eslint-disable-line no-control-regex\n\t\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-'); // legacy\n\t\t}\n\n\t\tconst baseName     = filename == null ? Story.domId : legalizeName(filename); // lazy equality for null\n\t\tconst saveName     = `${baseName}-${datestamp()}.save`;\n\t\tconst supplemental = metadata == null ? {} : { metadata }; // lazy equality for null\n\t\tconst saveObj      = LZString.compressToBase64(JSON.stringify(_marshal(supplemental)));\n\t\tsaveAs(new Blob([saveObj], { type : 'text/plain;charset=UTF-8' }), saveName);\n\t}\n\n\tfunction importFromDisk(event) {\n\t\tconst file   = event.target.files[0];\n\t\tconst reader = new FileReader();\n\n\t\t// Add the handler that will capture the file information once the load is finished.\n\t\tjQuery(reader).on('load', ev => {\n\t\t\tconst target = ev.currentTarget;\n\n\t\t\tif (!target.result) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet saveObj;\n\n\t\t\ttry {\n\t\t\t\tsaveObj = JSON.parse(\n\t\t\t\t\t/* legacy */ /\\.json$/i.test(file.name) || /^\\{/.test(target.result)\n\t\t\t\t\t\t? target.result\n\t\t\t\t\t\t: /* /legacy */ LZString.decompressFromBase64(target.result)\n\t\t\t\t);\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op; `_unmarshal()` will handle the error */ }\n\n\t\t\t_unmarshal(saveObj);\n\t\t});\n\n\t\t// Initiate the file load.\n\t\treader.readAsText(file);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSerialization Functions.\n\t*******************************************************************************************************************/\n\tfunction serialize(metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tconst supplemental = metadata == null ? {} : { metadata }; // lazy equality for null\n\t\treturn LZString.compressToBase64(JSON.stringify(_marshal(supplemental)));\n\t}\n\n\tfunction deserialize(base64Str) {\n\t\t/*\n\t\t\tNOTE: We purposefully do not attempt to catch parameter shenanigans\n\t\t\there, instead relying on `_unmarshal()` to do the heavy lifting.\n\t\t*/\n\n\t\tlet saveObj;\n\n\t\ttry {\n\t\t\tsaveObj = JSON.parse(LZString.decompressFromBase64(base64Str));\n\t\t}\n\t\tcatch (ex) { /* no-op; `_unmarshal()` will handle the error */ }\n\n\t\tif (!_unmarshal(saveObj)) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn saveObj.metadata;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _appendSlots(array, num) {\n\t\tfor (let i = 0; i < num; ++i) {\n\t\t\tarray.push(null);\n\t\t}\n\n\t\treturn array;\n\t}\n\n\tfunction _savesObjIsEmpty(saves) {\n\t\tconst slots = saves.slots;\n\t\tlet isSlotsEmpty = true;\n\n\t\tfor (let i = 0, iend = slots.length; i < iend; ++i) {\n\t\t\tif (slots[i] !== null) {\n\t\t\t\tisSlotsEmpty = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn saves.autosave === null && isSlotsEmpty;\n\t}\n\n\tfunction _savesObjSave(saves) {\n\t\tif (_savesObjIsEmpty(saves)) {\n\t\t\tstorage.delete('saves');\n\t\t\treturn true;\n\t\t}\n\n\t\treturn storage.set('saves', saves);\n\t}\n\n\tfunction _savesObjUpdate(saveObj) {\n\t\tif (saveObj == null || typeof saveObj !== 'object') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tlet updated = false;\n\n\t\t/* eslint-disable no-param-reassign */\n\t\tif (\n\t\t\t   !saveObj.hasOwnProperty('state')\n\t\t\t|| !saveObj.state.hasOwnProperty('delta')\n\t\t\t|| !saveObj.state.hasOwnProperty('index')\n\t\t) {\n\t\t\tif (saveObj.hasOwnProperty('data')) {\n\t\t\t\tdelete saveObj.mode;\n\t\t\t\tsaveObj.state = {\n\t\t\t\t\tdelta : State.deltaEncode(saveObj.data)\n\t\t\t\t};\n\t\t\t\tdelete saveObj.data;\n\t\t\t}\n\t\t\telse if (!saveObj.state.hasOwnProperty('delta')) {\n\t\t\t\tdelete saveObj.state.mode;\n\t\t\t\tsaveObj.state.delta = State.deltaEncode(saveObj.state.history);\n\t\t\t\tdelete saveObj.state.history;\n\t\t\t}\n\t\t\telse if (!saveObj.state.hasOwnProperty('index')) {\n\t\t\t\tdelete saveObj.state.mode;\n\t\t\t}\n\n\t\t\tsaveObj.state.index = saveObj.state.delta.length - 1;\n\t\t\tupdated = true;\n\t\t}\n\n\t\tif (saveObj.state.hasOwnProperty('rseed')) {\n\t\t\tsaveObj.state.seed = saveObj.state.rseed;\n\t\t\tdelete saveObj.state.rseed;\n\n\t\t\tsaveObj.state.delta.forEach((_, i, delta) => {\n\t\t\t\tif (delta[i].hasOwnProperty('rcount')) {\n\t\t\t\t\tdelta[i].pull = delta[i].rcount;\n\t\t\t\t\tdelete delta[i].rcount;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tupdated = true;\n\t\t}\n\n\t\tif (\n\t\t\t   saveObj.state.hasOwnProperty('expired') && typeof saveObj.state.expired === 'number'\n\t\t\t||  saveObj.state.hasOwnProperty('unique')\n\t\t\t||  saveObj.state.hasOwnProperty('last')\n\t\t) {\n\t\t\tif (saveObj.state.hasOwnProperty('expired') && typeof saveObj.state.expired === 'number') {\n\t\t\t\tdelete saveObj.state.expired;\n\t\t\t}\n\n\t\t\tif (saveObj.state.hasOwnProperty('unique') || saveObj.state.hasOwnProperty('last')) {\n\t\t\t\tsaveObj.state.expired = [];\n\n\t\t\t\tif (saveObj.state.hasOwnProperty('unique')) {\n\t\t\t\t\tsaveObj.state.expired.push(saveObj.state.unique);\n\t\t\t\t\tdelete saveObj.state.unique;\n\t\t\t\t}\n\n\t\t\t\tif (saveObj.state.hasOwnProperty('last')) {\n\t\t\t\t\tsaveObj.state.expired.push(saveObj.state.last);\n\t\t\t\t\tdelete saveObj.state.last;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tupdated = true;\n\t\t}\n\t\t/* eslint-enable no-param-reassign */\n\n\t\treturn updated;\n\t}\n\n\tfunction _marshal(supplemental) {\n\t\tif (DEBUG) { console.log('[Save/_marshal()]'); }\n\n\t\tif (supplemental != null && typeof supplemental !== 'object') { // lazy equality for null\n\t\t\tthrow new Error('supplemental parameter must be an object');\n\t\t}\n\n\t\tconst saveObj = Object.assign({}, supplemental, {\n\t\t\tid    : Config.saves.id,\n\t\t\tstate : State.marshalForSave()\n\t\t});\n\n\t\tif (Config.saves.version) {\n\t\t\tsaveObj.version = Config.saves.version;\n\t\t}\n\n\t\tif (typeof Config.saves.onSave === 'function') {\n\t\t\tConfig.saves.onSave(saveObj);\n\t\t}\n\n\t\t// Delta encode the state history and delete the non-encoded property.\n\t\tsaveObj.state.delta = State.deltaEncode(saveObj.state.history);\n\t\tdelete saveObj.state.history;\n\n\t\treturn saveObj;\n\t}\n\n\tfunction _unmarshal(saveObj) {\n\t\tif (DEBUG) { console.log('[Save/_unmarshal()]'); }\n\n\t\ttry {\n\t\t\t/* eslint-disable no-param-reassign */\n\t\t\t/* legacy */\n\t\t\t// Update saves with old/obsolete properties.\n\t\t\t_savesObjUpdate(saveObj);\n\t\t\t/* /legacy */\n\n\t\t\tif (!saveObj || !saveObj.hasOwnProperty('id') || !saveObj.hasOwnProperty('state')) {\n\t\t\t\tthrow new Error(L10n.get('errorSaveMissingData'));\n\t\t\t}\n\n\t\t\t// Delta decode the state history and delete the encoded property.\n\t\t\tsaveObj.state.history = State.deltaDecode(saveObj.state.delta);\n\t\t\tdelete saveObj.state.delta;\n\n\t\t\tif (typeof Config.saves.onLoad === 'function') {\n\t\t\t\tConfig.saves.onLoad(saveObj);\n\t\t\t}\n\n\t\t\tif (saveObj.id !== Config.saves.id) {\n\t\t\t\tthrow new Error(L10n.get('errorSaveIdMismatch'));\n\t\t\t}\n\n\t\t\t// Restore the state.\n\t\t\tState.unmarshalForSave(saveObj.state); // may also throw exceptions\n\n\t\t\t// Show the active moment.\n\t\t\tEngine.show();\n\t\t\t/* eslint-enable no-param-reassign */\n\t\t}\n\t\tcatch (ex) {\n\t\t\tUI.alert(`${ex.message.toUpperFirst()}.</p><p>${L10n.get('aborting')}.`);\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tSave Functions.\n\t\t*/\n\t\tinit  : { value : savesInit },\n\t\tget   : { value : savesObjGet },\n\t\tclear : { value : savesObjClear },\n\t\tok    : { value : savesOk },\n\n\t\t/*\n\t\t\tAutosave Functions.\n\t\t*/\n\t\tautosave : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tok     : { value : autosaveOk },\n\t\t\t\thas    : { value : autosaveHas },\n\t\t\t\tget    : { value : autosaveGet },\n\t\t\t\tload   : { value : autosaveLoad },\n\t\t\t\tsave   : { value : autosaveSave },\n\t\t\t\tdelete : { value : autosaveDelete }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tSlots Functions.\n\t\t*/\n\t\tslots : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tok      : { value : slotsOk },\n\t\t\t\tlength  : { get : slotsLength },\n\t\t\t\tisEmpty : { value : slotsIsEmpty },\n\t\t\t\tcount   : { value : slotsCount },\n\t\t\t\thas     : { value : slotsHas },\n\t\t\t\tget     : { value : slotsGet },\n\t\t\t\tload    : { value : slotsLoad },\n\t\t\t\tsave    : { value : slotsSave },\n\t\t\t\tdelete  : { value : slotsDelete }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tDisk Import/Export Functions.\n\t\t*/\n\t\texport : { value : exportToDisk },\n\t\timport : { value : importFromDisk },\n\n\t\t/*\n\t\t\tSerialization Functions.\n\t\t*/\n\t\tserialize   : { value : serialize },\n\t\tdeserialize : { value : deserialize }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tsetting.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util, settings:true, storage */\n\nvar Setting = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Setting control types object (pseudo-enumeration).\n\tconst Types = Util.toEnum({\n\t\tHeader : 0,\n\t\tToggle : 1,\n\t\tList   : 2,\n\t\tRange  : 3\n\t});\n\n\t// Setting definition array.\n\tconst _definitions = [];\n\n\n\t/*******************************************************************************************************************\n\t\tSettings Functions.\n\t*******************************************************************************************************************/\n\tfunction settingsInit() {\n\t\tif (DEBUG) { console.log('[Setting/settingsInit()]'); }\n\n\t\t/* legacy */\n\t\t// Attempt to migrate an existing `options` store to `settings`.\n\t\tif (storage.has('options')) {\n\t\t\tconst old = storage.get('options');\n\n\t\t\tif (old !== null) {\n\t\t\t\twindow.SugarCube.settings = settings = Object.assign(settingsCreate(), old);\n\t\t\t}\n\n\t\t\tsettingsSave();\n\t\t\tstorage.delete('options');\n\t\t}\n\t\t/* /legacy */\n\n\t\t// Load existing settings.\n\t\tsettingsLoad();\n\n\t\t// Execute `onInit` callbacks.\n\t\t_definitions.forEach(def => {\n\t\t\tif (def.hasOwnProperty('onInit')) {\n\t\t\t\tconst thisArg = {\n\t\t\t\t\tname    : def.name,\n\t\t\t\t\tvalue   : settings[def.name],\n\t\t\t\t\tdefault : def.default\n\t\t\t\t};\n\n\t\t\t\tif (def.hasOwnProperty('list')) {\n\t\t\t\t\tthisArg.list = def.list;\n\t\t\t\t}\n\n\t\t\t\tdef.onInit.call(thisArg);\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction settingsCreate() {\n\t\treturn Object.create(null);\n\t}\n\n\tfunction settingsSave() {\n\t\tconst savedSettings = settingsCreate();\n\n\t\tif (Object.keys(settings).length > 0) {\n\t\t\t_definitions\n\t\t\t\t.filter(def => def.type !== Types.Header && settings[def.name] !== def.default)\n\t\t\t\t.forEach(def => savedSettings[def.name] = settings[def.name]);\n\t\t}\n\n\t\tif (Object.keys(savedSettings).length === 0) {\n\t\t\tstorage.delete('settings');\n\t\t\treturn true;\n\t\t}\n\n\t\treturn storage.set('settings', savedSettings);\n\t}\n\n\tfunction settingsLoad() {\n\t\tconst defaultSettings = settingsCreate();\n\t\tconst loadedSettings  = storage.get('settings') || settingsCreate();\n\n\t\t// Load the defaults.\n\t\t_definitions\n\t\t\t.filter(def => def.type !== Types.Header)\n\t\t\t.forEach(def => defaultSettings[def.name] = def.default);\n\n\t\t// Assign to the `settings` object while overwriting the defaults with the loaded settings.\n\t\twindow.SugarCube.settings = settings = Object.assign(defaultSettings, loadedSettings);\n\t}\n\n\tfunction settingsClear() {\n\t\twindow.SugarCube.settings = settings = settingsCreate();\n\t\tstorage.delete('settings');\n\t\treturn true;\n\t}\n\n\tfunction settingsReset(name) {\n\t\tif (arguments.length === 0) {\n\t\t\tsettingsClear();\n\t\t\tsettingsLoad();\n\t\t}\n\t\telse {\n\t\t\tif (name == null || !definitionsHas(name)) { // lazy equality for null\n\t\t\t\tthrow new Error(`nonexistent setting \"${name}\"`);\n\t\t\t}\n\n\t\t\tconst def = definitionsGet(name);\n\n\t\t\tif (def.type !== Types.Header) {\n\t\t\t\tsettings[name] = def.default;\n\t\t\t}\n\t\t}\n\n\t\treturn settingsSave();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tDefinitions Functions.\n\t*******************************************************************************************************************/\n\tfunction definitionsForEach(callback, thisArg) {\n\t\t_definitions.forEach(callback, thisArg);\n\t}\n\n\tfunction definitionsAdd(type, name, def) {\n\t\tif (arguments.length < 3) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('type'); }\n\t\t\tif (arguments.length < 2) { errors.push('name'); }\n\t\t\tif (arguments.length < 3) { errors.push('definition'); }\n\t\t\tthrow new Error(`missing parameters, no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tif (typeof def !== 'object') {\n\t\t\tthrow new TypeError('definition parameter must be an object');\n\t\t}\n\n\t\tif (definitionsHas(name)) {\n\t\t\tthrow new Error(`cannot clobber existing setting \"${name}\"`);\n\t\t}\n\n\t\t/*\n\t\t\tDefinition object properties and types:\n\t\t\t\ttype      →  (all)   → Setting.Types\n\t\t\t\tname      →  (all)   → string\n\t\t\t\tlabel     →  (all)   → string\n\t\t\t\tdesc      →  (all)   → string\n\t\t\t\tdefault\n\t\t\t\t\t(if defined)\n \t\t\t\t\t\t  →  Toggle  → boolean\n\t\t\t\t\t\t  →  List    → Array\n\t\t\t\t\t\t  →  Range   → number\n\t\t\t\t\t(if undefined)\n\t\t\t\t\t\t  →  Toggle  → false\n\t\t\t\t\t\t  →  List    → list[0]\n\t\t\t\t\t\t  →  Range   → max\n\t\t\t\tlist      →  List    → Array\n\t\t\t\tmin       →  Range   → number\n\t\t\t\tmax       →  Range   → number\n\t\t\t\tstep      →  Range   → number\n\t\t\t\tonInit    →  (all)   → function\n\t\t\t\tonChange  →  (all)   → function\n\t\t*/\n\t\tconst definition = {\n\t\t\ttype,\n\t\t\tname,\n\t\t\tlabel : typeof def.label === 'string' ? def.label.trim() : ''\n\t\t};\n\n\t\tif (typeof def.desc === 'string') {\n\t\t\tconst desc = def.desc.trim();\n\n\t\t\tif (desc !== '') {\n\t\t\t\tdefinition.desc = desc;\n\t\t\t}\n\t\t}\n\n\t\tswitch (type) {\n\t\tcase Types.Header:\n\t\t\tbreak;\n\n\t\tcase Types.Toggle:\n\t\t\tdefinition.default = !!def.default;\n\t\t\tbreak;\n\n\t\tcase Types.List:\n\t\t\tif (!def.hasOwnProperty('list')) {\n\t\t\t\tthrow new Error('no list specified');\n\t\t\t}\n\t\t\telse if (!Array.isArray(def.list)) {\n\t\t\t\tthrow new TypeError('list must be an array');\n\t\t\t}\n\t\t\telse if (def.list.length === 0) {\n\t\t\t\tthrow new Error('list must not be empty');\n\t\t\t}\n\n\t\t\tdefinition.list = Object.freeze(def.list);\n\n\t\t\tif (def.default == null) { // lazy equality for null\n\t\t\t\tdefinition.default = def.list[0];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst defaultIndex = def.list.indexOf(def.default);\n\n\t\t\t\tif (defaultIndex === -1) {\n\t\t\t\t\tthrow new Error('list does not contain default');\n\t\t\t\t}\n\n\t\t\t\tdefinition.default = def.list[defaultIndex];\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase Types.Range:\n\t\t\tif (!def.hasOwnProperty('min')) {\n\t\t\t\tthrow new Error('no min specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.min !== 'number'\n\t\t\t\t|| Number.isNaN(def.min)\n\t\t\t\t|| !Number.isFinite(def.min)\n\t\t\t) {\n\t\t\t\tthrow new TypeError('min must be a finite number');\n\t\t\t}\n\n\t\t\tif (!def.hasOwnProperty('max')) {\n\t\t\t\tthrow new Error('no max specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.max !== 'number'\n\t\t\t\t|| Number.isNaN(def.max)\n\t\t\t\t|| !Number.isFinite(def.max)\n\t\t\t) {\n\t\t\t\tthrow new TypeError('max must be a finite number');\n\t\t\t}\n\n\t\t\tif (!def.hasOwnProperty('step')) {\n\t\t\t\tthrow new Error('no step specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.step !== 'number'\n\t\t\t\t|| Number.isNaN(def.step)\n\t\t\t\t|| !Number.isFinite(def.step)\n\t\t\t\t|| def.step <= 0\n\t\t\t) {\n\t\t\t\tthrow new TypeError('step must be a finite number greater than zero');\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Determine how many fractional digits we need to be concerned with based on the step value.\n\t\t\t\tconst fracDigits = (() => {\n\t\t\t\t\tconst str = String(def.step);\n\t\t\t\t\tconst pos = str.lastIndexOf('.');\n\t\t\t\t\treturn pos === -1 ? 0 : str.length - pos - 1;\n\t\t\t\t})();\n\n\t\t\t\t// Set up a function to validate a given value against the step value.\n\t\t\t\tfunction stepValidate(value) {\n\t\t\t\t\tif (fracDigits > 0) {\n\t\t\t\t\t\tconst ma = Number(`${def.min}e${fracDigits}`);\n\t\t\t\t\t\tconst sa = Number(`${def.step}e${fracDigits}`);\n\t\t\t\t\t\tconst va = Number(`${value}e${fracDigits}`) - ma;\n\t\t\t\t\t\treturn Number(`${va - va % sa + ma}e-${fracDigits}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst va = value - def.min;\n\t\t\t\t\treturn va - va % def.step + def.min;\n\t\t\t\t}\n\n\t\t\t\t// Sanity check the max value against the step value.\n\t\t\t\tif (stepValidate(def.max) !== def.max) {\n\t\t\t\t\tthrow new RangeError(`max (${def.max}) is not a multiple of the step (${def.step}) plus the min (${def.min})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdefinition.max = def.max;\n\t\t\tdefinition.min = def.min;\n\t\t\tdefinition.step = def.step;\n\n\t\t\tif (def.default == null) { // lazy equality for null\n\t\t\t\tdefinition.default = def.max;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (\n\t\t\t\t\t   typeof def.default !== 'number'\n\t\t\t\t\t|| Number.isNaN(def.default)\n\t\t\t\t\t|| !Number.isFinite(def.default)\n\t\t\t\t) {\n\t\t\t\t\tthrow new TypeError('default must be a finite number');\n\t\t\t\t}\n\t\t\t\telse if (def.default < def.min) {\n\t\t\t\t\tthrow new RangeError(`default (${def.default}) is less than min (${def.min})`);\n\t\t\t\t}\n\t\t\t\telse if (def.default > def.max) {\n\t\t\t\t\tthrow new RangeError(`default (${def.default}) is greater than max (${def.max})`);\n\t\t\t\t}\n\n\t\t\t\tdefinition.default = def.default;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new Error(`unknown Setting type: ${type}`);\n\t\t}\n\n\t\tif (typeof def.onInit === 'function') {\n\t\t\tdefinition.onInit = Object.freeze(def.onInit);\n\t\t}\n\n\t\tif (typeof def.onChange === 'function') {\n\t\t\tdefinition.onChange = Object.freeze(def.onChange);\n\t\t}\n\n\t\t_definitions.push(Object.freeze(definition));\n\t}\n\n\tfunction definitionsAddHeader(name, desc) {\n\t\tdefinitionsAdd(Types.Header, name, { desc });\n\t}\n\n\tfunction definitionsAddToggle(...args) {\n\t\tdefinitionsAdd(Types.Toggle, ...args);\n\t}\n\n\tfunction definitionsAddList(...args) {\n\t\tdefinitionsAdd(Types.List, ...args);\n\t}\n\n\tfunction definitionsAddRange(...args) {\n\t\tdefinitionsAdd(Types.Range, ...args);\n\t}\n\n\tfunction definitionsIsEmpty() {\n\t\treturn _definitions.length === 0;\n\t}\n\n\tfunction definitionsHas(name) {\n\t\treturn _definitions.some(definition => definition.name === name);\n\t}\n\n\tfunction definitionsGet(name) {\n\t\treturn _definitions.find(definition => definition.name === name);\n\t}\n\n\tfunction definitionsDelete(name) {\n\t\tif (definitionsHas(name)) {\n\t\t\tdelete settings[name];\n\t\t}\n\n\t\tfor (let i = 0; i < _definitions.length; ++i) {\n\t\t\tif (_definitions[i].name === name) {\n\t\t\t\t_definitions.splice(i, 1);\n\t\t\t\tdefinitionsDelete(name);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tEnumerations.\n\t\t*/\n\t\tTypes : { value : Types },\n\n\t\t/*\n\t\t\tSettings Functions.\n\t\t*/\n\t\tinit   : { value : settingsInit },\n\t\tcreate : { value : settingsCreate },\n\t\tsave   : { value : settingsSave },\n\t\tload   : { value : settingsLoad },\n\t\tclear  : { value : settingsClear },\n\t\treset  : { value : settingsReset },\n\n\t\t/*\n\t\t\tDefinitions Functions.\n\t\t*/\n\t\tforEach   : { value : definitionsForEach },\n\t\tadd       : { value : definitionsAdd },\n\t\taddHeader : { value : definitionsAddHeader },\n\t\taddToggle : { value : definitionsAddToggle },\n\t\taddList   : { value : definitionsAddList },\n\t\taddRange  : { value : definitionsAddRange },\n\t\tisEmpty   : { value : definitionsIsEmpty },\n\t\thas       : { value : definitionsHas },\n\t\tget       : { value : definitionsGet },\n\t\tdelete    : { value : definitionsDelete }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tstory.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Alert, Config, Passage, Scripting, StyleWrapper, Util, Wikifier */\n\nvar Story = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Map of normal passages.\n\tconst _passages = {};\n\n\t// List of script passages.\n\tconst _scripts = [];\n\n\t// List of style passages.\n\tconst _styles = [];\n\n\t// List of widget passages.\n\tconst _widgets = [];\n\n\t// Story title.\n\tlet _title = '';\n\n\t// Story IFID.\n\tlet _ifId = '';\n\n\t// DOM-compatible ID.\n\tlet _domId = '';\n\n\n\t/*******************************************************************************************************************\n\t\tStory Functions.\n\t*******************************************************************************************************************/\n\tfunction storyLoad() {\n\t\tif (DEBUG) { console.log('[Story/storyLoad()]'); }\n\n\t\tconst validationCodeTags = [\n\t\t\t'widget'\n\t\t];\n\t\tconst validationNoCodeTagPassages = [\n\t\t\t'PassageDone',\n\t\t\t'PassageFooter',\n\t\t\t'PassageHeader',\n\t\t\t'PassageReady',\n\t\t\t'StoryAuthor',\n\t\t\t'StoryBanner',\n\t\t\t'StoryCaption',\n\t\t\t'StoryInit',\n\t\t\t'StoryMenu',\n\t\t\t'StoryShare',\n\t\t\t'StorySubtitle'\n\t\t];\n\n\t\tfunction validateStartingPassage(passage) {\n\t\t\tif (passage.tags.includesAny(validationCodeTags)) {\n\t\t\t\tthrow new Error(`starting passage \"${passage.title}\" contains illegal tags; invalid: \"${passage.tags.filter(tag => validationCodeTags.includes(tag)).sort().join('\", \"')}\"`);\n\t\t\t}\n\t\t}\n\n\t\tfunction validateSpecialPassages(passage) {\n\t\t\tif (validationNoCodeTagPassages.includes(passage.title) && passage.tags.includesAny(validationCodeTags)) {\n\t\t\t\tthrow new Error(`special passage \"${passage.title}\" contains illegal tags; invalid: \"${passage.tags.filter(tag => validationCodeTags.includes(tag)).sort().join('\", \"')}\"`);\n\t\t\t}\n\t\t}\n\n\t\t// For Twine 1.\n\t\tif (TWINE1) {\n\t\t\t/*\n\t\t\t\tAdditional Twine 1 validation setup.\n\t\t\t*/\n\t\t\tvalidationCodeTags.unshift('script', 'stylesheet');\n\t\t\tvalidationNoCodeTagPassages.push('StoryTitle');\n\n\t\t\tfunction validateTwine1CodePassages(passage) {\n\t\t\t\tconst codeTags  = [...validationCodeTags];\n\t\t\t\tconst foundTags = [];\n\n\t\t\t\tpassage.tags.forEach(tag => {\n\t\t\t\t\tif (codeTags.includes(tag)) {\n\t\t\t\t\t\tfoundTags.push(...codeTags.delete(tag));\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (foundTags.length > 1) {\n\t\t\t\t\tthrow new Error(`code passage \"${passage.title}\" contains multiple code tags; invalid: \"${foundTags.sort().join('\", \"')}\"`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet the default starting passage.\n\t\t\t*/\n\t\t\tConfig.passages.start = (() => {\n\t\t\t\t/*\n\t\t\t\t\tHandle the Twine 1.4+ Test Play From Here feature.\n\n\t\t\t\t\tWARNING: Do not remove the `String()` wrapper from or change the quote\n\t\t\t\t\tstyle of the `\"START_AT\"` replacement target.  The former is there to\n\t\t\t\t\tkeep UglifyJS from pruning the code into oblivion—i.e. minifying the\n\t\t\t\t\tcode into something broken.  The latter is there because the Twine 1\n\t\t\t\t\tpattern that matches it depends upon the double quotes.\n\n\t\t\t\t*/\n\t\t\t\tconst testPlay = String(\"START_AT\"); // eslint-disable-line quotes\n\n\t\t\t\tif (testPlay !== '') {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tTest play; starting passage: \"${testPlay}\"`); }\n\n\t\t\t\t\tConfig.debug = true;\n\t\t\t\t\treturn testPlay;\n\t\t\t\t}\n\n\t\t\t\t// In the absence of a `testPlay` value, return 'Start'.\n\t\t\t\treturn 'Start';\n\t\t\t})();\n\n\t\t\t/*\n\t\t\t\tProcess the passages, excluding any tagged 'Twine.private' or 'annotation'.\n\t\t\t*/\n\t\t\tjQuery('#store-area')\n\t\t\t\t.children(':not([tags~=\"Twine.private\"],[tags~=\"annotation\"])')\n\t\t\t\t.each(function () {\n\t\t\t\t\tconst $this   = jQuery(this);\n\t\t\t\t\tconst passage = new Passage($this.attr('tiddler'), this);\n\n\t\t\t\t\t// Special cases.\n\t\t\t\t\tif (passage.title === Config.passages.start) {\n\t\t\t\t\t\tvalidateStartingPassage(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('stylesheet')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_styles.push(passage);\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('script')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_scripts.push(passage);\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('widget')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_widgets.push(passage);\n\t\t\t\t\t}\n\n\t\t\t\t\t// All other passages.\n\t\t\t\t\telse {\n\t\t\t\t\t\tvalidateSpecialPassages(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tSet the story title or throw an exception.\n\t\t\t*/\n\t\t\tif (_passages.hasOwnProperty('StoryTitle')) {\n\t\t\t\tconst buf = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(buf, _passages.StoryTitle.processText().trim());\n\t\t\t\t_storySetTitle(buf.textContent);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('cannot find the \"StoryTitle\" special passage');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet the default saves ID (must be done after the call to `_storySetTitle()`).\n\t\t\t*/\n\t\t\tConfig.saves.id = Story.domId;\n\t\t}\n\n\t\t// For Twine 2.\n\t\telse {\n\t\t\tconst $storydata = jQuery('tw-storydata');\n\t\t\tconst startNode  = $storydata.attr('startnode') || '';\n\n\t\t\t/*\n\t\t\t\tSet the default starting passage.\n\t\t\t*/\n\t\t\tConfig.passages.start = null; // no default in Twine 2\n\n\t\t\t/*\n\t\t\t\tProcess story options.\n\n\t\t\t\tNOTE: Currently, the only option of interest is 'debug', so we\n\t\t\t\tsimply use a regular expression to check for it.\n\t\t\t*/\n\t\t\tConfig.debug = /\\bdebug\\b/.test($storydata.attr('options'));\n\n\t\t\t/*\n\t\t\t\tProcess stylesheet passages.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('style') // alternatively: '[type=\"text/twine-css\"]' or '#twine-user-stylesheet'\n\t\t\t\t.each(function (i) {\n\t\t\t\t\t_styles.push(new Passage(`tw-user-style-${i}`, this));\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tProcess script passages.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('script') // alternatively: '[type=\"text/twine-javascript\"]' or '#twine-user-script'\n\t\t\t\t.each(function (i) {\n\t\t\t\t\t_scripts.push(new Passage(`tw-user-script-${i}`, this));\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tProcess normal passages, excluding any tagged 'Twine.private' or 'annotation'.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('tw-passagedata:not([tags~=\"Twine.private\"],[tags~=\"annotation\"])')\n\t\t\t\t.each(function () {\n\t\t\t\t\tconst $this   = jQuery(this);\n\t\t\t\t\tconst pid     = $this.attr('pid') || '';\n\t\t\t\t\tconst passage = new Passage($this.attr('name'), this);\n\n\t\t\t\t\t// Special cases.\n\t\t\t\t\tif (pid === startNode && startNode !== '') {\n\t\t\t\t\t\tConfig.passages.start = passage.title;\n\t\t\t\t\t\tvalidateStartingPassage(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('widget')) {\n\t\t\t\t\t\t_widgets.push(passage);\n\t\t\t\t\t}\n\n\t\t\t\t\t// All other passages.\n\t\t\t\t\telse {\n\t\t\t\t\t\tvalidateSpecialPassages(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tGet the story IFID.\n\t\t\t*/\n\t\t\t_ifId = $storydata.attr('ifid');\n\n\t\t\t/*\n\t\t\t\tSet the story title.\n\n\t\t\t\tFIXME: Maybe `$storydata.attr('name')` should be used instead of `'{{STORY_NAME}}'`?\n\t\t\t*/\n\t\t\t// _storySetTitle($storydata.attr('name'));\n\t\t\t_storySetTitle('{{STORY_NAME}}');\n\n\t\t\t/*\n\t\t\t\tSet the default saves ID (must be done after the call to `_storySetTitle()`).\n\t\t\t*/\n\t\t\tConfig.saves.id = Story.domId;\n\t\t}\n\t}\n\n\tfunction storyInit() {\n\t\tif (DEBUG) { console.log('[Story/storyInit()]'); }\n\n\t\t/*\n\t\t\tAdd the story styles.\n\t\t*/\n\t\t(() => {\n\t\t\tconst storyStyle = document.createElement('style');\n\n\t\t\t(new StyleWrapper(storyStyle))\n\t\t\t\t.add(_styles.map(style => style.text.trim()).join('\\n'));\n\n\t\t\tjQuery(storyStyle)\n\t\t\t\t.appendTo(document.head)\n\t\t\t\t.attr({\n\t\t\t\t\tid   : 'style-story',\n\t\t\t\t\ttype : 'text/css'\n\t\t\t\t});\n\t\t})();\n\n\t\t/*\n\t\t\tEvaluate the story scripts.\n\t\t*/\n\t\tfor (let i = 0; i < _scripts.length; ++i) {\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(_scripts[i].text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error(_scripts[i].title, typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t\tProcess the story widgets.\n\t\t*/\n\t\tfor (let i = 0; i < _widgets.length; ++i) {\n\t\t\ttry {\n\t\t\t\tWikifier.wikifyEval(_widgets[i].processText());\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error(_widgets[i].title, typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction _storySetTitle(rawTitle) {\n\t\tif (rawTitle == null) { // lazy equality for null\n\t\t\tthrow new Error('story title must not be null or undefined');\n\t\t}\n\n\t\tconst title = Util.unescape(String(rawTitle)).trim();\n\n\t\tif (title === '') { // lazy equality for null\n\t\t\tthrow new Error('story title must not be empty or consist solely of whitespace');\n\t\t}\n\n\t\tdocument.title = _title = title;\n\n\t\t// TODO: In v3 the `_domId` should be created from a combination of the\n\t\t// `_title` slug and the IFID, if available, to avoid collisions between\n\t\t// stories whose titles generate identical slugs.\n\t\t_domId = Util.slugify(_title);\n\n\t\t// [v2] Protect the `_domId` against being an empty string.\n\t\t//\n\t\t// If `_domId` is empty, attempt a failover.\n\t\tif (_domId === '') {\n\t\t\t// If `_ifId` is not empty, then use it.\n\t\t\tif (_ifId !== '') {\n\t\t\t\t_domId = _ifId;\n\t\t\t}\n\n\t\t\t// Elsewise generate a string from the `_title`'s code points (in hexadecimal).\n\t\t\telse {\n\t\t\t\tfor (let i = 0, len = _title.length; i < len; ++i) {\n\t\t\t\t\tconst { char, start, end } = Util.charAndPosAt(_title, i);\n\t\t\t\t\t_domId += char.codePointAt(0).toString(16);\n\t\t\t\t\ti += end - start;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction storyTitle() {\n\t\treturn _title;\n\t}\n\n\tfunction storyDomId() {\n\t\treturn _domId;\n\t}\n\n\tfunction storyIfId() {\n\t\treturn _ifId;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPassage Functions.\n\t*******************************************************************************************************************/\n\tfunction passagesAdd(passage) {\n\t\tif (!(passage instanceof Passage)) {\n\t\t\tthrow new TypeError('Story.add passage parameter must be an instance of Passage');\n\t\t}\n\n\t\tconst title = passage.title;\n\n\t\tif (!_passages.hasOwnProperty(title)) {\n\t\t\t_passages[title] = passage;\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tfunction passagesHas(title) {\n\t\tlet type = typeof title;\n\n\t\tswitch (type) {\n\t\t// Valid types.\n\t\tcase 'number':\n\t\tcase 'string':\n\t\t\treturn _passages.hasOwnProperty(String(title));\n\n\t\t// Invalid types.  We do the extra processing just to make a nicer error.\n\t\tcase 'undefined':\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\ttype = title === null ? 'null' : 'an object';\n\t\t\tbreak;\n\n\t\tdefault: // 'bigint', 'boolean', 'function', 'symbol'\n\t\t\ttype = `a ${type}`;\n\t\t\tbreak;\n\t\t}\n\n\t\tthrow new TypeError(`Story.has title parameter cannot be ${type}`);\n\t}\n\n\tfunction passagesGet(title) {\n\t\tlet type = typeof title;\n\n\t\tswitch (type) {\n\t\t// Valid types.\n\t\tcase 'number':\n\t\tcase 'string':\n\t\t/* eslint-disable indent */\n\t\t\t{\n\t\t\t\tconst id = String(title);\n\t\t\t\treturn _passages.hasOwnProperty(id) ? _passages[id] : new Passage(id || '(unknown)');\n\t\t\t}\n\t\t/* eslint-enable indent */\n\n\t\t// Invalid types.  We do the extra processing just to make a nicer error.\n\t\tcase 'undefined':\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\ttype = title === null ? 'null' : 'an object';\n\t\t\tbreak;\n\n\t\tdefault: // 'bigint', 'boolean', 'function', 'symbol'\n\t\t\ttype = `a ${type}`;\n\t\t\tbreak;\n\t\t}\n\n\t\tthrow new TypeError(`Story.get title parameter cannot be ${type}`);\n\t}\n\n\tfunction passagesGetAllRegular() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Object.assign({}, _passages));\n\t}\n\n\tfunction passagesGetAllScript() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_scripts));\n\t}\n\n\tfunction passagesGetAllStylesheet() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_styles));\n\t}\n\n\tfunction passagesGetAllWidget() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_widgets));\n\t}\n\n\tfunction passagesLookup(key, value  /* legacy */, sortKey = 'title'/* /legacy */) {\n\t\tconst results = [];\n\n\t\tObject.keys(_passages).forEach(name => {\n\t\t\tconst passage = _passages[name];\n\n\t\t\t// Objects (sans `null`).\n\t\t\tif (typeof passage[key] === 'object' && passage[key] !== null) {\n\t\t\t\t// The only object type currently supported is `Array`, since the\n\t\t\t\t// non-method `Passage` object properties currently yield only either\n\t\t\t\t// primitives or arrays.\n\t\t\t\tif (passage[key] instanceof Array && passage[key].some(m => Util.sameValueZero(m, value))) {\n\t\t\t\t\tresults.push(passage);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// All other types (incl. `null`).\n\t\t\telse if (Util.sameValueZero(passage[key], value)) {\n\t\t\t\tresults.push(passage);\n\t\t\t}\n\t\t});\n\n\t\t// For v3.\n\t\t// /* eslint-disable no-nested-ternary */\n\t\t// // QUESTION: Do we really need to sort the list?\n\t\t// results.sort((a, b) => a.title === b.title ? 0 : a.title < b.title ? -1 : +1);\n\t\t// /* eslint-enable no-nested-ternary */\n\n\t\t/* legacy */\n\t\t/* eslint-disable eqeqeq, no-nested-ternary, max-len */\n\t\tresults.sort((a, b) => a[sortKey] == b[sortKey] ? 0 : a[sortKey] < b[sortKey] ? -1 : +1); // lazy equality for null\n\t\t/* eslint-enable eqeqeq, no-nested-ternary, max-len */\n\t\t/* /legacy */\n\n\t\treturn results;\n\t}\n\n\tfunction passagesLookupWith(predicate /* legacy */, sortKey = 'title'/* /legacy */) {\n\t\tif (typeof predicate !== 'function') {\n\t\t\tthrow new TypeError('Story.lookupWith predicate parameter must be a function');\n\t\t}\n\n\t\tconst results = [];\n\n\t\tObject.keys(_passages).forEach(name => {\n\t\t\tconst passage = _passages[name];\n\n\t\t\tif (predicate(passage)) {\n\t\t\t\tresults.push(passage);\n\t\t\t}\n\t\t});\n\n\t\t// For v3.\n\t\t// /* eslint-disable no-nested-ternary */\n\t\t// // QUESTION: Do we really need to sort the list?\n\t\t// results.sort((a, b) => a.title === b.title ? 0 : a.title < b.title ? -1 : +1);\n\t\t// /* eslint-enable no-nested-ternary */\n\n\t\t/* legacy */\n\t\t/* eslint-disable eqeqeq, no-nested-ternary, max-len */\n\t\tresults.sort((a, b) => a[sortKey] == b[sortKey] ? 0 : a[sortKey] < b[sortKey] ? -1 : +1); // lazy equality for null\n\t\t/* eslint-enable eqeqeq, no-nested-ternary, max-len */\n\t\t/* /legacy */\n\n\t\treturn results;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Story Functions.\n\t\tload  : { value : storyLoad },\n\t\tinit  : { value : storyInit },\n\t\ttitle : { get : storyTitle },\n\t\tdomId : { get : storyDomId },\n\t\tifId  : { get : storyIfId },\n\n\t\t// Passage Functions.\n\t\tadd              : { value : passagesAdd },\n\t\thas              : { value : passagesHas },\n\t\tget              : { value : passagesGet },\n\t\tgetAllRegular    : { value : passagesGetAllRegular },\n\t\tgetAllScript     : { value : passagesGetAllScript },\n\t\tgetAllStylesheet : { value : passagesGetAllStylesheet },\n\t\tgetAllWidget     : { value : passagesGetAllWidget },\n\t\tlookup           : { value : passagesLookup },\n\t\tlookupWith       : { value : passagesLookupWith }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tui.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Dialog, Engine, Has, L10n, Save, Setting, State, Story, Util, Wikifier, Config, errorPrologRegExp,\n\t       settings\n*/\n\nvar UI = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUI Functions, Core.\n\t*******************************************************************************************************************/\n\tfunction uiAssembleLinkList(passage, listEl) {\n\t\tlet list = listEl;\n\n\t\t// Cache the values of `Config.debug` and `Config.cleanupWikifierOutput`,\n\t\t// then disable them during this method's run.\n\t\tconst debugState = Config.debug;\n\t\tconst cleanState = Config.cleanupWikifierOutput;\n\t\tConfig.debug = false;\n\t\tConfig.cleanupWikifierOutput = false;\n\n\t\ttry {\n\t\t\tif (list == null) { // lazy equality for null\n\t\t\t\tlist = document.createElement('ul');\n\t\t\t}\n\n\t\t\t// Wikify the content of the given source passage into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, Story.get(passage).processText().trim());\n\n\t\t\t// Gather the text of any error elements within the fragment…\n\t\t\tconst errors = [...frag.querySelectorAll('.error')]\n\t\t\t\t.map(errEl => errEl.textContent.replace(errorPrologRegExp, ''));\n\n\t\t\t// …and throw an exception, if there were any errors.\n\t\t\tif (errors.length > 0) {\n\t\t\t\tthrow new Error(errors.join('; '));\n\t\t\t}\n\n\t\t\twhile (frag.hasChildNodes()) {\n\t\t\t\tconst node = frag.firstChild;\n\n\t\t\t\t// Create list items for <a>-element nodes.\n\t\t\t\tif (node.nodeType === Node.ELEMENT_NODE && node.nodeName.toUpperCase() === 'A') {\n\t\t\t\t\tconst li = document.createElement('li');\n\t\t\t\t\tlist.appendChild(li);\n\t\t\t\t\tli.appendChild(node);\n\t\t\t\t}\n\n\t\t\t\t// Discard non-<a>-element nodes.\n\t\t\t\telse {\n\t\t\t\t\tfrag.removeChild(node);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\t// Restore the `Config` settings to their original values.\n\t\t\tConfig.cleanupWikifierOutput = cleanState;\n\t\t\tConfig.debug = debugState;\n\t\t}\n\n\t\treturn list;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUI Functions, Built-ins.\n\t*******************************************************************************************************************/\n\tfunction uiOpenAlert(message, /* options, closeFn */ ...args) {\n\t\tjQuery(Dialog.setup('Alert', 'alert'))\n\t\t\t.append(\n\t\t\t\t  `<p>${message}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"alert-ok\" class=\"ui-close\">${L10n.get(['alertOk', 'ok'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t);\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenJumpto(/* options, closeFn */ ...args) {\n\t\tuiBuildJumpto();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenRestart(/* options, closeFn */ ...args) {\n\t\tuiBuildRestart();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenSaves(/* options, closeFn */ ...args) {\n\t\tuiBuildSaves();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenSettings(/* options, closeFn */ ...args) {\n\t\tuiBuildSettings();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenShare(/* options, closeFn */ ...args) {\n\t\tuiBuildShare();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiBuildAutoload() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildAutoload()]'); }\n\n\t\tjQuery(Dialog.setup(L10n.get('autoloadTitle'), 'autoload'))\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  `<p>${L10n.get('autoloadPrompt')}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"autoload-ok\" class=\"ui-close\">${L10n.get(['autoloadOk', 'ok'])}</button></li>`\n\t\t\t\t+ `<li><button id=\"autoload-cancel\" class=\"ui-close\">${L10n.get(['autoloadCancel', 'cancel'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t);\n\n\t\t// Add an additional delegated click handler for the `.ui-close` elements to handle autoloading.\n\t\tjQuery(document).one('click.autoload', '.ui-close', ev => {\n\t\t\tconst isAutoloadOk = ev.target.id === 'autoload-ok';\n\t\t\tjQuery(document).one(':dialogclosed', () => {\n\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\tif (!isAutoloadOk || !Save.autosave.load()) {\n\t\t\t\t\tEngine.play(Config.passages.start);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildJumpto() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildJumpto()]'); }\n\n\t\tconst list = document.createElement('ul');\n\n\t\tjQuery(Dialog.setup(L10n.get('jumptoTitle'), 'jumpto list'))\n\t\t\t.append(list);\n\n\t\tconst expired = State.expired.length;\n\n\t\tfor (let i = State.size - 1; i >= 0; --i) {\n\t\t\tif (i === State.activeIndex) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst passage = Story.get(State.history[i].title);\n\n\t\t\tif (passage && passage.tags.includes('bookmark')) {\n\t\t\t\tjQuery(document.createElement('li'))\n\t\t\t\t\t.append(\n\t\t\t\t\t\tjQuery(document.createElement('a'))\n\t\t\t\t\t\t\t.ariaClick({ one : true }, (function (idx) {\n\t\t\t\t\t\t\t\treturn () => jQuery(document).one(':dialogclosed', () => Engine.goTo(idx));\n\t\t\t\t\t\t\t})(i))\n\t\t\t\t\t\t\t.addClass('ui-close')\n\t\t\t\t\t\t\t.text(`${L10n.get('jumptoTurn')} ${expired + i + 1}: ${passage.description()}`)\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo(list);\n\t\t\t}\n\t\t}\n\n\t\tif (!list.hasChildNodes()) {\n\t\t\tjQuery(list).append(`<li><a><em>${L10n.get('jumptoUnavailable')}</em></a></li>`);\n\t\t}\n\t}\n\n\tfunction uiBuildRestart() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildRestart()]'); }\n\n\t\tjQuery(Dialog.setup(L10n.get('restartTitle'), 'restart'))\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  `<p>${L10n.get('restartPrompt')}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"restart-ok\">${L10n.get(['restartOk', 'ok'])}</button></li>`\n\t\t\t\t+ `<li><button id=\"restart-cancel\" class=\"ui-close\">${L10n.get(['restartCancel', 'cancel'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t)\n\t\t\t.find('#restart-ok')\n\t\t\t/*\n\t\t\t\tInstead of adding '.ui-close' to '#restart-ok' (to receive the use of the default\n\t\t\t\tdelegated dialog close handler), we set up a special case close handler here.  We\n\t\t\t\tdo this to ensure that the invocation of `Engine.restart()` happens after the dialog\n\t\t\t\thas fully closed.  If we did not, then a race condition could occur, causing display\n\t\t\t\tshenanigans.\n\t\t\t*/\n\t\t\t.ariaClick({ one : true }, () => {\n\t\t\t\tjQuery(document).one(':dialogclosed', () => Engine.restart());\n\t\t\t\tDialog.close();\n\t\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildSaves() {\n\t\tfunction createActionItem(bId, bClass, bText, bAction) {\n\t\t\tconst $btn = jQuery(document.createElement('button'))\n\t\t\t\t.attr('id', `saves-${bId}`)\n\t\t\t\t.html(bText);\n\n\t\t\tif (bClass) {\n\t\t\t\t$btn.addClass(bClass);\n\t\t\t}\n\n\t\t\tif (bAction) {\n\t\t\t\t$btn.ariaClick(bAction);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$btn.ariaDisabled(true);\n\t\t\t}\n\n\t\t\treturn jQuery(document.createElement('li'))\n\t\t\t\t.append($btn);\n\t\t}\n\n\t\tfunction createSaveList() {\n\t\t\tfunction createButton(bId, bClass, bText, bSlot, bAction) {\n\t\t\t\tconst $btn = jQuery(document.createElement('button'))\n\t\t\t\t\t.attr('id', `saves-${bId}-${bSlot}`)\n\t\t\t\t\t.addClass(bId)\n\t\t\t\t\t.html(bText);\n\n\t\t\t\tif (bClass) {\n\t\t\t\t\t$btn.addClass(bClass);\n\t\t\t\t}\n\n\t\t\t\tif (bAction) {\n\t\t\t\t\tif (bSlot === 'auto') {\n\t\t\t\t\t\t$btn.ariaClick({\n\t\t\t\t\t\t\tlabel : `${bText} ${L10n.get('savesLabelAuto')}`\n\t\t\t\t\t\t}, () => bAction());\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t$btn.ariaClick({\n\t\t\t\t\t\t\tlabel : `${bText} ${L10n.get('savesLabelSlot')} ${bSlot + 1}`\n\t\t\t\t\t\t}, () => bAction(bSlot));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$btn.ariaDisabled(true);\n\t\t\t\t}\n\n\t\t\t\treturn $btn;\n\t\t\t}\n\n\t\t\tconst saves  = Save.get();\n\t\t\tconst $tbody = jQuery(document.createElement('tbody'));\n\n\t\t\tif (Save.autosave.ok()) {\n\t\t\t\tconst $tdSlot = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdLoad = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDesc = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDele = jQuery(document.createElement('td'));\n\n\t\t\t\t// Add the slot ID.\n\t\t\t\tjQuery(document.createElement('b'))\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttitle        : L10n.get('savesLabelAuto'),\n\t\t\t\t\t\t'aria-label' : L10n.get('savesLabelAuto')\n\t\t\t\t\t})\n\t\t\t\t\t.text('A') // '\\u25C6' Black Diamond\n\t\t\t\t\t.appendTo($tdSlot);\n\n\t\t\t\tif (saves.autosave) {\n\t\t\t\t\t// Add the load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('load', 'ui-close', L10n.get('savesLabelLoad'), 'auto', () => {\n\t\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.autosave.load());\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description (title and datestamp).\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.text(saves.autosave.title)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.addClass('datestamp')\n\t\t\t\t\t\t.html(\n\t\t\t\t\t\t\tsaves.autosave.date\n\t\t\t\t\t\t\t\t? `${new Date(saves.autosave.date).toLocaleString()}`\n\t\t\t\t\t\t\t\t: `<em>${L10n.get('savesUnknownDate')}</em>`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\n\t\t\t\t\t// Add the delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), 'auto', () => {\n\t\t\t\t\t\t\tSave.autosave.delete();\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Add the disabled load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('load', null, L10n.get('savesLabelLoad'), 'auto')\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description.\n\t\t\t\t\t$tdDesc.addClass('empty').text('\\u2022\\u00a0\\u00a0\\u2022\\u00a0\\u00a0\\u2022');\n\n\t\t\t\t\t// Add the disabled delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), 'auto')\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t.append($tdSlot)\n\t\t\t\t\t.append($tdLoad)\n\t\t\t\t\t.append($tdDesc)\n\t\t\t\t\t.append($tdDele)\n\t\t\t\t\t.appendTo($tbody);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = saves.slots.length; i < iend; ++i) {\n\t\t\t\tconst $tdSlot = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdLoad = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDesc = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDele = jQuery(document.createElement('td'));\n\n\t\t\t\t// Add the slot ID.\n\t\t\t\t$tdSlot.append(document.createTextNode(i + 1));\n\n\t\t\t\tif (saves.slots[i]) {\n\t\t\t\t\t// Add the load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('save', 'ui-close', L10n.get('savesLabelSave'), i, Save.slots.save),\n\t\t\t\t\t\tcreateButton('load', 'ui-close', L10n.get('savesLabelLoad'), i, slot => {\n\t\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.slots.load(slot));\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description (title and datestamp).\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.text(saves.slots[i].title)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.addClass('datestamp')\n\t\t\t\t\t\t.html(\n\t\t\t\t\t\t\tsaves.slots[i].date\n\t\t\t\t\t\t\t\t? `${new Date(saves.slots[i].date).toLocaleString()}`\n\t\t\t\t\t\t\t\t: `<em>${L10n.get('savesUnknownDate')}</em>`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\n\t\t\t\t\t// Add the delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), i, slot => {\n\t\t\t\t\t\t\tSave.slots.delete(slot);\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Add the save button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('save', 'ui-close', L10n.get('savesLabelSave'), i, Save.slots.save)\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description.\n\t\t\t\t\t$tdDesc.addClass('empty').text('\\u2022\\u00a0\\u00a0\\u2022\\u00a0\\u00a0\\u2022');\n\n\t\t\t\t\t// Add the disabled delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), i)\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t.append($tdSlot)\n\t\t\t\t\t.append($tdLoad)\n\t\t\t\t\t.append($tdDesc)\n\t\t\t\t\t.append($tdDele)\n\t\t\t\t\t.appendTo($tbody);\n\t\t\t}\n\n\t\t\treturn jQuery(document.createElement('table'))\n\t\t\t\t.attr('id', 'saves-list')\n\t\t\t\t.append($tbody);\n\t\t}\n\n\t\tif (DEBUG) { console.log('[UI/uiBuildSaves()]'); }\n\n\t\tconst $dialogBody = jQuery(Dialog.setup(L10n.get('savesTitle'), 'saves'));\n\t\tconst savesOk     = Save.ok();\n\n\t\t// Add saves list.\n\t\tif (savesOk) {\n\t\t\t$dialogBody.append(createSaveList());\n\t\t}\n\n\t\t// Add button bar items (export, import, and clear).\n\t\tif (savesOk || Has.fileAPI) {\n\t\t\tconst $btnBar = jQuery(document.createElement('ul'))\n\t\t\t\t.addClass('buttons')\n\t\t\t\t.appendTo($dialogBody);\n\n\t\t\tif (Has.fileAPI) {\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'export',\n\t\t\t\t\t'ui-close',\n\t\t\t\t\tL10n.get('savesLabelExport'),\n\t\t\t\t\t() => Save.export()\n\t\t\t\t));\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'import',\n\t\t\t\t\tnull,\n\t\t\t\t\tL10n.get('savesLabelImport'),\n\t\t\t\t\t() => $dialogBody.find('#saves-import-file').trigger('click')\n\t\t\t\t));\n\n\t\t\t\t// Add the hidden `input[type=file]` element which will be triggered by the `#saves-import` button.\n\t\t\t\tjQuery(document.createElement('input'))\n\t\t\t\t\t.css({\n\t\t\t\t\t\tdisplay    : 'block',\n\t\t\t\t\t\tvisibility : 'hidden',\n\t\t\t\t\t\tposition   : 'fixed',\n\t\t\t\t\t\tleft       : '-9999px',\n\t\t\t\t\t\ttop        : '-9999px',\n\t\t\t\t\t\twidth      : '1px',\n\t\t\t\t\t\theight     : '1px'\n\t\t\t\t\t})\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttype          : 'file',\n\t\t\t\t\t\tid            : 'saves-import-file',\n\t\t\t\t\t\ttabindex      : -1,\n\t\t\t\t\t\t'aria-hidden' : true\n\t\t\t\t\t})\n\t\t\t\t\t.on('change', ev => {\n\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.import(ev));\n\t\t\t\t\t\tDialog.close();\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo($dialogBody);\n\t\t\t}\n\n\t\t\tif (savesOk) {\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'clear',\n\t\t\t\t\tnull,\n\t\t\t\t\tL10n.get('savesLabelClear'),\n\t\t\t\t\tSave.autosave.has() || !Save.slots.isEmpty()\n\t\t\t\t\t\t? () => {\n\t\t\t\t\t\t\tSave.clear();\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t: null\n\t\t\t\t));\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tuiOpenAlert(L10n.get('savesIncapable'));\n\t\treturn false;\n\t}\n\n\tfunction uiBuildSettings() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildSettings()]'); }\n\n\t\tconst $dialogBody = jQuery(Dialog.setup(L10n.get('settingsTitle'), 'settings'));\n\n\t\tSetting.forEach(control => {\n\t\t\tif (control.type === Setting.Types.Header) {\n\t\t\t\tconst name     = control.name;\n\t\t\t\tconst id       = Util.slugify(name);\n\t\t\t\tconst $header  = jQuery(document.createElement('div'));\n\t\t\t\tconst $heading = jQuery(document.createElement('h2'));\n\n\t\t\t\t$header\n\t\t\t\t\t.attr('id', `header-body-${id}`)\n\t\t\t\t\t.append($heading)\n\t\t\t\t\t.appendTo($dialogBody);\n\t\t\t\t$heading\n\t\t\t\t\t.attr('id', `header-heading-${id}`)\n\t\t\t\t\t.wiki(name);\n\n\t\t\t\t// Set up the description, if any.\n\t\t\t\tif (control.desc) {\n\t\t\t\t\tjQuery(document.createElement('p'))\n\t\t\t\t\t\t.attr('id', `header-desc-${id}`)\n\t\t\t\t\t\t.wiki(control.desc)\n\t\t\t\t\t\t.appendTo($header);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst name        = control.name;\n\t\t\tconst id          = Util.slugify(name);\n\t\t\tconst $setting    = jQuery(document.createElement('div'));\n\t\t\tconst $label      = jQuery(document.createElement('label'));\n\t\t\tconst $controlBox = jQuery(document.createElement('div'));\n\t\t\tlet $control;\n\n\t\t\t// Set up the label+control wrapper.\n\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t.append($label)\n\t\t\t\t.append($controlBox)\n\t\t\t\t.appendTo($setting);\n\n\t\t\t// Set up the description, if any.\n\t\t\tif (control.desc) {\n\t\t\t\tjQuery(document.createElement('p'))\n\t\t\t\t\t.attr('id', `setting-desc-${id}`)\n\t\t\t\t\t.wiki(control.desc)\n\t\t\t\t\t.appendTo($setting);\n\t\t\t}\n\n\t\t\t// Set up the label.\n\t\t\t$label\n\t\t\t\t.attr({\n\t\t\t\t\tid  : `setting-label-${id}`,\n\t\t\t\t\tfor : `setting-control-${id}` // must be in sync with $control's ID (see below)\n\t\t\t\t})\n\t\t\t\t.wiki(control.label);\n\n\t\t\t// Set up the control.\n\t\t\tif (settings[name] == null) { // lazy equality for null\n\t\t\t\tsettings[name] = control.default;\n\t\t\t}\n\n\t\t\tswitch (control.type) {\n\t\t\tcase Setting.Types.Toggle:\n\t\t\t\t$control = jQuery(document.createElement('button'));\n\n\t\t\t\tif (settings[name]) {\n\t\t\t\t\t$control\n\t\t\t\t\t\t.addClass('enabled')\n\t\t\t\t\t\t.text(L10n.get('settingsOn'));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$control\n\t\t\t\t\t\t.text(L10n.get('settingsOff'));\n\t\t\t\t}\n\n\t\t\t\t$control.ariaClick(function () {\n\t\t\t\t\tif (settings[name]) {\n\t\t\t\t\t\tjQuery(this)\n\t\t\t\t\t\t\t.removeClass('enabled')\n\t\t\t\t\t\t\t.text(L10n.get('settingsOff'));\n\t\t\t\t\t\tsettings[name] = false;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tjQuery(this)\n\t\t\t\t\t\t\t.addClass('enabled')\n\t\t\t\t\t\t\t.text(L10n.get('settingsOn'));\n\t\t\t\t\t\tsettings[name] = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tSetting.save();\n\n\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\tdefault : control.default\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase Setting.Types.List:\n\t\t\t\t$control = jQuery(document.createElement('select'));\n\n\t\t\t\tfor (let i = 0, iend = control.list.length; i < iend; ++i) {\n\t\t\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t\t\t.val(i)\n\t\t\t\t\t\t.text(control.list[i])\n\t\t\t\t\t\t.appendTo($control);\n\t\t\t\t}\n\n\t\t\t\t$control\n\t\t\t\t\t.val(control.list.indexOf(settings[name]))\n\t\t\t\t\t.attr('tabindex', 0)\n\t\t\t\t\t.on('change', function () {\n\t\t\t\t\t\tsettings[name] = control.list[Number(this.value)];\n\t\t\t\t\t\tSetting.save();\n\n\t\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\t\tdefault : control.default,\n\t\t\t\t\t\t\t\tlist    : control.list\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase Setting.Types.Range:\n\t\t\t\t$control = jQuery(document.createElement('input'));\n\n\t\t\t\t// NOTE: Setting the value with `<jQuery>.val()` can cause odd behavior\n\t\t\t\t// in Edge if it's called before the type is set, so we use the `value`\n\t\t\t\t// content attribute here to dodge the entire issue.\n\t\t\t\t$control\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttype     : 'range',\n\t\t\t\t\t\tmin      : control.min,\n\t\t\t\t\t\tmax      : control.max,\n\t\t\t\t\t\tstep     : control.step,\n\t\t\t\t\t\tvalue    : settings[name],\n\t\t\t\t\t\ttabindex : 0\n\t\t\t\t\t})\n\t\t\t\t\t.on('change input', function () {\n\t\t\t\t\t\tsettings[name] = Number(this.value);\n\t\t\t\t\t\tSetting.save();\n\n\t\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\t\tdefault : control.default,\n\t\t\t\t\t\t\t\tmin     : control.min,\n\t\t\t\t\t\t\t\tmax     : control.max,\n\t\t\t\t\t\t\t\tstep    : control.step\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.on('keypress', ev => {\n\t\t\t\t\t\tif (ev.which === 13) {\n\t\t\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t\t\t$control.trigger('change');\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$control\n\t\t\t\t.attr('id', `setting-control-${id}`)\n\t\t\t\t.appendTo($controlBox);\n\n\t\t\t$setting\n\t\t\t\t.attr('id', `setting-body-${id}`)\n\t\t\t\t.appendTo($dialogBody);\n\t\t});\n\n\t\t// Add the button bar.\n\t\t$dialogBody\n\t\t\t.append(\n\t\t\t\t  '<ul class=\"buttons\">'\n\t\t\t\t+     `<li><button id=\"settings-ok\" class=\"ui-close\">${L10n.get(['settingsOk', 'ok'])}</button></li>`\n\t\t\t\t+     `<li><button id=\"settings-reset\">${L10n.get('settingsReset')}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t)\n\t\t\t.find('#settings-reset')\n\t\t\t/*\n\t\t\t\tInstead of adding '.ui-close' to '#settings-reset' (to receive the use of the default\n\t\t\t\tdelegated dialog close handler), we set up a special case close handler here.  We\n\t\t\t\tdo this to ensure that the invocation of `window.location.reload()` happens after the\n\t\t\t\tdialog has fully closed.  If we did not, then a race condition could occur, causing\n\t\t\t\tdisplay shenanigans.\n\t\t\t*/\n\t\t\t.ariaClick({ one : true }, () => {\n\t\t\t\tjQuery(document).one(':dialogclosed', () => {\n\t\t\t\t\tSetting.reset();\n\t\t\t\t\twindow.location.reload();\n\t\t\t\t});\n\t\t\t\tDialog.close();\n\t\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildShare() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildShare()]'); }\n\n\t\ttry {\n\t\t\tjQuery(Dialog.setup(L10n.get('shareTitle'), 'share list'))\n\t\t\t\t.append(uiAssembleLinkList('StoryShare'));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tconsole.error(ex);\n\t\t\tAlert.error('StoryShare', ex.message);\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tUI Functions, Core.\n\t\t*/\n\t\tassembleLinkList : { value : uiAssembleLinkList },\n\n\t\t/*\n\t\t\tUI Functions, Built-ins.\n\t\t*/\n\t\talert         : { value : uiOpenAlert },\n\t\tjumpto        : { value : uiOpenJumpto },\n\t\trestart       : { value : uiOpenRestart },\n\t\tsaves         : { value : uiOpenSaves },\n\t\tsettings      : { value : uiOpenSettings },\n\t\tshare         : { value : uiOpenShare },\n\t\tbuildAutoload : { value : uiBuildAutoload },\n\t\tbuildJumpto   : { value : uiBuildJumpto },\n\t\tbuildRestart  : { value : uiBuildRestart },\n\t\tbuildSaves    : { value : uiBuildSaves },\n\t\tbuildSettings : { value : uiBuildSettings },\n\t\tbuildShare    : { value : uiBuildShare },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\t// `UIBar` methods.\n\t\t/* global UIBar */\n\t\tstow                     : { value : () => UIBar.stow() },\n\t\tunstow                   : { value : () => UIBar.unstow() },\n\t\tsetStoryElements         : { value : () => UIBar.update() },\n\t\t// `Dialog` methods.\n\t\tisOpen                   : { value : (...args) => Dialog.isOpen(...args) },\n\t\tbody                     : { value : () => Dialog.body() },\n\t\tsetup                    : { value : (...args) => Dialog.setup(...args) },\n\t\taddClickHandler          : { value : (...args) => Dialog.addClickHandler(...args) },\n\t\topen                     : { value : (...args) => Dialog.open(...args) },\n\t\tclose                    : { value : (...args) => Dialog.close(...args) },\n\t\tresize                   : { value : () => Dialog.resize() },\n\t\t// Deprecated method names.\n\t\tbuildDialogAutoload      : { value : uiBuildAutoload },\n\t\tbuildDialogJumpto        : { value : uiBuildJumpto },\n\t\tbuildDialogRestart       : { value : uiBuildRestart },\n\t\tbuildDialogSaves         : { value : uiBuildSaves },\n\t\tbuildDialogSettings      : { value : uiBuildSettings },\n\t\tbuildDialogShare         : { value : uiBuildShare },\n\t\tbuildLinkListFromPassage : { value : uiAssembleLinkList }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tuibar.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Dialog, Engine, L10n, Setting, State, Story, UI, Config, setDisplayTitle, setPageElement\n*/\n\nvar UIBar = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// UI bar element cache.\n\tlet _$uiBar = null;\n\n\n\t/*******************************************************************************\n\t\tUI Bar Functions.\n\t*******************************************************************************/\n\n\tfunction uiBarDestroy() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarDestroy()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Hide the UI bar.\n\t\t_$uiBar.hide();\n\n\t\t// Remove its namespaced events.\n\t\tjQuery(document).off('.ui-bar');\n\n\t\t// Remove its styles.\n\t\tjQuery(document.head).find('#style-ui-bar').remove();\n\n\t\t// Remove it from the DOM.\n\t\t_$uiBar.remove();\n\n\t\t// Drop the reference to the element.\n\t\t_$uiBar = null;\n\t}\n\n\tfunction uiBarHide() {\n\t\tif (_$uiBar) {\n\t\t\t_$uiBar.hide();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarInit() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarInit()]'); }\n\n\t\tif (document.getElementById('ui-bar')) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Generate the UI bar elements.\n\t\tconst $elems = (() => {\n\t\t\tconst toggleLabel   = L10n.get('uiBarToggle');\n\t\t\tconst backwardLabel = L10n.get('uiBarBackward');\n\t\t\tconst jumptoLabel   = L10n.get('uiBarJumpto');\n\t\t\tconst forwardLabel  = L10n.get('uiBarForward');\n\n\t\t\treturn jQuery(document.createDocumentFragment())\n\t\t\t\t.append(\n\t\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t\t  '<div id=\"ui-bar\">'\n\t\t\t\t\t+     '<div id=\"ui-bar-tray\">'\n\t\t\t\t\t+         `<button id=\"ui-bar-toggle\" tabindex=\"0\" title=\"${toggleLabel}\" aria-label=\"${toggleLabel}\"></button>`\n\t\t\t\t\t+         '<div id=\"ui-bar-history\">'\n\t\t\t\t\t+             `<button id=\"history-backward\" tabindex=\"0\" title=\"${backwardLabel}\" aria-label=\"${backwardLabel}\">\\uE821</button>`\n\t\t\t\t\t+             `<button id=\"history-jumpto\" tabindex=\"0\" title=\"${jumptoLabel}\" aria-label=\"${jumptoLabel}\">\\uE839</button>`\n\t\t\t\t\t+             `<button id=\"history-forward\" tabindex=\"0\" title=\"${forwardLabel}\" aria-label=\"${forwardLabel}\">\\uE822</button>`\n\t\t\t\t\t+         '</div>'\n\t\t\t\t\t+     '</div>'\n\t\t\t\t\t+     '<div id=\"ui-bar-body\">'\n\t\t\t\t\t+         '<header id=\"title\" role=\"banner\">'\n\t\t\t\t\t+             '<div id=\"story-banner\"></div>'\n\t\t\t\t\t+             '<h1 id=\"story-title\"></h1>'\n\t\t\t\t\t+             '<div id=\"story-subtitle\"></div>'\n\t\t\t\t\t+             '<div id=\"story-title-separator\"></div>'\n\t\t\t\t\t+             '<p id=\"story-author\"></p>'\n\t\t\t\t\t+         '</header>'\n\t\t\t\t\t+         '<div id=\"story-caption\"></div>'\n\t\t\t\t\t+         '<nav id=\"menu\" role=\"navigation\">'\n\t\t\t\t\t+             '<ul id=\"menu-story\"></ul>'\n\t\t\t\t\t+             '<ul id=\"menu-core\">'\n\t\t\t\t\t+                 `<li id=\"menu-item-saves\"><a tabindex=\"0\">${L10n.get('savesTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-settings\"><a tabindex=\"0\">${L10n.get('settingsTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-restart\"><a tabindex=\"0\">${L10n.get('restartTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-share\"><a tabindex=\"0\">${L10n.get('shareTitle')}</a></li>`\n\t\t\t\t\t+             '</ul>'\n\t\t\t\t\t+         '</nav>'\n\t\t\t\t\t+     '</div>'\n\t\t\t\t\t+ '</div>'\n\t\t\t\t\t/* eslint-enable max-len */\n\t\t\t\t);\n\t\t})();\n\n\t\t/*\n\t\t\tCache the UI bar element, since its going to be used often.\n\n\t\t\tNOTE: We rewrap the element itself, rather than simply using the result\n\t\t\tof `find()`, so that we cache an uncluttered jQuery-wrapper (i.e. `context`\n\t\t\trefers to the element and there is no `prevObject`).\n\t\t*/\n\t\t_$uiBar = jQuery($elems.find('#ui-bar').get(0));\n\n\t\t// Insert the UI bar elements into the page before the main script.\n\t\t$elems.insertBefore('body>script#script-sugarcube');\n\n\t\t// Set up the UI bar's global event handlers.\n\t\tjQuery(document)\n\t\t\t// Set up a handler for the history-backward/-forward buttons.\n\t\t\t.on(':historyupdate.ui-bar', (($backward, $forward) => () => {\n\t\t\t\t$backward.ariaDisabled(State.length < 2);\n\t\t\t\t$forward.ariaDisabled(State.length === State.size);\n\t\t\t})(jQuery('#history-backward'), jQuery('#history-forward')));\n\t}\n\n\tfunction uiBarIsHidden() {\n\t\treturn _$uiBar && _$uiBar.css('display') === 'none';\n\t}\n\n\tfunction uiBarIsStowed() {\n\t\treturn _$uiBar && _$uiBar.hasClass('stowed');\n\t}\n\n\tfunction uiBarShow() {\n\t\tif (_$uiBar) {\n\t\t\t_$uiBar.show();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarStart() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarStart()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Set up the #ui-bar's initial state.\n\t\tif (\n\t\t\ttypeof Config.ui.stowBarInitially === 'boolean'\n\t\t\t\t? Config.ui.stowBarInitially\n\t\t\t\t: jQuery(window).width() <= Config.ui.stowBarInitially\n\t\t) {\n\t\t\tuiBarStow(true);\n\t\t}\n\n\t\t// Set up the #ui-bar-toggle and #ui-bar-history widgets.\n\t\tjQuery('#ui-bar-toggle')\n\t\t\t.ariaClick({\n\t\t\t\tlabel : L10n.get('uiBarToggle')\n\t\t\t}, () => _$uiBar.toggleClass('stowed'));\n\n\t\tif (Config.history.controls) {\n\t\t\tjQuery('#history-backward')\n\t\t\t\t.ariaDisabled(State.length < 2)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tlabel : L10n.get('uiBarBackward')\n\t\t\t\t}, () => Engine.backward());\n\n\t\t\tif (Story.lookup('tags', 'bookmark').length > 0) {\n\t\t\t\tjQuery('#history-jumpto')\n\t\t\t\t\t.ariaClick({\n\t\t\t\t\t\tlabel : L10n.get('uiBarJumpto')\n\t\t\t\t\t}, () => UI.jumpto());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery('#history-jumpto').remove();\n\t\t\t}\n\n\t\t\tjQuery('#history-forward')\n\t\t\t\t.ariaDisabled(State.length === State.size)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tlabel : L10n.get('uiBarForward')\n\t\t\t\t}, () => Engine.forward());\n\t\t}\n\t\telse {\n\t\t\tjQuery('#ui-bar-history').remove();\n\t\t}\n\n\t\t// Set up the story display title.\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t}\n\t\telse {\n\t\t\tif (TWINE1) { // for Twine 1\n\t\t\t\tsetPageElement('story-title', 'StoryTitle', Story.title);\n\t\t\t}\n\t\t\telse { // for Twine 2\n\t\t\t\tjQuery('#story-title').text(Story.title);\n\t\t\t}\n\t\t}\n\n\t\t// Set up the dynamic page elements.\n\t\tif (!Story.has('StoryCaption')) {\n\t\t\tjQuery('#story-caption').remove();\n\t\t}\n\n\t\tif (!Story.has('StoryMenu')) {\n\t\t\tjQuery('#menu-story').remove();\n\t\t}\n\n\t\tif (!Config.ui.updateStoryElements) {\n\t\t\t// We only need to set the story elements here if `Config.ui.updateStoryElements`\n\t\t\t// is falsy, since otherwise they will be set by `Engine.play()`.\n\t\t\tuiBarUpdate();\n\t\t}\n\n\t\t// Set up the Saves menu item.\n\t\tjQuery('#menu-item-saves a')\n\t\t\t.ariaClick(ev => {\n\t\t\t\tev.preventDefault();\n\t\t\t\tUI.buildSaves();\n\t\t\t\tDialog.open();\n\t\t\t})\n\t\t\t.text(L10n.get('savesTitle'));\n\n\t\t// Set up the Settings menu item.\n\t\tif (!Setting.isEmpty()) {\n\t\t\tjQuery('#menu-item-settings a')\n\t\t\t\t.ariaClick(ev => {\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\tUI.buildSettings();\n\t\t\t\t\tDialog.open();\n\t\t\t\t})\n\t\t\t\t.text(L10n.get('settingsTitle'));\n\t\t}\n\t\telse {\n\t\t\tjQuery('#menu-item-settings').remove();\n\t\t}\n\n\t\t// Set up the Restart menu item.\n\t\tjQuery('#menu-item-restart a')\n\t\t\t.ariaClick(ev => {\n\t\t\t\tev.preventDefault();\n\t\t\t\tUI.buildRestart();\n\t\t\t\tDialog.open();\n\t\t\t})\n\t\t\t.text(L10n.get('restartTitle'));\n\n\t\t// Set up the Share menu item.\n\t\tif (Story.has('StoryShare')) {\n\t\t\tjQuery('#menu-item-share a')\n\t\t\t\t.ariaClick(ev => {\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\tUI.buildShare();\n\t\t\t\t\tDialog.open();\n\t\t\t\t})\n\t\t\t\t.text(L10n.get('shareTitle'));\n\t\t}\n\t\telse {\n\t\t\tjQuery('#menu-item-share').remove();\n\t\t}\n\t}\n\n\tfunction uiBarStow(noAnimation) {\n\t\tif (_$uiBar && !_$uiBar.hasClass('stowed')) {\n\t\t\tlet $story;\n\n\t\t\tif (noAnimation) {\n\t\t\t\t$story = jQuery('#story');\n\t\t\t\t$story.addClass('no-transition');\n\t\t\t\t_$uiBar.addClass('no-transition');\n\t\t\t}\n\n\t\t\t_$uiBar.addClass('stowed');\n\n\t\t\tif (noAnimation) {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t$story.removeClass('no-transition');\n\t\t\t\t\t_$uiBar.removeClass('no-transition');\n\t\t\t\t}, Engine.minDomActionDelay);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarUnstow(noAnimation) {\n\t\tif (_$uiBar && _$uiBar.hasClass('stowed')) {\n\t\t\tlet $story;\n\n\t\t\tif (noAnimation) {\n\t\t\t\t$story = jQuery('#story');\n\t\t\t\t$story.addClass('no-transition');\n\t\t\t\t_$uiBar.addClass('no-transition');\n\t\t\t}\n\n\t\t\t_$uiBar.removeClass('stowed');\n\n\t\t\tif (noAnimation) {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t$story.removeClass('no-transition');\n\t\t\t\t\t_$uiBar.removeClass('no-transition');\n\t\t\t\t}, Engine.minDomActionDelay);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarUpdate() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarUpdate()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Set up the (non-navigation) dynamic page elements.\n\t\tsetPageElement('story-banner', 'StoryBanner');\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t}\n\t\tsetPageElement('story-subtitle', 'StorySubtitle');\n\t\tsetPageElement('story-author', 'StoryAuthor');\n\t\tsetPageElement('story-caption', 'StoryCaption');\n\n\t\t// Set up the #menu-story items.\n\t\tconst menuStory = document.getElementById('menu-story');\n\n\t\tif (menuStory !== null) {\n\t\t\tjQuery(menuStory).empty();\n\n\t\t\tif (Story.has('StoryMenu')) {\n\t\t\t\ttry {\n\t\t\t\t\tUI.assembleLinkList('StoryMenu', menuStory);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\tconsole.error(ex);\n\t\t\t\t\tAlert.error('StoryMenu', ex.message);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tdestroy  : { value : uiBarDestroy },\n\t\thide     : { value : uiBarHide },\n\t\tinit     : { value : uiBarInit },\n\t\tisHidden : { value : uiBarIsHidden },\n\t\tisStowed : { value : uiBarIsStowed },\n\t\tshow     : { value : uiBarShow },\n\t\tstart    : { value : uiBarStart },\n\t\tstow     : { value : uiBarStow },\n\t\tunstow   : { value : uiBarUnstow },\n\t\tupdate   : { value : uiBarUpdate },\n\n\t\t// Legacy Functions.\n\t\tsetStoryElements : { value : uiBarUpdate }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tdebugbar.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal DebugView, Engine, L10n, Patterns, State, Util, session\n*/\n\nvar DebugBar = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tconst _variableRe   = new RegExp(`^${Patterns.variable}$`);\n\tconst _numericKeyRe = /^\\d+$/;\n\tconst _watchList    = [];\n\tlet _$debugBar   = null;\n\tlet _$watchBody  = null;\n\tlet _$watchList  = null;\n\tlet _$turnSelect = null;\n\tlet _stowed      = true;\n\n\n\t/*******************************************************************************************************************\n\t\tDebug Bar Functions.\n\t*******************************************************************************************************************/\n\tfunction debugBarInit() {\n\t\tif (DEBUG) { console.log('[DebugBar/debugBarInit()]'); }\n\n\t\t/*\n\t\t\tGenerate the debug bar elements and append them to the `<body>`.\n\t\t*/\n\t\tconst barToggleLabel   = L10n.get('debugBarToggle');\n\t\tconst watchAddLabel    = L10n.get('debugBarAddWatch');\n\t\tconst watchAllLabel    = L10n.get('debugBarWatchAll');\n\t\tconst watchNoneLabel   = L10n.get('debugBarWatchNone');\n\t\tconst watchToggleLabel = L10n.get('debugBarWatchToggle');\n\t\tconst viewsToggleLabel = L10n.get('debugBarViewsToggle');\n\n\t\tjQuery(document.createDocumentFragment())\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  '<div id=\"debug-bar\">'\n\t\t\t\t+     '<div id=\"debug-bar-watch\">'\n\t\t\t\t+         `<div>${L10n.get('debugBarNoWatches')}</div>>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div>'\n\t\t\t\t+         `<button id=\"debug-bar-watch-toggle\" tabindex=\"0\" title=\"${watchToggleLabel}\" aria-label=\"${watchToggleLabel}\">${L10n.get('debugBarLabelWatch')}</button>`\n\t\t\t\t+         `<label id=\"debug-bar-watch-label\" for=\"debug-bar-watch-input\">${L10n.get('debugBarLabelAdd')}</label>`\n\t\t\t\t+         '<input id=\"debug-bar-watch-input\" name=\"debug-bar-watch-input\" type=\"text\" list=\"debug-bar-watch-list\" tabindex=\"0\">'\n\t\t\t\t+         '<datalist id=\"debug-bar-watch-list\" aria-hidden=\"true\" hidden=\"hidden\"></datalist>'\n\t\t\t\t+         `<button id=\"debug-bar-watch-add\" tabindex=\"0\" title=\"${watchAddLabel}\" aria-label=\"${watchAddLabel}\"></button>`\n\t\t\t\t+         `<button id=\"debug-bar-watch-all\" tabindex=\"0\" title=\"${watchAllLabel}\" aria-label=\"${watchAllLabel}\"></button>`\n\t\t\t\t+         `<button id=\"debug-bar-watch-none\" tabindex=\"0\" title=\"${watchNoneLabel}\" aria-label=\"${watchNoneLabel}\"></button>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div>'\n\t\t\t\t+         `<button id=\"debug-bar-views-toggle\" tabindex=\"0\" title=\"${viewsToggleLabel}\" aria-label=\"${viewsToggleLabel}\">${L10n.get('debugBarLabelViews')}</button>`\n\t\t\t\t+         `<label id=\"debug-bar-turn-label\" for=\"debug-bar-turn-select\">${L10n.get('debugBarLabelTurn')}</label>`\n\t\t\t\t+         '<select id=\"debug-bar-turn-select\" tabindex=\"0\"></select>'\n\t\t\t\t+     '</div>'\n\t\t\t\t+     `<button id=\"debug-bar-toggle\" tabindex=\"0\" title=\"${barToggleLabel}\" aria-label=\"${barToggleLabel}\"></button>`\n\t\t\t\t+ '</div>'\n\t\t\t\t+ '<div id=\"debug-bar-hint\"></div>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t)\n\t\t\t.appendTo('body');\n\n\t\t/*\n\t\t\tCache various oft used elements.\n\n\t\t\tNOTE: We rewrap the elements themselves, rather than simply using\n\t\t\tthe results of `find()`, so that we cache uncluttered jQuery-wrappers\n\t\t\t(i.e. `context` refers to the elements and there is no `prevObject`).\n\t\t*/\n\t\t_$debugBar   = jQuery('#debug-bar');\n\t\t_$watchBody  = jQuery(_$debugBar.find('#debug-bar-watch').get(0));\n\t\t_$watchList  = jQuery(_$debugBar.find('#debug-bar-watch-list').get(0));\n\t\t_$turnSelect = jQuery(_$debugBar.find('#debug-bar-turn-select').get(0));\n\n\t\tconst $barToggle   = jQuery(_$debugBar.find('#debug-bar-toggle').get(0));\n\t\tconst $watchToggle = jQuery(_$debugBar.find('#debug-bar-watch-toggle').get(0));\n\t\tconst $watchInput  = jQuery(_$debugBar.find('#debug-bar-watch-input').get(0));\n\t\tconst $watchAdd    = jQuery(_$debugBar.find('#debug-bar-watch-add').get(0));\n\t\tconst $watchAll    = jQuery(_$debugBar.find('#debug-bar-watch-all').get(0));\n\t\tconst $watchNone   = jQuery(_$debugBar.find('#debug-bar-watch-none').get(0));\n\t\tconst $viewsToggle = jQuery(_$debugBar.find('#debug-bar-views-toggle').get(0));\n\n\t\t/*\n\t\t\tSet up the debug bar's local event handlers.\n\t\t*/\n\t\t$barToggle\n\t\t\t.ariaClick(debugBarToggle);\n\t\t$watchToggle\n\t\t\t.ariaClick(debugBarWatchToggle);\n\t\t$watchInput\n\t\t\t.on(':addwatch', function () {\n\t\t\t\tdebugBarWatchAdd(this.value.trim());\n\t\t\t\tthis.value = '';\n\t\t\t})\n\t\t\t.on('keypress', ev => {\n\t\t\t\tif (ev.which === 13) { // 13 is Return/Enter\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t$watchInput.trigger(':addwatch');\n\t\t\t\t}\n\t\t\t});\n\t\t$watchAdd\n\t\t\t.ariaClick(() => $watchInput.trigger(':addwatch'));\n\t\t$watchAll\n\t\t\t.ariaClick(debugBarWatchAddAll);\n\t\t$watchNone\n\t\t\t.ariaClick(debugBarWatchClear);\n\t\t_$turnSelect\n\t\t\t.on('change', function () {\n\t\t\t\tEngine.goTo(Number(this.value));\n\t\t\t});\n\t\t$viewsToggle\n\t\t\t.ariaClick(() => {\n\t\t\t\tDebugView.toggle();\n\t\t\t\t_updateSession();\n\t\t\t});\n\n\t\t/*\n\t\t\tSet up the debug bar's global event handlers.\n\t\t*/\n\t\tjQuery(document)\n\t\t\t// Set up a handler for the history select.\n\t\t\t.on(':historyupdate.debug-bar', _updateTurnSelect)\n\t\t\t// Set up a handler for the variables watch.\n\t\t\t.on(':passageend.debug-bar', () => {\n\t\t\t\t_updateWatchBody();\n\t\t\t\t_updateWatchList();\n\t\t\t})\n\t\t\t// Set up a handler for engine resets to clear the active debug session.\n\t\t\t.on(':enginerestart.debug-bar', _clearSession);\n\n\t\t/*\n\t\t\tInitially enable debug views if there's no active debug session.\n\t\t*/\n\t\tif (!_hasSession()) {\n\t\t\tDebugView.enable();\n\t\t}\n\t}\n\n\tfunction debugBarStart() {\n\t\tif (DEBUG) { console.log('[DebugBar/debugBarStart()]'); }\n\n\t\t// Attempt to restore an existing session.\n\t\t_restoreSession();\n\n\t\t// Update the UI.\n\t\t_updateBar();\n\t\t_updateTurnSelect();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t}\n\n\tfunction debugBarIsStowed() {\n\t\treturn _stowed;\n\t}\n\n\tfunction debugBarStow() {\n\t\t_debugBarStowNoUpdate();\n\t\t_stowed = true;\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarUnstow() {\n\t\t_debugBarUnstowNoUpdate();\n\t\t_stowed = false;\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarToggle() {\n\t\tif (_stowed) {\n\t\t\tdebugBarUnstow();\n\t\t}\n\t\telse {\n\t\t\tdebugBarStow();\n\t\t}\n\t}\n\n\tfunction debugBarWatchAdd(varName) {\n\t\tif (!_variableRe.test(varName)) {\n\t\t\treturn;\n\t\t}\n\n\t\t_watchList.pushUnique(varName);\n\t\t_watchList.sort();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchAddAll() {\n\t\tObject.keys(State.variables).map(name => _watchList.pushUnique(`$${name}`));\n\t\tObject.keys(State.temporary).map(name => _watchList.pushUnique(`_${name}`));\n\n\t\t_watchList.sort();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchClear() {\n\t\tfor (let i = _watchList.length - 1; i >= 0; --i) {\n\t\t\t_watchList.pop();\n\t\t}\n\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchDelete(varName) {\n\t\t_watchList.delete(varName);\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchDisable() {\n\t\t_debugBarWatchDisableNoUpdate();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchEnable() {\n\t\t_debugBarWatchEnableNoUpdate();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchIsEnabled() {\n\t\treturn !_$watchBody.attr('hidden');\n\t}\n\n\tfunction debugBarWatchToggle() {\n\t\tif (_$watchBody.attr('hidden')) {\n\t\t\tdebugBarWatchEnable();\n\t\t}\n\t\telse {\n\t\t\tdebugBarWatchDisable();\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _debugBarStowNoUpdate() {\n\t\t_$debugBar.css('right', `-${_$debugBar.outerWidth()}px`);\n\t}\n\n\tfunction _debugBarUnstowNoUpdate() {\n\t\t_$debugBar.css('right', 0);\n\t}\n\n\tfunction _debugBarWatchDisableNoUpdate() {\n\t\t_$watchBody.attr({\n\t\t\t'aria-hidden' : true,\n\t\t\thidden        : 'hidden'\n\t\t});\n\t}\n\n\tfunction _debugBarWatchEnableNoUpdate() {\n\t\t_$watchBody.removeAttr('aria-hidden hidden');\n\t}\n\n\tfunction _clearSession() {\n\t\tsession.delete('debugState');\n\t}\n\n\tfunction _hasSession() {\n\t\treturn session.has('debugState');\n\t}\n\n\tfunction _restoreSession() {\n\t\tif (!_hasSession()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst debugState = session.get('debugState');\n\n\t\t_stowed = debugState.stowed;\n\n\t\t_watchList.push(...debugState.watchList);\n\n\t\tif (debugState.watchEnabled) {\n\t\t\t_debugBarWatchEnableNoUpdate();\n\t\t}\n\t\telse {\n\t\t\t_debugBarWatchDisableNoUpdate();\n\t\t}\n\n\t\tif (debugState.viewsEnabled) {\n\t\t\tDebugView.enable();\n\t\t}\n\t\telse {\n\t\t\tDebugView.disable();\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction _updateSession() {\n\t\tsession.set('debugState', {\n\t\t\tstowed       : _stowed,\n\t\t\twatchList    : _watchList,\n\t\t\twatchEnabled : debugBarWatchIsEnabled(),\n\t\t\tviewsEnabled : DebugView.isEnabled()\n\t\t});\n\t}\n\n\tfunction _updateBar() {\n\t\tif (_stowed) {\n\t\t\tdebugBarStow();\n\t\t}\n\t\telse {\n\t\t\tdebugBarUnstow();\n\t\t}\n\t}\n\n\tfunction _updateWatchBody() {\n\t\tif (_watchList.length === 0) {\n\t\t\t_$watchBody\n\t\t\t\t.empty()\n\t\t\t\t.append(`<div>${L10n.get('debugBarNoWatches')}</div>`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst delLabel = L10n.get('debugBarDeleteWatch');\n\t\tconst $table   = jQuery(document.createElement('table'));\n\t\tconst $tbody   = jQuery(document.createElement('tbody'));\n\n\t\tfor (let i = 0, len = _watchList.length; i < len; ++i) {\n\t\t\tconst varName = _watchList[i];\n\t\t\tconst varKey  = varName.slice(1);\n\t\t\tconst store   = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\tconst $row    = jQuery(document.createElement('tr'));\n\t\t\tconst $delBtn = jQuery(document.createElement('button'));\n\t\t\tconst $code   = jQuery(document.createElement('code'));\n\n\t\t\t$delBtn\n\t\t\t\t.addClass('watch-delete')\n\t\t\t\t.attr('data-name', varName)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tone   : true,\n\t\t\t\t\tlabel : delLabel\n\t\t\t\t}, () => debugBarWatchDelete(varName));\n\t\t\t$code\n\t\t\t\t.text(_toWatchString(store[varKey]));\n\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.append($delBtn)\n\t\t\t\t.appendTo($row);\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.text(varName)\n\t\t\t\t.appendTo($row);\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.append($code)\n\t\t\t\t.appendTo($row);\n\t\t\t$row\n\t\t\t\t.appendTo($tbody);\n\t\t}\n\n\t\t$table\n\t\t\t.append($tbody);\n\t\t_$watchBody\n\t\t\t.empty()\n\t\t\t.append($table);\n\t}\n\n\tfunction _updateWatchList() {\n\t\tconst svn = Object.keys(State.variables);\n\t\tconst tvn = Object.keys(State.temporary);\n\n\t\tif (svn.length === 0 && tvn.length === 0) {\n\t\t\t_$watchList.empty();\n\t\t\treturn;\n\t\t}\n\n\t\tconst names   = [...svn.map(name => `$${name}`), ...tvn.map(name => `_${name}`)].sort();\n\t\tconst options = document.createDocumentFragment();\n\n\t\tnames.delete(_watchList);\n\n\t\tfor (let i = 0, len = names.length; i < len; ++i) {\n\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t.val(names[i])\n\t\t\t\t.appendTo(options);\n\t\t}\n\n\t\t_$watchList\n\t\t\t.empty()\n\t\t\t.append(options);\n\t}\n\n\tfunction _updateTurnSelect() {\n\t\tconst histLen = State.size;\n\t\tconst expLen  = State.expired.length;\n\t\tconst options = document.createDocumentFragment();\n\n\t\tfor (let i = 0; i < histLen; ++i) {\n\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t.val(i)\n\t\t\t\t.text(`${expLen + i + 1}. ${Util.escape(State.history[i].title)}`)\n\t\t\t\t.appendTo(options);\n\t\t}\n\n\t\t_$turnSelect\n\t\t\t.empty()\n\t\t\t.ariaDisabled(histLen < 2)\n\t\t\t.append(options)\n\t\t\t.val(State.activeIndex);\n\t}\n\n\tfunction _toWatchString(value) {\n\t\t/*\n\t\t\tHandle the `null` primitive.\n\t\t*/\n\t\tif (value === null) {\n\t\t\treturn 'null';\n\t\t}\n\n\t\t/*\n\t\t\tHandle the rest of the primitives and functions.\n\t\t*/\n\t\tswitch (typeof value) {\n\t\tcase 'number':\n\t\t\tif (Number.isNaN(value)) {\n\t\t\t\treturn 'NaN';\n\t\t\t}\n\t\t\telse if (!Number.isFinite(value)) {\n\t\t\t\treturn 'Infinity';\n\t\t\t}\n\t\t\t/* falls through */\n\t\tcase 'boolean':\n\t\tcase 'symbol':\n\t\tcase 'undefined':\n\t\t\treturn String(value);\n\n\t\tcase 'string':\n\t\t\treturn JSON.stringify(value);\n\n\t\t// case 'symbol':\n\t\t// \treturn `Symbol\\u202F\"${String(value).slice(7, -1)}\"`;\n\n\t\tcase 'function':\n\t\t\t// return JSON.stringify(value.toString());\n\t\t\treturn 'Function';\n\t\t}\n\n\t\tconst objType = Util.toStringTag(value);\n\n\t\t// /*\n\t\t// \tHandle instances of the primitive exemplar objects (`Boolean`, `Number`, `String`).\n\t\t// */\n\t\t// if (objType === 'Boolean') {\n\t\t// \treturn `Boolean\\u202F{${String(value)}}`;\n\t\t// }\n\t\t// if (objType === 'Number') {\n\t\t// \treturn `Number\\u202F{${String(value)}}`;\n\t\t// }\n\t\t// if (objType === 'String') {\n\t\t// \treturn `String\\u202F{\"${String(value)}\"}`;\n\t\t// }\n\n\t\t/*\n\t\t\tHandle `Date` objects.\n\t\t*/\n\t\tif (objType === 'Date') {\n\t\t\t// return `Date\\u202F${value.toISOString()}`;\n\t\t\treturn `Date\\u202F{${value.toLocaleString()}}`;\n\t\t}\n\n\t\t/*\n\t\t\tHandle `RegExp` objects.\n\t\t*/\n\t\tif (objType === 'RegExp') {\n\t\t\treturn `RegExp\\u202F${value.toString()}`;\n\t\t}\n\n\t\tconst result = [];\n\n\t\t/*\n\t\t\tHandle `Array` & `Set` objects.\n\t\t*/\n\t\tif (value instanceof Array || value instanceof Set) {\n\t\t\tconst list = value instanceof Array ? value : Array.from(value);\n\n\t\t\t// own numeric properties\n\t\t\t// NOTE: Do not use `<Array>.forEach()` here as it skips undefined members.\n\t\t\tfor (let i = 0, len = list.length; i < len; ++i) {\n\t\t\t\tresult.push(list.hasOwnProperty(i) ? _toWatchString(list[i]) : '<empty>');\n\t\t\t}\n\n\t\t\t// own enumerable non-numeric expando properties\n\t\t\tObject.keys(list)\n\t\t\t\t.filter(key => !_numericKeyRe.test(key))\n\t\t\t\t.forEach(key => result.push(`${_toWatchString(key)}: ${_toWatchString(list[key])}`));\n\n\t\t\treturn `${objType}(${list.length})\\u202F[${result.join(', ')}]`;\n\t\t}\n\n\t\t/*\n\t\t\tHandle `Map` objects.\n\t\t*/\n\t\tif (value instanceof Map) {\n\t\t\tvalue.forEach((val, key) => result.push(`${_toWatchString(key)} \\u2192 ${_toWatchString(val)}`));\n\n\t\t\treturn `${objType}(${value.size})\\u202F{${result.join(', ')}}`;\n\t\t}\n\n\t\t/*\n\t\t\tGeneral object handling.\n\t\t*/\n\t\t// own enumerable properties\n\t\tObject.keys(value)\n\t\t\t.forEach(key => result.push(`${_toWatchString(key)}: ${_toWatchString(value[key])}`));\n\n\t\treturn `${objType}\\u202F{${result.join(', ')}}`;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tDebug Bar Functions.\n\t\t*/\n\t\tinit     : { value : debugBarInit },\n\t\tisStowed : { value : debugBarIsStowed },\n\t\tstart    : { value : debugBarStart },\n\t\tstow     : { value : debugBarStow },\n\t\ttoggle   : { value : debugBarToggle },\n\t\tunstow   : { value : debugBarUnstow },\n\n\t\t/*\n\t\t\tWatch Functions.\n\t\t*/\n\t\twatch : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd       : { value : debugBarWatchAdd },\n\t\t\t\tall       : { value : debugBarWatchAddAll },\n\t\t\t\tclear     : { value : debugBarWatchClear },\n\t\t\t\tdelete    : { value : debugBarWatchDelete },\n\t\t\t\tdisable   : { value : debugBarWatchDisable },\n\t\t\t\tenable    : { value : debugBarWatchEnable },\n\t\t\t\tisEnabled : { value : debugBarWatchIsEnabled },\n\t\t\t\ttoggle    : { value : debugBarWatchToggle }\n\t\t\t}))\n\t\t}\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tloadscreen.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Engine */\n\nvar LoadScreen = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Locks collection.\n\tconst _locks = new Set();\n\n\t// Auto-incrementing lock ID.\n\tlet _autoId = 0;\n\n\n\t/*******************************************************************************************************************\n\t\tLoadScreen Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tInitialize management of the loading screen.\n\t*/\n\tfunction loadScreenInit() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenInit()]'); }\n\n\t\t// Add a `readystatechange` listener for hiding/showing the loading screen.\n\t\tjQuery(document).on('readystatechange.SugarCube', () => {\n\t\t\tif (DEBUG) { console.log(`[LoadScreen/<readystatechange>] document.readyState: \"${document.readyState}\"; locks(${_locks.size}):`, _locks); }\n\n\t\t\tif (_locks.size > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// The value of `document.readyState` may be: 'loading' -> 'interactive' -> 'complete'.\n\t\t\t// Though, to reach this point, it must already be in, at least, the 'interactive' state.\n\t\t\tif (document.readyState === 'complete') {\n\t\t\t\tif (jQuery(document.documentElement).attr('data-init') === 'loading') {\n\t\t\t\t\tif (Config.loadDelay > 0) {\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tif (_locks.size === 0) {\n\t\t\t\t\t\t\t\tloadScreenHide();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, Math.max(Engine.minDomActionDelay, Config.loadDelay));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tloadScreenHide();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloadScreenShow();\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\tClear the loading screen.\n\t*/\n\tfunction loadScreenClear() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenClear()]'); }\n\n\t\t// Remove the event listener.\n\t\tjQuery(document).off('readystatechange.SugarCube');\n\n\t\t// Clear all locks.\n\t\t_locks.clear();\n\n\t\t// Hide the loading screen.\n\t\tloadScreenHide();\n\t}\n\n\t/*\n\t\tHide the loading screen.\n\t*/\n\tfunction loadScreenHide() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenHide()]'); }\n\n\t\tjQuery(document.documentElement).removeAttr('data-init');\n\t}\n\n\t/*\n\t\tShow the loading screen.\n\t*/\n\tfunction loadScreenShow() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenShow()]'); }\n\n\t\tjQuery(document.documentElement).attr('data-init', 'loading');\n\t}\n\n\t/*\n\t\tReturns a new lock ID after locking and showing the loading screen.\n\t*/\n\tfunction loadScreenLock() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenLock()]'); }\n\n\t\t++_autoId;\n\t\t_locks.add(_autoId);\n\n\t\tif (DEBUG) { console.log(`\\tacquired loading screen lock; id: ${_autoId}`); }\n\n\t\tloadScreenShow();\n\t\treturn _autoId;\n\t}\n\n\t/*\n\t\tRemove the lock associated with the given lock ID and, if no locks remain,\n\t\ttrigger a `readystatechange` event.\n\t*/\n\tfunction loadScreenUnlock(id) {\n\t\tif (DEBUG) { console.log(`[LoadScreen/loadScreenUnlock(id: ${id})]`); }\n\n\t\tif (id == null) { // lazy equality for null\n\t\t\tthrow new Error('LoadScreen.unlock called with a null or undefined ID');\n\t\t}\n\n\t\tif (_locks.has(id)) {\n\t\t\t_locks.delete(id);\n\n\t\t\tif (DEBUG) { console.log(`\\treleased loading screen lock; id: ${id}`); }\n\t\t}\n\n\t\tif (_locks.size === 0) {\n\t\t\tjQuery(document).trigger('readystatechange');\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : loadScreenInit },\n\t\tclear  : { value : loadScreenClear },\n\t\thide   : { value : loadScreenHide },\n\t\tshow   : { value : loadScreenShow },\n\t\tlock   : { value : loadScreenLock },\n\t\tunlock : { value : loadScreenUnlock }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tsugarcube.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Browser, Config, Dialog, Engine, Fullscreen, Has, LoadScreen, SimpleStore, L10n, Macro, Passage,\n\t       Save, Scripting, Setting, SimpleAudio, State, Story, UI, UIBar, DebugBar, Util, Visibility, Wikifier\n*/\n/* eslint-disable no-var */\n\n/*\n\tVersion object.\n*/\nvar version = Object.freeze({\n\ttitle      : 'SugarCube',\n\tmajor      : 2,\n\tminor      : 31,\n\tpatch      : 1,\n\tprerelease : null,\n\tbuild      : 22,\n\tdate       : new Date(\"2020-05-06T21:54:46.872Z\"),\n\t/* legacy */\n\textensions : {},\n\t/* /legacy */\n\n\ttoString() {\n\t\t'use strict';\n\n\t\tconst prerelease = this.prerelease ? `-${this.prerelease}` : '';\n\t\treturn `${this.major}.${this.minor}.${this.patch}${prerelease}+${this.build}`;\n\t},\n\n\tshort() {\n\t\t'use strict';\n\n\t\tconst prerelease = this.prerelease ? `-${this.prerelease}` : '';\n\t\treturn `${this.title} (v${this.major}.${this.minor}.${this.patch}${prerelease})`;\n\t},\n\n\tlong() {\n\t\t'use strict';\n\n\t\treturn `${this.title} v${this.toString()} (${this.date.toUTCString()})`;\n\t}\n});\n\n/* eslint-disable no-unused-vars */\n/*\n\tInternal variables.\n*/\n// Temporary state object.\nvar TempState = {};\n\n// Legacy macros object.\nvar macros = {};\n\n// Post-display task callbacks object.\nvar postdisplay = {};\n\n// Post-render task callbacks object.\nvar postrender = {};\n\n// Pre-display task callbacks object.\nvar predisplay = {};\n\n// Pre-history task callbacks object.\nvar prehistory = {};\n\n// Pre-render task callbacks object.\nvar prerender = {};\n\n// Session storage manager object.\nvar session = null;\n\n// Settings object.\nvar settings = {};\n\n// Setup object.\nvar setup = {};\n\n// Persistant storage manager object.\nvar storage = null;\n\n/*\n\tLegacy aliases.\n*/\nvar browser       = Browser;\nvar config        = Config;\nvar has           = Has;\nvar History       = State;\nvar state         = State;\nvar tale          = Story;\nvar TempVariables = State.temporary;\n/* eslint-enable no-unused-vars */\n\n/*\n\tGlobal `SugarCube` object.  Allows scripts to detect if they're running in SugarCube by\n\ttesting for the object (e.g. `\"SugarCube\" in window`) and contains exported identifiers\n\tfor debugging purposes.\n*/\nwindow.SugarCube = {};\n\n/*\n\tMain function, entry point for the story.\n*/\njQuery(() => {\n\t'use strict';\n\n\tif (DEBUG) { console.log('[SugarCube/main()] Document loaded; beginning startup.'); }\n\n\t/*\n\t\tWARNING!\n\n\t\tThe ordering of the code within this function is critically important,\n\t\tso be careful when mucking around with it.\n\t*/\n\ttry {\n\t\t// Acquire an initial lock for and initialize the loading screen.\n\t\tconst lockId = LoadScreen.lock();\n\t\tLoadScreen.init();\n\n\t\t// Normalize the document.\n\t\tif (document.normalize) {\n\t\t\tdocument.normalize();\n\t\t}\n\n\t\t// Load the story data (must be done before most anything else).\n\t\tStory.load();\n\n\t\t// Instantiate the storage and session objects.\n\t\t// NOTE: `SimpleStore.create(storageId, persistent)`\n\t\tstorage = SimpleStore.create(Story.domId, true);\n\t\tsession = SimpleStore.create(Story.domId, false);\n\n\t\t// Initialize the user interface (must be done before story initialization, specifically before scripts).\n\t\tDialog.init();\n\t\tUIBar.init();\n\t\tEngine.init();\n\n\t\t// Initialize the story (largely load the user styles, scripts, and widgets).\n\t\tStory.init();\n\n\t\t// Initialize the localization (must be done after story initialization).\n\t\tL10n.init();\n\n\t\t// Alert when the browser is degrading required capabilities (must be done after localization initialization).\n\t\tif (!session.has('rcWarn') && storage.name === 'cookie') {\n\t\t\t/* eslint-disable no-alert */\n\t\t\tsession.set('rcWarn', 1);\n\t\t\twindow.alert(L10n.get('warningNoWebStorage'));\n\t\t\t/* eslint-enable no-alert */\n\t\t}\n\n\t\t// Initialize the saves (must be done after story initialization, but before engine start).\n\t\tSave.init();\n\n\t\t// Initialize the settings.\n\t\tSetting.init();\n\n\t\t// Initialize the macros.\n\t\tMacro.init();\n\n\t\t// Start the engine (should be done as late as possible, but before interface startup).\n\t\tEngine.start();\n\n\t\t// Initialize the debug bar interface (should be done as late as possible, but before interface startup).\n\t\tif (Config.debug) {\n\t\t\tDebugBar.init();\n\t\t}\n\n\t\t// Set a recurring timer to start the interfaces (necessary due to DOM readiness issues in some browsers).\n\t\tconst $window    = $(window);\n\t\tconst vprCheckId = setInterval(() => {\n\t\t\t// If `$window.width()` returns a zero value, bail out and wait.\n\t\t\tif (!$window.width()) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Clear the recurring timer.\n\t\t\tclearInterval(vprCheckId);\n\n\t\t\t// Start the UI bar interface.\n\t\t\tUIBar.start();\n\n\t\t\t// Start the debug bar interface.\n\t\t\tif (Config.debug) {\n\t\t\t\tDebugBar.start();\n\t\t\t}\n\n\t\t\t// Trigger the `:storyready` global synthetic event.\n\t\t\tjQuery.event.trigger({ type : ':storyready' });\n\n\t\t\t// Release the loading screen lock after a short delay.\n\t\t\tsetTimeout(() => LoadScreen.unlock(lockId), Engine.minDomActionDelay * 2);\n\t\t}, Engine.minDomActionDelay);\n\n\t\t// Finally, export identifiers for debugging purposes.\n\t\tObject.defineProperty(window, 'SugarCube', {\n\t\t\t// WARNING: We need to assign new values at points, so seal it, do not freeze it.\n\t\t\tvalue : Object.seal(Object.assign(Object.create(null), {\n\t\t\t\tBrowser,\n\t\t\t\tConfig,\n\t\t\t\tDialog,\n\t\t\t\tEngine,\n\t\t\t\tFullscreen,\n\t\t\t\tHas,\n\t\t\t\tL10n,\n\t\t\t\tMacro,\n\t\t\t\tPassage,\n\t\t\t\tSave,\n\t\t\t\tScripting,\n\t\t\t\tSetting,\n\t\t\t\tSimpleAudio,\n\t\t\t\tState,\n\t\t\t\tStory,\n\t\t\t\tUI,\n\t\t\t\tUIBar,\n\t\t\t\tDebugBar,\n\t\t\t\tUtil,\n\t\t\t\tVisibility,\n\t\t\t\tWikifier,\n\t\t\t\tsession,\n\t\t\t\tsettings,\n\t\t\t\tsetup,\n\t\t\t\tstorage,\n\t\t\t\tversion\n\t\t\t}))\n\t\t});\n\n\t\tif (DEBUG) { console.log('[SugarCube/main()] Startup complete; story ready.'); }\n\t}\n\tcatch (ex) {\n\t\tconsole.error(ex);\n\t\tLoadScreen.clear();\n\t\treturn Alert.fatal(null, ex.message, ex);\n\t}\n});\n\n})(window, window.document, jQuery);\n}\n\t</script>\n</body>\n</html>\n"});
\ No newline at end of file
diff --git a/devNotes/sugarcube stuff/2.31.1-format.js b/devNotes/sugarcube stuff/2.31.1-format.js
index 416e757805b..0a6c2339ca2 100644
--- a/devNotes/sugarcube stuff/2.31.1-format.js	
+++ b/devNotes/sugarcube stuff/2.31.1-format.js	
@@ -1 +1 @@
-window.storyFormat({"name":"SugarCube","version":"2.31.1","description":"A full featured, highly customizable story format.  See its <a href=\"http://www.motoslave.net/sugarcube/2/#documentation\" target=\"_blank\">documentation</a>.","author":"Thomas Michael Edwards","image":"icon.svg","url":"http://www.motoslave.net/sugarcube/","license":"BSD-2-Clause","proofing":false,"source":"<!DOCTYPE html>\n<html data-init=\"no-js\">\n<head>\n<meta charset=\"UTF-8\" />\n<title>{{STORY_NAME}}</title>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n<!--\n\nSugarCube (v2.31.1): A free (gratis and libre) story format.\n\nCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n-->\n<script id=\"script-libraries\" type=\"text/javascript\">\nif(document.head&&document.addEventListener&&document.querySelector&&Object.create&&Object.freeze&&JSON){document.documentElement.setAttribute(\"data-init\", \"loading\");\n/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js */\nif(\"document\" in self){if(!(\"classList\" in document.createElement(\"_\"))){(function(j){\"use strict\";if(!(\"Element\" in j)){return}var a=\"classList\",f=\"prototype\",m=j.Element[f],b=Object,k=String[f].trim||function(){return this.replace(/^\\s+|\\s+$/g,\"\")},c=Array[f].indexOf||function(q){var p=0,o=this.length;for(;p<o;p++){if(p in this&&this[p]===q){return p}}return -1},n=function(o,p){this.name=o;this.code=DOMException[o];this.message=p},g=function(p,o){if(o===\"\"){throw new n(\"SYNTAX_ERR\",\"An invalid or illegal string was specified\")}if(/\\s/.test(o)){throw new n(\"INVALID_CHARACTER_ERR\",\"String contains an invalid character\")}return c.call(p,o)},d=function(s){var r=k.call(s.getAttribute(\"class\")||\"\"),q=r?r.split(/\\s+/):[],p=0,o=q.length;for(;p<o;p++){this.push(q[p])}this._updateClassName=function(){s.setAttribute(\"class\",this.toString())}},e=d[f]=[],i=function(){return new d(this)};n[f]=Error[f];e.item=function(o){return this[o]||null};e.contains=function(o){o+=\"\";return g(this,o)!==-1};e.add=function(){var s=arguments,r=0,p=s.length,q,o=false;do{q=s[r]+\"\";if(g(this,q)===-1){this.push(q);o=true}}while(++r<p);if(o){this._updateClassName()}};e.remove=function(){var t=arguments,s=0,p=t.length,r,o=false,q;do{r=t[s]+\"\";q=g(this,r);while(q!==-1){this.splice(q,1);o=true;q=g(this,r)}}while(++s<p);if(o){this._updateClassName()}};e.toggle=function(p,q){p+=\"\";var o=this.contains(p),r=o?q!==true&&\"remove\":q!==false&&\"add\";if(r){this[r](p)}if(q===true||q===false){return q}else{return !o}};e.toString=function(){return this.join(\" \")};if(b.defineProperty){var l={get:i,enumerable:true,configurable:true};try{b.defineProperty(m,a,l)}catch(h){if(h.number===-2146823252){l.enumerable=false;b.defineProperty(m,a,l)}}}else{if(b[f].__defineGetter__){m.__defineGetter__(a,i)}}}(self))}else{(function(){var b=document.createElement(\"_\");b.classList.add(\"c1\",\"c2\");if(!b.classList.contains(\"c2\")){var c=function(e){var d=DOMTokenList.prototype[e];DOMTokenList.prototype[e]=function(h){var g,f=arguments.length;for(g=0;g<f;g++){h=arguments[g];d.call(this,h)}}};c(\"add\");c(\"remove\")}b.classList.toggle(\"c3\",false);if(b.classList.contains(\"c3\")){var a=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(d,e){if(1 in arguments&&!this.contains(d)===!e){return e}else{return a.call(this,d)}}}b=null}())}};\n/*!\n * https://github.com/es-shims/es5-shim\n * @license es5-shim Copyright 2009-2015 by contributors, MIT License\n * see https://github.com/es-shims/es5-shim/blob/v4.5.13/LICENSE\n */\n(function(t,r){\"use strict\";if(typeof define===\"function\"&&define.amd){define(r)}else if(typeof exports===\"object\"){module.exports=r()}else{t.returnExports=r()}})(this,function(){var t=Array;var r=t.prototype;var e=Object;var n=e.prototype;var i=Function;var a=i.prototype;var o=String;var f=o.prototype;var u=Number;var l=u.prototype;var s=r.slice;var c=r.splice;var v=r.push;var h=r.unshift;var p=r.concat;var y=r.join;var d=a.call;var g=a.apply;var w=Math.max;var b=Math.min;var T=n.toString;var m=typeof Symbol===\"function\"&&typeof Symbol.toStringTag===\"symbol\";var D;var S=Function.prototype.toString,x=/^\\s*class /,O=function isES6ClassFn(t){try{var r=S.call(t);var e=r.replace(/\\/\\/.*\\n/g,\"\");var n=e.replace(/\\/\\*[.\\s\\S]*\\*\\//g,\"\");var i=n.replace(/\\n/gm,\" \").replace(/ {2}/g,\" \");return x.test(i)}catch(a){return false}},E=function tryFunctionObject(t){try{if(O(t)){return false}S.call(t);return true}catch(r){return false}},j=\"[object Function]\",I=\"[object GeneratorFunction]\",D=function isCallable(t){if(!t){return false}if(typeof t!==\"function\"&&typeof t!==\"object\"){return false}if(m){return E(t)}if(O(t)){return false}var r=T.call(t);return r===j||r===I};var M;var U=RegExp.prototype.exec,$=function tryRegexExec(t){try{U.call(t);return true}catch(r){return false}},F=\"[object RegExp]\";M=function isRegex(t){if(typeof t!==\"object\"){return false}return m?$(t):T.call(t)===F};var N;var C=String.prototype.valueOf,k=function tryStringObject(t){try{C.call(t);return true}catch(r){return false}},A=\"[object String]\";N=function isString(t){if(typeof t===\"string\"){return true}if(typeof t!==\"object\"){return false}return m?k(t):T.call(t)===A};var R=e.defineProperty&&function(){try{var t={};e.defineProperty(t,\"x\",{enumerable:false,value:t});for(var r in t){return false}return t.x===t}catch(n){return false}}();var P=function(t){var r;if(R){r=function(t,r,n,i){if(!i&&r in t){return}e.defineProperty(t,r,{configurable:true,enumerable:false,writable:true,value:n})}}else{r=function(t,r,e,n){if(!n&&r in t){return}t[r]=e}}return function defineProperties(e,n,i){for(var a in n){if(t.call(n,a)){r(e,a,n[a],i)}}}}(n.hasOwnProperty);var J=function isPrimitive(t){var r=typeof t;return t===null||r!==\"object\"&&r!==\"function\"};var Y=u.isNaN||function isActualNaN(t){return t!==t};var z={ToInteger:function ToInteger(t){var r=+t;if(Y(r)){r=0}else if(r!==0&&r!==1/0&&r!==-(1/0)){r=(r>0||-1)*Math.floor(Math.abs(r))}return r},ToPrimitive:function ToPrimitive(t){var r,e,n;if(J(t)){return t}e=t.valueOf;if(D(e)){r=e.call(t);if(J(r)){return r}}n=t.toString;if(D(n)){r=n.call(t);if(J(r)){return r}}throw new TypeError},ToObject:function(t){if(t==null){throw new TypeError(\"can't convert \"+t+\" to object\")}return e(t)},ToUint32:function ToUint32(t){return t>>>0}};var Z=function Empty(){};P(a,{bind:function bind(t){var r=this;if(!D(r)){throw new TypeError(\"Function.prototype.bind called on incompatible \"+r)}var n=s.call(arguments,1);var a;var o=function(){if(this instanceof a){var i=g.call(r,this,p.call(n,s.call(arguments)));if(e(i)===i){return i}return this}else{return g.call(r,t,p.call(n,s.call(arguments)))}};var f=w(0,r.length-n.length);var u=[];for(var l=0;l<f;l++){v.call(u,\"$\"+l)}a=i(\"binder\",\"return function (\"+y.call(u,\",\")+\"){ return binder.apply(this, arguments); }\")(o);if(r.prototype){Z.prototype=r.prototype;a.prototype=new Z;Z.prototype=null}return a}});var G=d.bind(n.hasOwnProperty);var H=d.bind(n.toString);var W=d.bind(s);var B=g.bind(s);if(typeof document===\"object\"&&document&&document.documentElement){try{W(document.documentElement.childNodes)}catch(X){var L=W;var q=B;W=function arraySliceIE(t){var r=[];var e=t.length;while(e-- >0){r[e]=t[e]}return q(r,L(arguments,1))};B=function arraySliceApplyIE(t,r){return q(W(t),r)}}}var K=d.bind(f.slice);var Q=d.bind(f.split);var V=d.bind(f.indexOf);var _=d.bind(v);var tt=d.bind(n.propertyIsEnumerable);var rt=d.bind(r.sort);var et=t.isArray||function isArray(t){return H(t)===\"[object Array]\"};var nt=[].unshift(0)!==1;P(r,{unshift:function(){h.apply(this,arguments);return this.length}},nt);P(t,{isArray:et});var it=e(\"a\");var at=it[0]!==\"a\"||!(0 in it);var ot=function properlyBoxed(t){var r=true;var e=true;var n=false;if(t){try{t.call(\"foo\",function(t,e,n){if(typeof n!==\"object\"){r=false}});t.call([1],function(){\"use strict\";e=typeof this===\"string\"},\"x\")}catch(i){n=true}}return!!t&&!n&&r&&e};P(r,{forEach:function forEach(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=-1;var i=z.ToUint32(e.length);var a;if(arguments.length>1){a=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.forEach callback must be a function\")}while(++n<i){if(n in e){if(typeof a===\"undefined\"){t(e[n],n,r)}else{t.call(a,e[n],n,r)}}}}},!ot(r.forEach));P(r,{map:function map(r){var e=z.ToObject(this);var n=at&&N(this)?Q(this,\"\"):e;var i=z.ToUint32(n.length);var a=t(i);var o;if(arguments.length>1){o=arguments[1]}if(!D(r)){throw new TypeError(\"Array.prototype.map callback must be a function\")}for(var f=0;f<i;f++){if(f in n){if(typeof o===\"undefined\"){a[f]=r(n[f],f,e)}else{a[f]=r.call(o,n[f],f,e)}}}return a}},!ot(r.map));P(r,{filter:function filter(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i=[];var a;var o;if(arguments.length>1){o=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.filter callback must be a function\")}for(var f=0;f<n;f++){if(f in e){a=e[f];if(typeof o===\"undefined\"?t(a,f,r):t.call(o,a,f,r)){_(i,a)}}}return i}},!ot(r.filter));P(r,{every:function every(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i;if(arguments.length>1){i=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.every callback must be a function\")}for(var a=0;a<n;a++){if(a in e&&!(typeof i===\"undefined\"?t(e[a],a,r):t.call(i,e[a],a,r))){return false}}return true}},!ot(r.every));P(r,{some:function some(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i;if(arguments.length>1){i=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.some callback must be a function\")}for(var a=0;a<n;a++){if(a in e&&(typeof i===\"undefined\"?t(e[a],a,r):t.call(i,e[a],a,r))){return true}}return false}},!ot(r.some));var ft=false;if(r.reduce){ft=typeof r.reduce.call(\"es5\",function(t,r,e,n){return n})===\"object\"}P(r,{reduce:function reduce(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);if(!D(t)){throw new TypeError(\"Array.prototype.reduce callback must be a function\")}if(n===0&&arguments.length===1){throw new TypeError(\"reduce of empty array with no initial value\")}var i=0;var a;if(arguments.length>=2){a=arguments[1]}else{do{if(i in e){a=e[i++];break}if(++i>=n){throw new TypeError(\"reduce of empty array with no initial value\")}}while(true)}for(;i<n;i++){if(i in e){a=t(a,e[i],i,r)}}return a}},!ft);var ut=false;if(r.reduceRight){ut=typeof r.reduceRight.call(\"es5\",function(t,r,e,n){return n})===\"object\"}P(r,{reduceRight:function reduceRight(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);if(!D(t)){throw new TypeError(\"Array.prototype.reduceRight callback must be a function\")}if(n===0&&arguments.length===1){throw new TypeError(\"reduceRight of empty array with no initial value\")}var i;var a=n-1;if(arguments.length>=2){i=arguments[1]}else{do{if(a in e){i=e[a--];break}if(--a<0){throw new TypeError(\"reduceRight of empty array with no initial value\")}}while(true)}if(a<0){return i}do{if(a in e){i=t(i,e[a],a,r)}}while(a--);return i}},!ut);var lt=r.indexOf&&[0,1].indexOf(1,2)!==-1;P(r,{indexOf:function indexOf(t){var r=at&&N(this)?Q(this,\"\"):z.ToObject(this);var e=z.ToUint32(r.length);if(e===0){return-1}var n=0;if(arguments.length>1){n=z.ToInteger(arguments[1])}n=n>=0?n:w(0,e+n);for(;n<e;n++){if(n in r&&r[n]===t){return n}}return-1}},lt);var st=r.lastIndexOf&&[0,1].lastIndexOf(0,-3)!==-1;P(r,{lastIndexOf:function lastIndexOf(t){var r=at&&N(this)?Q(this,\"\"):z.ToObject(this);var e=z.ToUint32(r.length);if(e===0){return-1}var n=e-1;if(arguments.length>1){n=b(n,z.ToInteger(arguments[1]))}n=n>=0?n:e-Math.abs(n);for(;n>=0;n--){if(n in r&&t===r[n]){return n}}return-1}},st);var ct=function(){var t=[1,2];var r=t.splice();return t.length===2&&et(r)&&r.length===0}();P(r,{splice:function splice(t,r){if(arguments.length===0){return[]}else{return c.apply(this,arguments)}}},!ct);var vt=function(){var t={};r.splice.call(t,0,0,1);return t.length===1}();P(r,{splice:function splice(t,r){if(arguments.length===0){return[]}var e=arguments;this.length=w(z.ToInteger(this.length),0);if(arguments.length>0&&typeof r!==\"number\"){e=W(arguments);if(e.length<2){_(e,this.length-t)}else{e[1]=z.ToInteger(r)}}return c.apply(this,e)}},!vt);var ht=function(){var r=new t(1e5);r[8]=\"x\";r.splice(1,1);return r.indexOf(\"x\")===7}();var pt=function(){var t=256;var r=[];r[t]=\"a\";r.splice(t+1,0,\"b\");return r[t]===\"a\"}();P(r,{splice:function splice(t,r){var e=z.ToObject(this);var n=[];var i=z.ToUint32(e.length);var a=z.ToInteger(t);var f=a<0?w(i+a,0):b(a,i);var u=b(w(z.ToInteger(r),0),i-f);var l=0;var s;while(l<u){s=o(f+l);if(G(e,s)){n[l]=e[s]}l+=1}var c=W(arguments,2);var v=c.length;var h;if(v<u){l=f;var p=i-u;while(l<p){s=o(l+u);h=o(l+v);if(G(e,s)){e[h]=e[s]}else{delete e[h]}l+=1}l=i;var y=i-u+v;while(l>y){delete e[l-1];l-=1}}else if(v>u){l=i-u;while(l>f){s=o(l+u-1);h=o(l+v-1);if(G(e,s)){e[h]=e[s]}else{delete e[h]}l-=1}}l=f;for(var d=0;d<c.length;++d){e[l]=c[d];l+=1}e.length=i-u+v;return n}},!ht||!pt);var yt=r.join;var dt;try{dt=Array.prototype.join.call(\"123\",\",\")!==\"1,2,3\"}catch(X){dt=true}if(dt){P(r,{join:function join(t){var r=typeof t===\"undefined\"?\",\":t;return yt.call(N(this)?Q(this,\"\"):this,r)}},dt)}var gt=[1,2].join(undefined)!==\"1,2\";if(gt){P(r,{join:function join(t){var r=typeof t===\"undefined\"?\",\":t;return yt.call(this,r)}},gt)}var wt=function push(t){var r=z.ToObject(this);var e=z.ToUint32(r.length);var n=0;while(n<arguments.length){r[e+n]=arguments[n];n+=1}r.length=e+n;return e+n};var bt=function(){var t={};var r=Array.prototype.push.call(t,undefined);return r!==1||t.length!==1||typeof t[0]!==\"undefined\"||!G(t,0)}();P(r,{push:function push(t){if(et(this)){return v.apply(this,arguments)}return wt.apply(this,arguments)}},bt);var Tt=function(){var t=[];var r=t.push(undefined);return r!==1||t.length!==1||typeof t[0]!==\"undefined\"||!G(t,0)}();P(r,{push:wt},Tt);P(r,{slice:function(t,r){var e=N(this)?Q(this,\"\"):this;return B(e,arguments)}},at);var mt=function(){try{[1,2].sort(null)}catch(t){try{[1,2].sort({})}catch(r){return false}}return true}();var Dt=function(){try{[1,2].sort(/a/);return false}catch(t){}return true}();var St=function(){try{[1,2].sort(undefined);return true}catch(t){}return false}();P(r,{sort:function sort(t){if(typeof t===\"undefined\"){return rt(this)}if(!D(t)){throw new TypeError(\"Array.prototype.sort callback must be a function\")}return rt(this,t)}},mt||!St||!Dt);var xt=!tt({toString:null},\"toString\");var Ot=tt(function(){},\"prototype\");var Et=!G(\"x\",\"0\");var jt=function(t){var r=t.constructor;return r&&r.prototype===t};var It={$applicationCache:true,$console:true,$external:true,$frame:true,$frameElement:true,$frames:true,$innerHeight:true,$innerWidth:true,$onmozfullscreenchange:true,$onmozfullscreenerror:true,$outerHeight:true,$outerWidth:true,$pageXOffset:true,$pageYOffset:true,$parent:true,$scrollLeft:true,$scrollTop:true,$scrollX:true,$scrollY:true,$self:true,$webkitIndexedDB:true,$webkitStorageInfo:true,$window:true,$width:true,$height:true,$top:true,$localStorage:true};var Mt=function(){if(typeof window===\"undefined\"){return false}for(var t in window){try{if(!It[\"$\"+t]&&G(window,t)&&window[t]!==null&&typeof window[t]===\"object\"){jt(window[t])}}catch(r){return true}}return false}();var Ut=function(t){if(typeof window===\"undefined\"||!Mt){return jt(t)}try{return jt(t)}catch(r){return false}};var $t=[\"toString\",\"toLocaleString\",\"valueOf\",\"hasOwnProperty\",\"isPrototypeOf\",\"propertyIsEnumerable\",\"constructor\"];var Ft=$t.length;var Nt=function isArguments(t){return H(t)===\"[object Arguments]\"};var Ct=function isArguments(t){return t!==null&&typeof t===\"object\"&&typeof t.length===\"number\"&&t.length>=0&&!et(t)&&D(t.callee)};var kt=Nt(arguments)?Nt:Ct;P(e,{keys:function keys(t){var r=D(t);var e=kt(t);var n=t!==null&&typeof t===\"object\";var i=n&&N(t);if(!n&&!r&&!e){throw new TypeError(\"Object.keys called on a non-object\")}var a=[];var f=Ot&&r;if(i&&Et||e){for(var u=0;u<t.length;++u){_(a,o(u))}}if(!e){for(var l in t){if(!(f&&l===\"prototype\")&&G(t,l)){_(a,o(l))}}}if(xt){var s=Ut(t);for(var c=0;c<Ft;c++){var v=$t[c];if(!(s&&v===\"constructor\")&&G(t,v)){_(a,v)}}}return a}});var At=e.keys&&function(){return e.keys(arguments).length===2}(1,2);var Rt=e.keys&&function(){var t=e.keys(arguments);return arguments.length!==1||t.length!==1||t[0]!==1}(1);var Pt=e.keys;P(e,{keys:function keys(t){if(kt(t)){return Pt(W(t))}else{return Pt(t)}}},!At||Rt);var Jt=new Date(-0xc782b5b342b24).getUTCMonth()!==0;var Yt=new Date(-0x55d318d56a724);var zt=new Date(14496624e5);var Zt=Yt.toUTCString()!==\"Mon, 01 Jan -45875 11:59:59 GMT\";var Gt;var Ht;var Wt=Yt.getTimezoneOffset();if(Wt<-720){Gt=Yt.toDateString()!==\"Tue Jan 02 -45875\";Ht=!/^Thu Dec 10 2015 \\d\\d:\\d\\d:\\d\\d GMT[-+]\\d\\d\\d\\d(?: |$)/.test(String(zt))}else{Gt=Yt.toDateString()!==\"Mon Jan 01 -45875\";Ht=!/^Wed Dec 09 2015 \\d\\d:\\d\\d:\\d\\d GMT[-+]\\d\\d\\d\\d(?: |$)/.test(String(zt))}var Bt=d.bind(Date.prototype.getFullYear);var Xt=d.bind(Date.prototype.getMonth);var Lt=d.bind(Date.prototype.getDate);var qt=d.bind(Date.prototype.getUTCFullYear);var Kt=d.bind(Date.prototype.getUTCMonth);var Qt=d.bind(Date.prototype.getUTCDate);var Vt=d.bind(Date.prototype.getUTCDay);var _t=d.bind(Date.prototype.getUTCHours);var tr=d.bind(Date.prototype.getUTCMinutes);var rr=d.bind(Date.prototype.getUTCSeconds);var er=d.bind(Date.prototype.getUTCMilliseconds);var nr=[\"Sun\",\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\"];var ir=[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"];var ar=function daysInMonth(t,r){return Lt(new Date(r,t,0))};P(Date.prototype,{getFullYear:function getFullYear(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);if(t<0&&Xt(this)>11){return t+1}return t},getMonth:function getMonth(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);var r=Xt(this);if(t<0&&r>11){return 0}return r},getDate:function getDate(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);var r=Xt(this);var e=Lt(this);if(t<0&&r>11){if(r===12){return e}var n=ar(0,t+1);return n-e+1}return e},getUTCFullYear:function getUTCFullYear(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);if(t<0&&Kt(this)>11){return t+1}return t},getUTCMonth:function getUTCMonth(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);var r=Kt(this);if(t<0&&r>11){return 0}return r},getUTCDate:function getUTCDate(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);var r=Kt(this);var e=Qt(this);if(t<0&&r>11){if(r===12){return e}var n=ar(0,t+1);return n-e+1}return e}},Jt);P(Date.prototype,{toUTCString:function toUTCString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Vt(this);var r=Qt(this);var e=Kt(this);var n=qt(this);var i=_t(this);var a=tr(this);var o=rr(this);return nr[t]+\", \"+(r<10?\"0\"+r:r)+\" \"+ir[e]+\" \"+n+\" \"+(i<10?\"0\"+i:i)+\":\"+(a<10?\"0\"+a:a)+\":\"+(o<10?\"0\"+o:o)+\" GMT\"}},Jt||Zt);P(Date.prototype,{toDateString:function toDateString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=this.getDay();var r=this.getDate();var e=this.getMonth();var n=this.getFullYear();return nr[t]+\" \"+ir[e]+\" \"+(r<10?\"0\"+r:r)+\" \"+n}},Jt||Gt);if(Jt||Ht){Date.prototype.toString=function toString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=this.getDay();var r=this.getDate();var e=this.getMonth();var n=this.getFullYear();var i=this.getHours();var a=this.getMinutes();var o=this.getSeconds();var f=this.getTimezoneOffset();var u=Math.floor(Math.abs(f)/60);var l=Math.floor(Math.abs(f)%60);return nr[t]+\" \"+ir[e]+\" \"+(r<10?\"0\"+r:r)+\" \"+n+\" \"+(i<10?\"0\"+i:i)+\":\"+(a<10?\"0\"+a:a)+\":\"+(o<10?\"0\"+o:o)+\" GMT\"+(f>0?\"-\":\"+\")+(u<10?\"0\"+u:u)+(l<10?\"0\"+l:l)};if(R){e.defineProperty(Date.prototype,\"toString\",{configurable:true,enumerable:false,writable:true})}}var or=-621987552e5;var fr=\"-000001\";var ur=Date.prototype.toISOString&&new Date(or).toISOString().indexOf(fr)===-1;var lr=Date.prototype.toISOString&&new Date(-1).toISOString()!==\"1969-12-31T23:59:59.999Z\";var sr=d.bind(Date.prototype.getTime);P(Date.prototype,{toISOString:function toISOString(){if(!isFinite(this)||!isFinite(sr(this))){throw new RangeError(\"Date.prototype.toISOString called on non-finite value.\")}var t=qt(this);var r=Kt(this);t+=Math.floor(r/12);r=(r%12+12)%12;var e=[r+1,Qt(this),_t(this),tr(this),rr(this)];t=(t<0?\"-\":t>9999?\"+\":\"\")+K(\"00000\"+Math.abs(t),0<=t&&t<=9999?-4:-6);for(var n=0;n<e.length;++n){e[n]=K(\"00\"+e[n],-2)}return t+\"-\"+W(e,0,2).join(\"-\")+\"T\"+W(e,2).join(\":\")+\".\"+K(\"000\"+er(this),-3)+\"Z\"}},ur||lr);var cr=function(){try{return Date.prototype.toJSON&&new Date(NaN).toJSON()===null&&new Date(or).toJSON().indexOf(fr)!==-1&&Date.prototype.toJSON.call({toISOString:function(){return true}})}catch(t){return false}}();if(!cr){Date.prototype.toJSON=function toJSON(t){var r=e(this);var n=z.ToPrimitive(r);if(typeof n===\"number\"&&!isFinite(n)){return null}var i=r.toISOString;if(!D(i)){throw new TypeError(\"toISOString property is not callable\")}return i.call(r)}}var vr=Date.parse(\"+033658-09-27T01:46:40.000Z\")===1e15;var hr=!isNaN(Date.parse(\"2012-04-04T24:00:00.500Z\"))||!isNaN(Date.parse(\"2012-11-31T23:59:59.000Z\"))||!isNaN(Date.parse(\"2012-12-31T23:59:60.000Z\"));var pr=isNaN(Date.parse(\"2000-01-01T00:00:00.000Z\"));if(pr||hr||!vr){var yr=Math.pow(2,31)-1;var dr=Y(new Date(1970,0,1,0,0,0,yr+1).getTime());Date=function(t){var r=function Date(e,n,i,a,f,u,l){var s=arguments.length;var c;if(this instanceof t){var v=u;var h=l;if(dr&&s>=7&&l>yr){var p=Math.floor(l/yr)*yr;var y=Math.floor(p/1e3);v+=y;h-=y*1e3}c=s===1&&o(e)===e?new t(r.parse(e)):s>=7?new t(e,n,i,a,f,v,h):s>=6?new t(e,n,i,a,f,v):s>=5?new t(e,n,i,a,f):s>=4?new t(e,n,i,a):s>=3?new t(e,n,i):s>=2?new t(e,n):s>=1?new t(e instanceof t?+e:e):new t}else{c=t.apply(this,arguments)}if(!J(c)){P(c,{constructor:r},true)}return c};var e=new RegExp(\"^\"+\"(\\\\d{4}|[+-]\\\\d{6})\"+\"(?:-(\\\\d{2})\"+\"(?:-(\\\\d{2})\"+\"(?:\"+\"T(\\\\d{2})\"+\":(\\\\d{2})\"+\"(?:\"+\":(\\\\d{2})\"+\"(?:(\\\\.\\\\d{1,}))?\"+\")?\"+\"(\"+\"Z|\"+\"(?:\"+\"([-+])\"+\"(\\\\d{2})\"+\":(\\\\d{2})\"+\")\"+\")?)?)?)?\"+\"$\");var n=[0,31,59,90,120,151,181,212,243,273,304,334,365];var i=function dayFromMonth(t,r){var e=r>1?1:0;return n[r]+Math.floor((t-1969+e)/4)-Math.floor((t-1901+e)/100)+Math.floor((t-1601+e)/400)+365*(t-1970)};var a=function toUTC(r){var e=0;var n=r;if(dr&&n>yr){var i=Math.floor(n/yr)*yr;var a=Math.floor(i/1e3);e+=a;n-=a*1e3}return u(new t(1970,0,1,0,0,e,n))};for(var f in t){if(G(t,f)){r[f]=t[f]}}P(r,{now:t.now,UTC:t.UTC},true);r.prototype=t.prototype;P(r.prototype,{constructor:r},true);var l=function parse(r){var n=e.exec(r);if(n){var o=u(n[1]),f=u(n[2]||1)-1,l=u(n[3]||1)-1,s=u(n[4]||0),c=u(n[5]||0),v=u(n[6]||0),h=Math.floor(u(n[7]||0)*1e3),p=Boolean(n[4]&&!n[8]),y=n[9]===\"-\"?1:-1,d=u(n[10]||0),g=u(n[11]||0),w;var b=c>0||v>0||h>0;if(s<(b?24:25)&&c<60&&v<60&&h<1e3&&f>-1&&f<12&&d<24&&g<60&&l>-1&&l<i(o,f+1)-i(o,f)){w=((i(o,f)+l)*24+s+d*y)*60;w=((w+c+g*y)*60+v)*1e3+h;if(p){w=a(w)}if(-864e13<=w&&w<=864e13){return w}}return NaN}return t.parse.apply(this,arguments)};P(r,{parse:l});return r}(Date)}if(!Date.now){Date.now=function now(){return(new Date).getTime()}}var gr=l.toFixed&&(8e-5.toFixed(3)!==\"0.000\"||.9.toFixed(0)!==\"1\"||1.255.toFixed(2)!==\"1.25\"||(1000000000000000128).toFixed(0)!==\"1000000000000000128\");var wr={base:1e7,size:6,data:[0,0,0,0,0,0],multiply:function multiply(t,r){var e=-1;var n=r;while(++e<wr.size){n+=t*wr.data[e];wr.data[e]=n%wr.base;n=Math.floor(n/wr.base)}},divide:function divide(t){var r=wr.size;var e=0;while(--r>=0){e+=wr.data[r];wr.data[r]=Math.floor(e/t);e=e%t*wr.base}},numToString:function numToString(){var t=wr.size;var r=\"\";while(--t>=0){if(r!==\"\"||t===0||wr.data[t]!==0){var e=o(wr.data[t]);if(r===\"\"){r=e}else{r+=K(\"0000000\",0,7-e.length)+e}}}return r},pow:function pow(t,r,e){return r===0?e:r%2===1?pow(t,r-1,e*t):pow(t*t,r/2,e)},log:function log(t){var r=0;var e=t;while(e>=4096){r+=12;e/=4096}while(e>=2){r+=1;e/=2}return r}};var br=function toFixed(t){var r,e,n,i,a,f,l,s;r=u(t);r=Y(r)?0:Math.floor(r);if(r<0||r>20){throw new RangeError(\"Number.toFixed called with invalid number of decimals\")}e=u(this);if(Y(e)){return\"NaN\"}if(e<=-1e21||e>=1e21){return o(e)}n=\"\";if(e<0){n=\"-\";e=-e}i=\"0\";if(e>1e-21){a=wr.log(e*wr.pow(2,69,1))-69;f=a<0?e*wr.pow(2,-a,1):e/wr.pow(2,a,1);f*=4503599627370496;a=52-a;if(a>0){wr.multiply(0,f);l=r;while(l>=7){wr.multiply(1e7,0);l-=7}wr.multiply(wr.pow(10,l,1),0);l=a-1;while(l>=23){wr.divide(1<<23);l-=23}wr.divide(1<<l);wr.multiply(1,1);wr.divide(2);i=wr.numToString()}else{wr.multiply(0,f);wr.multiply(1<<-a,0);i=wr.numToString()+K(\"0.00000000000000000000\",2,2+r)}}if(r>0){s=i.length;if(s<=r){i=n+K(\"0.0000000000000000000\",0,r-s+2)+i}else{i=n+K(i,0,s-r)+\".\"+K(i,s-r)}}else{i=n+i}return i};P(l,{toFixed:br},gr);var Tr=function(){try{return 1..toPrecision(undefined)===\"1\"}catch(t){return true}}();var mr=l.toPrecision;P(l,{toPrecision:function toPrecision(t){return typeof t===\"undefined\"?mr.call(this):mr.call(this,t)}},Tr);if(\"ab\".split(/(?:ab)*/).length!==2||\".\".split(/(.?)(.?)/).length!==4||\"tesst\".split(/(s)*/)[1]===\"t\"||\"test\".split(/(?:)/,-1).length!==4||\"\".split(/.?/).length||\".\".split(/()()/).length>1){(function(){var t=typeof/()??/.exec(\"\")[1]===\"undefined\";var r=Math.pow(2,32)-1;f.split=function(e,n){var i=String(this);if(typeof e===\"undefined\"&&n===0){return[]}if(!M(e)){return Q(this,e,n)}var a=[];var o=(e.ignoreCase?\"i\":\"\")+(e.multiline?\"m\":\"\")+(e.unicode?\"u\":\"\")+(e.sticky?\"y\":\"\"),f=0,u,l,s,c;var h=new RegExp(e.source,o+\"g\");if(!t){u=new RegExp(\"^\"+h.source+\"$(?!\\\\s)\",o)}var p=typeof n===\"undefined\"?r:z.ToUint32(n);l=h.exec(i);while(l){s=l.index+l[0].length;if(s>f){_(a,K(i,f,l.index));if(!t&&l.length>1){l[0].replace(u,function(){for(var t=1;t<arguments.length-2;t++){if(typeof arguments[t]===\"undefined\"){l[t]=void 0}}})}if(l.length>1&&l.index<i.length){v.apply(a,W(l,1))}c=l[0].length;f=s;if(a.length>=p){break}}if(h.lastIndex===l.index){h.lastIndex++}l=h.exec(i)}if(f===i.length){if(c||!h.test(\"\")){_(a,\"\")}}else{_(a,K(i,f))}return a.length>p?W(a,0,p):a}})()}else if(\"0\".split(void 0,0).length){f.split=function split(t,r){if(typeof t===\"undefined\"&&r===0){return[]}return Q(this,t,r)}}var Dr=f.replace;var Sr=function(){var t=[];\"x\".replace(/x(.)?/g,function(r,e){_(t,e)});return t.length===1&&typeof t[0]===\"undefined\"}();if(!Sr){f.replace=function replace(t,r){var e=D(r);var n=M(t)&&/\\)[*?]/.test(t.source);if(!e||!n){return Dr.call(this,t,r)}else{var i=function(e){var n=arguments.length;var i=t.lastIndex;t.lastIndex=0;var a=t.exec(e)||[];t.lastIndex=i;_(a,arguments[n-2],arguments[n-1]);return r.apply(this,a)};return Dr.call(this,t,i)}}}var xr=f.substr;var Or=\"\".substr&&\"0b\".substr(-1)!==\"b\";P(f,{substr:function substr(t,r){var e=t;if(t<0){e=w(this.length+t,0)}return xr.call(this,e,r)}},Or);var Er=\"\\t\\n\\x0B\\f\\r \\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\"+\"\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\"+\"\\u2029\\ufeff\";var jr=\"\\u200b\";var Ir=\"[\"+Er+\"]\";var Mr=new RegExp(\"^\"+Ir+Ir+\"*\");var Ur=new RegExp(Ir+Ir+\"*$\");var $r=f.trim&&(Er.trim()||!jr.trim());P(f,{trim:function trim(){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}return o(this).replace(Mr,\"\").replace(Ur,\"\")}},$r);var Fr=d.bind(String.prototype.trim);var Nr=f.lastIndexOf&&\"abc\\u3042\\u3044\".lastIndexOf(\"\\u3042\\u3044\",2)!==-1;P(f,{lastIndexOf:function lastIndexOf(t){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}var r=o(this);var e=o(t);var n=arguments.length>1?u(arguments[1]):NaN;var i=Y(n)?Infinity:z.ToInteger(n);var a=b(w(i,0),r.length);var f=e.length;var l=a+f;while(l>0){l=w(0,l-f);var s=V(K(r,l,a+f),e);if(s!==-1){return l+s}}return-1}},Nr);var Cr=f.lastIndexOf;P(f,{lastIndexOf:function lastIndexOf(t){return Cr.apply(this,arguments)}},f.lastIndexOf.length!==1);if(parseInt(Er+\"08\")!==8||parseInt(Er+\"0x16\")!==22){parseInt=function(t){var r=/^[-+]?0[xX]/;return function parseInt(e,n){if(typeof e===\"symbol\"){\"\"+e}var i=Fr(String(e));var a=u(n)||(r.test(i)?16:10);return t(i,a)}}(parseInt)}if(1/parseFloat(\"-0\")!==-Infinity){parseFloat=function(t){return function parseFloat(r){var e=Fr(String(r));var n=t(e);return n===0&&K(e,0,1)===\"-\"?-0:n}}(parseFloat)}if(String(new RangeError(\"test\"))!==\"RangeError: test\"){var kr=function toString(){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}var t=this.name;if(typeof t===\"undefined\"){t=\"Error\"}else if(typeof t!==\"string\"){t=o(t)}var r=this.message;if(typeof r===\"undefined\"){r=\"\"}else if(typeof r!==\"string\"){r=o(r)}if(!t){return r}if(!r){return t}return t+\": \"+r};Error.prototype.toString=kr}if(R){var Ar=function(t,r){if(tt(t,r)){var e=Object.getOwnPropertyDescriptor(t,r);if(e.configurable){e.enumerable=false;Object.defineProperty(t,r,e)}}};Ar(Error.prototype,\"message\");if(Error.prototype.message!==\"\"){Error.prototype.message=\"\"}Ar(Error.prototype,\"name\")}if(String(/a/gim)!==\"/a/gim\"){var Rr=function toString(){var t=\"/\"+this.source+\"/\";if(this.global){t+=\"g\"}if(this.ignoreCase){t+=\"i\"}if(this.multiline){t+=\"m\"}return t};RegExp.prototype.toString=Rr}});\n//# sourceMappingURL=es5-shim.map\n/*!\n * https://github.com/paulmillr/es6-shim\n * @license es6-shim Copyright 2013-2016 by Paul Miller (http://paulmillr.com)\n *   and contributors,  MIT License\n * es6-shim: v0.35.4\n * see https://github.com/paulmillr/es6-shim/blob/0.35.4/LICENSE\n * Details and documentation:\n * https://github.com/paulmillr/es6-shim/\n */\n(function(e,t){if(typeof define===\"function\"&&define.amd){define(t)}else if(typeof exports===\"object\"){module.exports=t()}else{e.returnExports=t()}})(this,function(){\"use strict\";var e=Function.call.bind(Function.apply);var t=Function.call.bind(Function.call);var r=Array.isArray;var n=Object.keys;var o=function notThunker(t){return function notThunk(){return!e(t,this,arguments)}};var i=function(e){try{e();return false}catch(t){return true}};var a=function valueOrFalseIfThrows(e){try{return e()}catch(t){return false}};var u=o(i);var f=function(){return!i(function(){return Object.defineProperty({},\"x\",{get:function(){}})})};var s=!!Object.defineProperty&&f();var c=function foo(){}.name===\"foo\";var l=Function.call.bind(Array.prototype.forEach);var p=Function.call.bind(Array.prototype.reduce);var v=Function.call.bind(Array.prototype.filter);var y=Function.call.bind(Array.prototype.some);var h=function(e,t,r,n){if(!n&&t in e){return}if(s){Object.defineProperty(e,t,{configurable:true,enumerable:false,writable:true,value:r})}else{e[t]=r}};var b=function(e,t,r){l(n(t),function(n){var o=t[n];h(e,n,o,!!r)})};var g=Function.call.bind(Object.prototype.toString);var d=typeof/abc/===\"function\"?function IsCallableSlow(e){return typeof e===\"function\"&&g(e)===\"[object Function]\"}:function IsCallableFast(e){return typeof e===\"function\"};var m={getter:function(e,t,r){if(!s){throw new TypeError(\"getters require true ES5 support\")}Object.defineProperty(e,t,{configurable:true,enumerable:false,get:r})},proxy:function(e,t,r){if(!s){throw new TypeError(\"getters require true ES5 support\")}var n=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,{configurable:n.configurable,enumerable:n.enumerable,get:function getKey(){return e[t]},set:function setKey(r){e[t]=r}})},redefine:function(e,t,r){if(s){var n=Object.getOwnPropertyDescriptor(e,t);n.value=r;Object.defineProperty(e,t,n)}else{e[t]=r}},defineByDescriptor:function(e,t,r){if(s){Object.defineProperty(e,t,r)}else if(\"value\"in r){e[t]=r.value}},preserveToString:function(e,t){if(t&&d(t.toString)){h(e,\"toString\",t.toString.bind(t),true)}}};var O=Object.create||function(e,t){var r=function Prototype(){};r.prototype=e;var o=new r;if(typeof t!==\"undefined\"){n(t).forEach(function(e){m.defineByDescriptor(o,e,t[e])})}return o};var w=function(e,t){if(!Object.setPrototypeOf){return false}return a(function(){var r=function Subclass(t){var r=new e(t);Object.setPrototypeOf(r,Subclass.prototype);return r};Object.setPrototypeOf(r,e);r.prototype=O(e.prototype,{constructor:{value:r}});return t(r)})};var j=function(){if(typeof self!==\"undefined\"){return self}if(typeof window!==\"undefined\"){return window}if(typeof global!==\"undefined\"){return global}throw new Error(\"unable to locate global object\")};var S=j();var T=S.isFinite;var I=Function.call.bind(String.prototype.indexOf);var E=Function.apply.bind(Array.prototype.indexOf);var P=Function.call.bind(Array.prototype.concat);var C=Function.call.bind(String.prototype.slice);var M=Function.call.bind(Array.prototype.push);var x=Function.apply.bind(Array.prototype.push);var N=Function.call.bind(Array.prototype.shift);var A=Math.max;var R=Math.min;var _=Math.floor;var k=Math.abs;var L=Math.exp;var F=Math.log;var D=Math.sqrt;var z=Function.call.bind(Object.prototype.hasOwnProperty);var q;var W=function(){};var G=S.Map;var H=G&&G.prototype[\"delete\"];var V=G&&G.prototype.get;var B=G&&G.prototype.has;var U=G&&G.prototype.set;var $=S.Symbol||{};var J=$.species||\"@@species\";var X=Number.isNaN||function isNaN(e){return e!==e};var K=Number.isFinite||function isFinite(e){return typeof e===\"number\"&&T(e)};var Z=d(Math.sign)?Math.sign:function sign(e){var t=Number(e);if(t===0){return t}if(X(t)){return t}return t<0?-1:1};var Y=function log1p(e){var t=Number(e);if(t<-1||X(t)){return NaN}if(t===0||t===Infinity){return t}if(t===-1){return-Infinity}return 1+t-1===0?t:t*(F(1+t)/(1+t-1))};var Q=function isArguments(e){return g(e)===\"[object Arguments]\"};var ee=function isArguments(e){return e!==null&&typeof e===\"object\"&&typeof e.length===\"number\"&&e.length>=0&&g(e)!==\"[object Array]\"&&g(e.callee)===\"[object Function]\"};var te=Q(arguments)?Q:ee;var re={primitive:function(e){return e===null||typeof e!==\"function\"&&typeof e!==\"object\"},string:function(e){return g(e)===\"[object String]\"},regex:function(e){return g(e)===\"[object RegExp]\"},symbol:function(e){return typeof S.Symbol===\"function\"&&typeof e===\"symbol\"}};var ne=function overrideNative(e,t,r){var n=e[t];h(e,t,r,true);m.preserveToString(e[t],n)};var oe=typeof $===\"function\"&&typeof $[\"for\"]===\"function\"&&re.symbol($());var ie=re.symbol($.iterator)?$.iterator:\"_es6-shim iterator_\";if(S.Set&&typeof(new S.Set)[\"@@iterator\"]===\"function\"){ie=\"@@iterator\"}if(!S.Reflect){h(S,\"Reflect\",{},true)}var ae=S.Reflect;var ue=String;var fe=typeof document===\"undefined\"||!document?null:document.all;var se=fe==null?function isNullOrUndefined(e){return e==null}:function isNullOrUndefinedAndNotDocumentAll(e){return e==null&&e!==fe};var ce={Call:function Call(t,r){var n=arguments.length>2?arguments[2]:[];if(!ce.IsCallable(t)){throw new TypeError(t+\" is not a function\")}return e(t,r,n)},RequireObjectCoercible:function(e,t){if(se(e)){throw new TypeError(t||\"Cannot call method on \"+e)}return e},TypeIsObject:function(e){if(e===void 0||e===null||e===true||e===false){return false}return typeof e===\"function\"||typeof e===\"object\"||e===fe},ToObject:function(e,t){return Object(ce.RequireObjectCoercible(e,t))},IsCallable:d,IsConstructor:function(e){return ce.IsCallable(e)},ToInt32:function(e){return ce.ToNumber(e)>>0},ToUint32:function(e){return ce.ToNumber(e)>>>0},ToNumber:function(e){if(g(e)===\"[object Symbol]\"){throw new TypeError(\"Cannot convert a Symbol value to a number\")}return+e},ToInteger:function(e){var t=ce.ToNumber(e);if(X(t)){return 0}if(t===0||!K(t)){return t}return(t>0?1:-1)*_(k(t))},ToLength:function(e){var t=ce.ToInteger(e);if(t<=0){return 0}if(t>Number.MAX_SAFE_INTEGER){return Number.MAX_SAFE_INTEGER}return t},SameValue:function(e,t){if(e===t){if(e===0){return 1/e===1/t}return true}return X(e)&&X(t)},SameValueZero:function(e,t){return e===t||X(e)&&X(t)},IsIterable:function(e){return ce.TypeIsObject(e)&&(typeof e[ie]!==\"undefined\"||te(e))},GetIterator:function(e){if(te(e)){return new q(e,\"value\")}var t=ce.GetMethod(e,ie);if(!ce.IsCallable(t)){throw new TypeError(\"value is not an iterable\")}var r=ce.Call(t,e);if(!ce.TypeIsObject(r)){throw new TypeError(\"bad iterator\")}return r},GetMethod:function(e,t){var r=ce.ToObject(e)[t];if(se(r)){return void 0}if(!ce.IsCallable(r)){throw new TypeError(\"Method not callable: \"+t)}return r},IteratorComplete:function(e){return!!e.done},IteratorClose:function(e,t){var r=ce.GetMethod(e,\"return\");if(r===void 0){return}var n,o;try{n=ce.Call(r,e)}catch(i){o=i}if(t){return}if(o){throw o}if(!ce.TypeIsObject(n)){throw new TypeError(\"Iterator's return method returned a non-object.\")}},IteratorNext:function(e){var t=arguments.length>1?e.next(arguments[1]):e.next();if(!ce.TypeIsObject(t)){throw new TypeError(\"bad iterator\")}return t},IteratorStep:function(e){var t=ce.IteratorNext(e);var r=ce.IteratorComplete(t);return r?false:t},Construct:function(e,t,r,n){var o=typeof r===\"undefined\"?e:r;if(!n&&ae.construct){return ae.construct(e,t,o)}var i=o.prototype;if(!ce.TypeIsObject(i)){i=Object.prototype}var a=O(i);var u=ce.Call(e,a,t);return ce.TypeIsObject(u)?u:a},SpeciesConstructor:function(e,t){var r=e.constructor;if(r===void 0){return t}if(!ce.TypeIsObject(r)){throw new TypeError(\"Bad constructor\")}var n=r[J];if(se(n)){return t}if(!ce.IsConstructor(n)){throw new TypeError(\"Bad @@species\")}return n},CreateHTML:function(e,t,r,n){var o=ce.ToString(e);var i=\"<\"+t;if(r!==\"\"){var a=ce.ToString(n);var u=a.replace(/\"/g,\"&quot;\");i+=\" \"+r+'=\"'+u+'\"'}var f=i+\">\";var s=f+o;return s+\"</\"+t+\">\"},IsRegExp:function IsRegExp(e){if(!ce.TypeIsObject(e)){return false}var t=e[$.match];if(typeof t!==\"undefined\"){return!!t}return re.regex(e)},ToString:function ToString(e){return ue(e)}};if(s&&oe){var le=function defineWellKnownSymbol(e){if(re.symbol($[e])){return $[e]}var t=$[\"for\"](\"Symbol.\"+e);Object.defineProperty($,e,{configurable:false,enumerable:false,writable:false,value:t});return t};if(!re.symbol($.search)){var pe=le(\"search\");var ve=String.prototype.search;h(RegExp.prototype,pe,function search(e){return ce.Call(ve,e,[this])});var ye=function search(e){var t=ce.RequireObjectCoercible(this);if(!se(e)){var r=ce.GetMethod(e,pe);if(typeof r!==\"undefined\"){return ce.Call(r,e,[t])}}return ce.Call(ve,t,[ce.ToString(e)])};ne(String.prototype,\"search\",ye)}if(!re.symbol($.replace)){var he=le(\"replace\");var be=String.prototype.replace;h(RegExp.prototype,he,function replace(e,t){return ce.Call(be,e,[this,t])});var ge=function replace(e,t){var r=ce.RequireObjectCoercible(this);if(!se(e)){var n=ce.GetMethod(e,he);if(typeof n!==\"undefined\"){return ce.Call(n,e,[r,t])}}return ce.Call(be,r,[ce.ToString(e),t])};ne(String.prototype,\"replace\",ge)}if(!re.symbol($.split)){var de=le(\"split\");var me=String.prototype.split;h(RegExp.prototype,de,function split(e,t){return ce.Call(me,e,[this,t])});var Oe=function split(e,t){var r=ce.RequireObjectCoercible(this);if(!se(e)){var n=ce.GetMethod(e,de);if(typeof n!==\"undefined\"){return ce.Call(n,e,[r,t])}}return ce.Call(me,r,[ce.ToString(e),t])};ne(String.prototype,\"split\",Oe)}var we=re.symbol($.match);var je=we&&function(){var e={};e[$.match]=function(){return 42};return\"a\".match(e)!==42}();if(!we||je){var Se=le(\"match\");var Te=String.prototype.match;h(RegExp.prototype,Se,function match(e){return ce.Call(Te,e,[this])});var Ie=function match(e){var t=ce.RequireObjectCoercible(this);if(!se(e)){var r=ce.GetMethod(e,Se);if(typeof r!==\"undefined\"){return ce.Call(r,e,[t])}}return ce.Call(Te,t,[ce.ToString(e)])};ne(String.prototype,\"match\",Ie)}}var Ee=function wrapConstructor(e,t,r){m.preserveToString(t,e);if(Object.setPrototypeOf){Object.setPrototypeOf(e,t)}if(s){l(Object.getOwnPropertyNames(e),function(n){if(n in W||r[n]){return}m.proxy(e,n,t)})}else{l(Object.keys(e),function(n){if(n in W||r[n]){return}t[n]=e[n]})}t.prototype=e.prototype;m.redefine(e.prototype,\"constructor\",t)};var Pe=function(){return this};var Ce=function(e){if(s&&!z(e,J)){m.getter(e,J,Pe)}};var Me=function(e,t){var r=t||function iterator(){return this};h(e,ie,r);if(!e[ie]&&re.symbol(ie)){e[ie]=r}};var xe=function createDataProperty(e,t,r){if(s){Object.defineProperty(e,t,{configurable:true,enumerable:true,writable:true,value:r})}else{e[t]=r}};var Ne=function createDataPropertyOrThrow(e,t,r){xe(e,t,r);if(!ce.SameValue(e[t],r)){throw new TypeError(\"property is nonconfigurable\")}};var Ae=function(e,t,r,n){if(!ce.TypeIsObject(e)){throw new TypeError(\"Constructor requires `new`: \"+t.name)}var o=t.prototype;if(!ce.TypeIsObject(o)){o=r}var i=O(o);for(var a in n){if(z(n,a)){var u=n[a];h(i,a,u,true)}}return i};if(String.fromCodePoint&&String.fromCodePoint.length!==1){var Re=String.fromCodePoint;ne(String,\"fromCodePoint\",function fromCodePoint(e){return ce.Call(Re,this,arguments)})}var _e={fromCodePoint:function fromCodePoint(e){var t=[];var r;for(var n=0,o=arguments.length;n<o;n++){r=Number(arguments[n]);if(!ce.SameValue(r,ce.ToInteger(r))||r<0||r>1114111){throw new RangeError(\"Invalid code point \"+r)}if(r<65536){M(t,String.fromCharCode(r))}else{r-=65536;M(t,String.fromCharCode((r>>10)+55296));M(t,String.fromCharCode(r%1024+56320))}}return t.join(\"\")},raw:function raw(e){var t=ce.ToObject(e,\"bad callSite\");var r=ce.ToObject(t.raw,\"bad raw value\");var n=r.length;var o=ce.ToLength(n);if(o<=0){return\"\"}var i=[];var a=0;var u,f,s,c;while(a<o){u=ce.ToString(a);s=ce.ToString(r[u]);M(i,s);if(a+1>=o){break}f=a+1<arguments.length?arguments[a+1]:\"\";c=ce.ToString(f);M(i,c);a+=1}return i.join(\"\")}};if(String.raw&&String.raw({raw:{0:\"x\",1:\"y\",length:2}})!==\"xy\"){ne(String,\"raw\",_e.raw)}b(String,_e);var ke=function repeat(e,t){if(t<1){return\"\"}if(t%2){return repeat(e,t-1)+e}var r=repeat(e,t/2);return r+r};var Le=Infinity;var Fe={repeat:function repeat(e){var t=ce.ToString(ce.RequireObjectCoercible(this));var r=ce.ToInteger(e);if(r<0||r>=Le){throw new RangeError(\"repeat count must be less than infinity and not overflow maximum string size\")}return ke(t,r)},startsWith:function startsWith(e){var t=ce.ToString(ce.RequireObjectCoercible(this));if(ce.IsRegExp(e)){throw new TypeError('Cannot call method \"startsWith\" with a regex')}var r=ce.ToString(e);var n;if(arguments.length>1){n=arguments[1]}var o=A(ce.ToInteger(n),0);return C(t,o,o+r.length)===r},endsWith:function endsWith(e){var t=ce.ToString(ce.RequireObjectCoercible(this));if(ce.IsRegExp(e)){throw new TypeError('Cannot call method \"endsWith\" with a regex')}var r=ce.ToString(e);var n=t.length;var o;if(arguments.length>1){o=arguments[1]}var i=typeof o===\"undefined\"?n:ce.ToInteger(o);var a=R(A(i,0),n);return C(t,a-r.length,a)===r},includes:function includes(e){if(ce.IsRegExp(e)){throw new TypeError('\"includes\" does not accept a RegExp')}var t=ce.ToString(e);var r;if(arguments.length>1){r=arguments[1]}return I(this,t,r)!==-1},codePointAt:function codePointAt(e){var t=ce.ToString(ce.RequireObjectCoercible(this));var r=ce.ToInteger(e);var n=t.length;if(r>=0&&r<n){var o=t.charCodeAt(r);var i=r+1===n;if(o<55296||o>56319||i){return o}var a=t.charCodeAt(r+1);if(a<56320||a>57343){return o}return(o-55296)*1024+(a-56320)+65536}}};if(String.prototype.includes&&\"a\".includes(\"a\",Infinity)!==false){ne(String.prototype,\"includes\",Fe.includes)}if(String.prototype.startsWith&&String.prototype.endsWith){var De=i(function(){return\"/a/\".startsWith(/a/)});var ze=a(function(){return\"abc\".startsWith(\"a\",Infinity)===false});if(!De||!ze){ne(String.prototype,\"startsWith\",Fe.startsWith);ne(String.prototype,\"endsWith\",Fe.endsWith)}}if(oe){var qe=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".startsWith(e)});if(!qe){ne(String.prototype,\"startsWith\",Fe.startsWith)}var We=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".endsWith(e)});if(!We){ne(String.prototype,\"endsWith\",Fe.endsWith)}var Ge=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".includes(e)});if(!Ge){ne(String.prototype,\"includes\",Fe.includes)}}b(String.prototype,Fe);var He=[\"\\t\\n\\x0B\\f\\r \\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\",\"\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\",\"\\u2029\\ufeff\"].join(\"\");var Ve=new RegExp(\"(^[\"+He+\"]+)|([\"+He+\"]+$)\",\"g\");var Be=function trim(){return ce.ToString(ce.RequireObjectCoercible(this)).replace(Ve,\"\")};var Ue=[\"\\x85\",\"\\u200b\",\"\\ufffe\"].join(\"\");var $e=new RegExp(\"[\"+Ue+\"]\",\"g\");var Je=/^[-+]0x[0-9a-f]+$/i;var Xe=Ue.trim().length!==Ue.length;h(String.prototype,\"trim\",Be,Xe);var Ke=function(e){return{value:e,done:arguments.length===0}};var Ze=function(e){ce.RequireObjectCoercible(e);this._s=ce.ToString(e);this._i=0};Ze.prototype.next=function(){var e=this._s;var t=this._i;if(typeof e===\"undefined\"||t>=e.length){this._s=void 0;return Ke()}var r=e.charCodeAt(t);var n,o;if(r<55296||r>56319||t+1===e.length){o=1}else{n=e.charCodeAt(t+1);o=n<56320||n>57343?1:2}this._i=t+o;return Ke(e.substr(t,o))};Me(Ze.prototype);Me(String.prototype,function(){return new Ze(this)});var Ye={from:function from(e){var r=this;var n;if(arguments.length>1){n=arguments[1]}var o,i;if(typeof n===\"undefined\"){o=false}else{if(!ce.IsCallable(n)){throw new TypeError(\"Array.from: when provided, the second argument must be a function\")}if(arguments.length>2){i=arguments[2]}o=true}var a=typeof(te(e)||ce.GetMethod(e,ie))!==\"undefined\";var u,f,s;if(a){f=ce.IsConstructor(r)?Object(new r):[];var c=ce.GetIterator(e);var l,p;s=0;while(true){l=ce.IteratorStep(c);if(l===false){break}p=l.value;try{if(o){p=typeof i===\"undefined\"?n(p,s):t(n,i,p,s)}f[s]=p}catch(v){ce.IteratorClose(c,true);throw v}s+=1}u=s}else{var y=ce.ToObject(e);u=ce.ToLength(y.length);f=ce.IsConstructor(r)?Object(new r(u)):new Array(u);var h;for(s=0;s<u;++s){h=y[s];if(o){h=typeof i===\"undefined\"?n(h,s):t(n,i,h,s)}Ne(f,s,h)}}f.length=u;return f},of:function of(){var e=arguments.length;var t=this;var n=r(t)||!ce.IsCallable(t)?new Array(e):ce.Construct(t,[e]);for(var o=0;o<e;++o){Ne(n,o,arguments[o])}n.length=e;return n}};b(Array,Ye);Ce(Array);q=function(e,t){this.i=0;this.array=e;this.kind=t};b(q.prototype,{next:function(){var e=this.i;var t=this.array;if(!(this instanceof q)){throw new TypeError(\"Not an ArrayIterator\")}if(typeof t!==\"undefined\"){var r=ce.ToLength(t.length);for(;e<r;e++){var n=this.kind;var o;if(n===\"key\"){o=e}else if(n===\"value\"){o=t[e]}else if(n===\"entry\"){o=[e,t[e]]}this.i=e+1;return Ke(o)}}this.array=void 0;return Ke()}});Me(q.prototype);var Qe=Array.of===Ye.of||function(){var e=function Foo(e){this.length=e};e.prototype=[];var t=Array.of.apply(e,[1,2]);return t instanceof e&&t.length===2}();if(!Qe){ne(Array,\"of\",Ye.of)}var et={copyWithin:function copyWithin(e,t){var r=ce.ToObject(this);var n=ce.ToLength(r.length);var o=ce.ToInteger(e);var i=ce.ToInteger(t);var a=o<0?A(n+o,0):R(o,n);var u=i<0?A(n+i,0):R(i,n);var f;if(arguments.length>2){f=arguments[2]}var s=typeof f===\"undefined\"?n:ce.ToInteger(f);var c=s<0?A(n+s,0):R(s,n);var l=R(c-u,n-a);var p=1;if(u<a&&a<u+l){p=-1;u+=l-1;a+=l-1}while(l>0){if(u in r){r[a]=r[u]}else{delete r[a]}u+=p;a+=p;l-=1}return r},fill:function fill(e){var t;if(arguments.length>1){t=arguments[1]}var r;if(arguments.length>2){r=arguments[2]}var n=ce.ToObject(this);var o=ce.ToLength(n.length);t=ce.ToInteger(typeof t===\"undefined\"?0:t);r=ce.ToInteger(typeof r===\"undefined\"?o:r);var i=t<0?A(o+t,0):R(t,o);var a=r<0?o+r:r;for(var u=i;u<o&&u<a;++u){n[u]=e}return n},find:function find(e){var r=ce.ToObject(this);var n=ce.ToLength(r.length);if(!ce.IsCallable(e)){throw new TypeError(\"Array#find: predicate must be a function\")}var o=arguments.length>1?arguments[1]:null;for(var i=0,a;i<n;i++){a=r[i];if(o){if(t(e,o,a,i,r)){return a}}else if(e(a,i,r)){return a}}},findIndex:function findIndex(e){var r=ce.ToObject(this);var n=ce.ToLength(r.length);if(!ce.IsCallable(e)){throw new TypeError(\"Array#findIndex: predicate must be a function\")}var o=arguments.length>1?arguments[1]:null;for(var i=0;i<n;i++){if(o){if(t(e,o,r[i],i,r)){return i}}else if(e(r[i],i,r)){return i}}return-1},keys:function keys(){return new q(this,\"key\")},values:function values(){return new q(this,\"value\")},entries:function entries(){return new q(this,\"entry\")}};if(Array.prototype.keys&&!ce.IsCallable([1].keys().next)){delete Array.prototype.keys}if(Array.prototype.entries&&!ce.IsCallable([1].entries().next)){delete Array.prototype.entries}if(Array.prototype.keys&&Array.prototype.entries&&!Array.prototype.values&&Array.prototype[ie]){b(Array.prototype,{values:Array.prototype[ie]});if(re.symbol($.unscopables)){Array.prototype[$.unscopables].values=true}}if(c&&Array.prototype.values&&Array.prototype.values.name!==\"values\"){var tt=Array.prototype.values;ne(Array.prototype,\"values\",function values(){return ce.Call(tt,this,arguments)});h(Array.prototype,ie,Array.prototype.values,true)}b(Array.prototype,et);if(1/[true].indexOf(true,-0)<0){h(Array.prototype,\"indexOf\",function indexOf(e){var t=E(this,arguments);if(t===0&&1/t<0){return 0}return t},true)}Me(Array.prototype,function(){return this.values()});if(Object.getPrototypeOf){Me(Object.getPrototypeOf([].values()))}var rt=function(){return a(function(){return Array.from({length:-1}).length===0})}();var nt=function(){var e=Array.from([0].entries());return e.length===1&&r(e[0])&&e[0][0]===0&&e[0][1]===0}();if(!rt||!nt){ne(Array,\"from\",Ye.from)}var ot=function(){return a(function(){return Array.from([0],void 0)})}();if(!ot){var it=Array.from;ne(Array,\"from\",function from(e){if(arguments.length>1&&typeof arguments[1]!==\"undefined\"){return ce.Call(it,this,arguments)}else{return t(it,this,e)}})}var at=-(Math.pow(2,32)-1);var ut=function(e,r){var n={length:at};n[r?(n.length>>>0)-1:0]=true;return a(function(){t(e,n,function(){throw new RangeError(\"should not reach here\")},[]);return true})};if(!ut(Array.prototype.forEach)){var ft=Array.prototype.forEach;ne(Array.prototype,\"forEach\",function forEach(e){return ce.Call(ft,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.map)){var st=Array.prototype.map;ne(Array.prototype,\"map\",function map(e){return ce.Call(st,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.filter)){var ct=Array.prototype.filter;ne(Array.prototype,\"filter\",function filter(e){return ce.Call(ct,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.some)){var lt=Array.prototype.some;ne(Array.prototype,\"some\",function some(e){return ce.Call(lt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.every)){var pt=Array.prototype.every;ne(Array.prototype,\"every\",function every(e){return ce.Call(pt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.reduce)){var vt=Array.prototype.reduce;ne(Array.prototype,\"reduce\",function reduce(e){return ce.Call(vt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.reduceRight,true)){var yt=Array.prototype.reduceRight;ne(Array.prototype,\"reduceRight\",function reduceRight(e){return ce.Call(yt,this.length>=0?this:[],arguments)},true)}var ht=Number(\"0o10\")!==8;var bt=Number(\"0b10\")!==2;var gt=y(Ue,function(e){return Number(e+0+e)===0});if(ht||bt||gt){var dt=Number;var mt=/^0b[01]+$/i;var Ot=/^0o[0-7]+$/i;var wt=mt.test.bind(mt);var jt=Ot.test.bind(Ot);var St=function(e){var t;if(typeof e.valueOf===\"function\"){t=e.valueOf();if(re.primitive(t)){return t}}if(typeof e.toString===\"function\"){t=e.toString();if(re.primitive(t)){return t}}throw new TypeError(\"No default value\")};var Tt=$e.test.bind($e);var It=Je.test.bind(Je);var Et=function(){var e=function Number(t){var r;if(arguments.length>0){r=re.primitive(t)?t:St(t,\"number\")}else{r=0}if(typeof r===\"string\"){r=ce.Call(Be,r);if(wt(r)){r=parseInt(C(r,2),2)}else if(jt(r)){r=parseInt(C(r,2),8)}else if(Tt(r)||It(r)){r=NaN}}var n=this;var o=a(function(){dt.prototype.valueOf.call(n);return true});if(n instanceof e&&!o){return new dt(r)}return dt(r)};return e}();Ee(dt,Et,{});b(Et,{NaN:dt.NaN,MAX_VALUE:dt.MAX_VALUE,MIN_VALUE:dt.MIN_VALUE,NEGATIVE_INFINITY:dt.NEGATIVE_INFINITY,POSITIVE_INFINITY:dt.POSITIVE_INFINITY});Number=Et;m.redefine(S,\"Number\",Et)}var Pt=Math.pow(2,53)-1;b(Number,{MAX_SAFE_INTEGER:Pt,MIN_SAFE_INTEGER:-Pt,EPSILON:2.220446049250313e-16,parseInt:S.parseInt,parseFloat:S.parseFloat,isFinite:K,isInteger:function isInteger(e){return K(e)&&ce.ToInteger(e)===e},isSafeInteger:function isSafeInteger(e){return Number.isInteger(e)&&k(e)<=Number.MAX_SAFE_INTEGER},isNaN:X});h(Number,\"parseInt\",S.parseInt,Number.parseInt!==S.parseInt);if([,1].find(function(){return true})===1){ne(Array.prototype,\"find\",et.find)}if([,1].findIndex(function(){return true})!==0){ne(Array.prototype,\"findIndex\",et.findIndex)}var Ct=Function.bind.call(Function.bind,Object.prototype.propertyIsEnumerable);var Mt=function ensureEnumerable(e,t){if(s&&Ct(e,t)){Object.defineProperty(e,t,{enumerable:false})}};var xt=function sliceArgs(){var e=Number(this);var t=arguments.length;var r=t-e;var n=new Array(r<0?0:r);for(var o=e;o<t;++o){n[o-e]=arguments[o]}return n};var Nt=function assignTo(e){return function assignToSource(t,r){t[r]=e[r];return t}};var At=function(e,t){var r=n(Object(t));var o;if(ce.IsCallable(Object.getOwnPropertySymbols)){o=v(Object.getOwnPropertySymbols(Object(t)),Ct(t))}return p(P(r,o||[]),Nt(t),e)};var Rt={assign:function(e,t){var r=ce.ToObject(e,\"Cannot convert undefined or null to object\");return p(ce.Call(xt,1,arguments),At,r)},is:function is(e,t){return ce.SameValue(e,t)}};var _t=Object.assign&&Object.preventExtensions&&function(){var e=Object.preventExtensions({1:2});try{Object.assign(e,\"xy\")}catch(t){return e[1]===\"y\"}}();if(_t){ne(Object,\"assign\",Rt.assign)}b(Object,Rt);if(s){var kt={setPrototypeOf:function(e,r){var n;var o=function(e,t){if(!ce.TypeIsObject(e)){throw new TypeError(\"cannot set prototype on a non-object\")}if(!(t===null||ce.TypeIsObject(t))){throw new TypeError(\"can only set prototype to an object or null\"+t)}};var i=function(e,r){o(e,r);t(n,e,r);return e};try{n=e.getOwnPropertyDescriptor(e.prototype,r).set;t(n,{},null)}catch(a){if(e.prototype!=={}[r]){return}n=function(e){this[r]=e};i.polyfill=i(i({},null),e.prototype)instanceof e}return i}(Object,\"__proto__\")};b(Object,kt)}if(Object.setPrototypeOf&&Object.getPrototypeOf&&Object.getPrototypeOf(Object.setPrototypeOf({},null))!==null&&Object.getPrototypeOf(Object.create(null))===null){(function(){var e=Object.create(null);var t=Object.getPrototypeOf;var r=Object.setPrototypeOf;Object.getPrototypeOf=function(r){var n=t(r);return n===e?null:n};Object.setPrototypeOf=function(t,n){var o=n===null?e:n;return r(t,o)};Object.setPrototypeOf.polyfill=false})()}var Lt=!i(function(){return Object.keys(\"foo\")});if(!Lt){var Ft=Object.keys;ne(Object,\"keys\",function keys(e){return Ft(ce.ToObject(e))});n=Object.keys}var Dt=i(function(){return Object.keys(/a/g)});if(Dt){var zt=Object.keys;ne(Object,\"keys\",function keys(e){if(re.regex(e)){var t=[];for(var r in e){if(z(e,r)){M(t,r)}}return t}return zt(e)});n=Object.keys}if(Object.getOwnPropertyNames){var qt=!i(function(){return Object.getOwnPropertyNames(\"foo\")});if(!qt){var Wt=typeof window===\"object\"?Object.getOwnPropertyNames(window):[];var Gt=Object.getOwnPropertyNames;ne(Object,\"getOwnPropertyNames\",function getOwnPropertyNames(e){var t=ce.ToObject(e);if(g(t)===\"[object Window]\"){try{return Gt(t)}catch(r){return P([],Wt)}}return Gt(t)})}}if(Object.getOwnPropertyDescriptor){var Ht=!i(function(){return Object.getOwnPropertyDescriptor(\"foo\",\"bar\")});if(!Ht){var Vt=Object.getOwnPropertyDescriptor;ne(Object,\"getOwnPropertyDescriptor\",function getOwnPropertyDescriptor(e,t){return Vt(ce.ToObject(e),t)})}}if(Object.seal){var Bt=!i(function(){return Object.seal(\"foo\")});if(!Bt){var Ut=Object.seal;ne(Object,\"seal\",function seal(e){if(!ce.TypeIsObject(e)){return e}return Ut(e)})}}if(Object.isSealed){var $t=!i(function(){return Object.isSealed(\"foo\")});if(!$t){var Jt=Object.isSealed;ne(Object,\"isSealed\",function isSealed(e){if(!ce.TypeIsObject(e)){return true}return Jt(e)})}}if(Object.freeze){var Xt=!i(function(){return Object.freeze(\"foo\")});if(!Xt){var Kt=Object.freeze;ne(Object,\"freeze\",function freeze(e){if(!ce.TypeIsObject(e)){return e}return Kt(e)})}}if(Object.isFrozen){var Zt=!i(function(){return Object.isFrozen(\"foo\")});if(!Zt){var Yt=Object.isFrozen;ne(Object,\"isFrozen\",function isFrozen(e){if(!ce.TypeIsObject(e)){return true}return Yt(e)})}}if(Object.preventExtensions){var Qt=!i(function(){return Object.preventExtensions(\"foo\")});if(!Qt){var er=Object.preventExtensions;ne(Object,\"preventExtensions\",function preventExtensions(e){if(!ce.TypeIsObject(e)){return e}return er(e)})}}if(Object.isExtensible){var tr=!i(function(){return Object.isExtensible(\"foo\")});if(!tr){var rr=Object.isExtensible;ne(Object,\"isExtensible\",function isExtensible(e){if(!ce.TypeIsObject(e)){return false}return rr(e)})}}if(Object.getPrototypeOf){var nr=!i(function(){return Object.getPrototypeOf(\"foo\")});if(!nr){var or=Object.getPrototypeOf;ne(Object,\"getPrototypeOf\",function getPrototypeOf(e){return or(ce.ToObject(e))})}}var ir=s&&function(){var e=Object.getOwnPropertyDescriptor(RegExp.prototype,\"flags\");return e&&ce.IsCallable(e.get)}();if(s&&!ir){var ar=function flags(){if(!ce.TypeIsObject(this)){throw new TypeError(\"Method called on incompatible type: must be an object.\")}var e=\"\";if(this.global){e+=\"g\"}if(this.ignoreCase){e+=\"i\"}if(this.multiline){e+=\"m\"}if(this.unicode){e+=\"u\"}if(this.sticky){e+=\"y\"}return e};m.getter(RegExp.prototype,\"flags\",ar)}var ur=s&&a(function(){return String(new RegExp(/a/g,\"i\"))===\"/a/i\"});var fr=oe&&s&&function(){var e=/./;e[$.match]=false;return RegExp(e)===e}();var sr=a(function(){return RegExp.prototype.toString.call({source:\"abc\"})===\"/abc/\"});var cr=sr&&a(function(){return RegExp.prototype.toString.call({source:\"a\",flags:\"b\"})===\"/a/b\"});if(!sr||!cr){var lr=RegExp.prototype.toString;h(RegExp.prototype,\"toString\",function toString(){var e=ce.RequireObjectCoercible(this);if(re.regex(e)){return t(lr,e)}var r=ue(e.source);var n=ue(e.flags);return\"/\"+r+\"/\"+n},true);m.preserveToString(RegExp.prototype.toString,lr)}if(s&&(!ur||fr)){var pr=Object.getOwnPropertyDescriptor(RegExp.prototype,\"flags\").get;var vr=Object.getOwnPropertyDescriptor(RegExp.prototype,\"source\")||{};var yr=function(){return this.source};var hr=ce.IsCallable(vr.get)?vr.get:yr;var br=RegExp;var gr=function(){return function RegExp(e,t){var r=ce.IsRegExp(e);var n=this instanceof RegExp;if(!n&&r&&typeof t===\"undefined\"&&e.constructor===RegExp){return e}var o=e;var i=t;if(re.regex(e)){o=ce.Call(hr,e);i=typeof t===\"undefined\"?ce.Call(pr,e):t;return new RegExp(o,i)}else if(r){o=e.source;i=typeof t===\"undefined\"?e.flags:t}return new br(e,t)}}();Ee(br,gr,{$input:true});RegExp=gr;m.redefine(S,\"RegExp\",gr)}if(s){var dr={input:\"$_\",lastMatch:\"$&\",lastParen:\"$+\",leftContext:\"$`\",rightContext:\"$'\"};l(n(dr),function(e){if(e in RegExp&&!(dr[e]in RegExp)){m.getter(RegExp,dr[e],function get(){return RegExp[e]})}})}Ce(RegExp);var mr=1/Number.EPSILON;var Or=function roundTiesToEven(e){return e+mr-mr};var wr=Math.pow(2,-23);var jr=Math.pow(2,127)*(2-wr);var Sr=Math.pow(2,-126);var Tr=Math.E;var Ir=Math.LOG2E;var Er=Math.LOG10E;var Pr=Number.prototype.clz;delete Number.prototype.clz;var Cr={acosh:function acosh(e){var t=Number(e);if(X(t)||e<1){return NaN}if(t===1){return 0}if(t===Infinity){return t}var r=1/(t*t);if(t<2){return Y(t-1+D(1-r)*t)}var n=t/2;return Y(n+D(1-r)*n-1)+1/Ir},asinh:function asinh(e){var t=Number(e);if(t===0||!T(t)){return t}var r=k(t);var n=r*r;var o=Z(t);if(r<1){return o*Y(r+n/(D(n+1)+1))}return o*(Y(r/2+D(1+1/n)*r/2-1)+1/Ir)},atanh:function atanh(e){var t=Number(e);if(t===0){return t}if(t===-1){return-Infinity}if(t===1){return Infinity}if(X(t)||t<-1||t>1){return NaN}var r=k(t);return Z(t)*Y(2*r/(1-r))/2},cbrt:function cbrt(e){var t=Number(e);if(t===0){return t}var r=t<0;var n;if(r){t=-t}if(t===Infinity){n=Infinity}else{n=L(F(t)/3);n=(t/(n*n)+2*n)/3}return r?-n:n},clz32:function clz32(e){var t=Number(e);var r=ce.ToUint32(t);if(r===0){return 32}return Pr?ce.Call(Pr,r):31-_(F(r+.5)*Ir)},cosh:function cosh(e){var t=Number(e);if(t===0){return 1}if(X(t)){return NaN}if(!T(t)){return Infinity}var r=L(k(t)-1);return(r+1/(r*Tr*Tr))*(Tr/2)},expm1:function expm1(e){var t=Number(e);if(t===-Infinity){return-1}if(!T(t)||t===0){return t}if(k(t)>.5){return L(t)-1}var r=t;var n=0;var o=1;while(n+r!==n){n+=r;o+=1;r*=t/o}return n},hypot:function hypot(e,t){var r=0;var n=0;for(var o=0;o<arguments.length;++o){var i=k(Number(arguments[o]));if(n<i){r*=n/i*(n/i);r+=1;n=i}else{r+=i>0?i/n*(i/n):i}}return n===Infinity?Infinity:n*D(r)},log2:function log2(e){return F(e)*Ir},log10:function log10(e){return F(e)*Er},log1p:Y,sign:Z,sinh:function sinh(e){var t=Number(e);if(!T(t)||t===0){return t}var r=k(t);if(r<1){var n=Math.expm1(r);return Z(t)*n*(1+1/(n+1))/2}var o=L(r-1);return Z(t)*(o-1/(o*Tr*Tr))*(Tr/2)},tanh:function tanh(e){var t=Number(e);if(X(t)||t===0){return t}if(t>=20){return 1}if(t<=-20){return-1}return(Math.expm1(t)-Math.expm1(-t))/(L(t)+L(-t))},trunc:function trunc(e){var t=Number(e);return t<0?-_(-t):_(t)},imul:function imul(e,t){var r=ce.ToUint32(e);var n=ce.ToUint32(t);var o=r>>>16&65535;var i=r&65535;var a=n>>>16&65535;var u=n&65535;return i*u+(o*u+i*a<<16>>>0)|0},fround:function fround(e){var t=Number(e);if(t===0||t===Infinity||t===-Infinity||X(t)){return t}var r=Z(t);var n=k(t);if(n<Sr){return r*Or(n/Sr/wr)*Sr*wr}var o=(1+wr/Number.EPSILON)*n;var i=o-(o-n);if(i>jr||X(i)){return r*Infinity}return r*i}};var Mr=function withinULPDistance(e,t,r){return k(1-e/t)/Number.EPSILON<(r||8)};b(Math,Cr);h(Math,\"sinh\",Cr.sinh,Math.sinh(710)===Infinity);h(Math,\"cosh\",Cr.cosh,Math.cosh(710)===Infinity);h(Math,\"log1p\",Cr.log1p,Math.log1p(-1e-17)!==-1e-17);h(Math,\"asinh\",Cr.asinh,Math.asinh(-1e7)!==-Math.asinh(1e7));h(Math,\"asinh\",Cr.asinh,Math.asinh(1e300)===Infinity);h(Math,\"atanh\",Cr.atanh,Math.atanh(1e-300)===0);h(Math,\"tanh\",Cr.tanh,Math.tanh(-2e-17)!==-2e-17);\nh(Math,\"acosh\",Cr.acosh,Math.acosh(Number.MAX_VALUE)===Infinity);h(Math,\"acosh\",Cr.acosh,!Mr(Math.acosh(1+Number.EPSILON),Math.sqrt(2*Number.EPSILON)));h(Math,\"cbrt\",Cr.cbrt,!Mr(Math.cbrt(1e-300),1e-100));h(Math,\"sinh\",Cr.sinh,Math.sinh(-2e-17)!==-2e-17);var xr=Math.expm1(10);h(Math,\"expm1\",Cr.expm1,xr>22025.465794806718||xr<22025.465794806718);var Nr=Math.round;var Ar=Math.round(.5-Number.EPSILON/4)===0&&Math.round(-.5+Number.EPSILON/3.99)===1;var Rr=mr+1;var _r=2*mr-1;var kr=[Rr,_r].every(function(e){return Math.round(e)===e});h(Math,\"round\",function round(e){var t=_(e);var r=t===-1?-0:t+1;return e-t<.5?t:r},!Ar||!kr);m.preserveToString(Math.round,Nr);var Lr=Math.imul;if(Math.imul(4294967295,5)!==-5){Math.imul=Cr.imul;m.preserveToString(Math.imul,Lr)}if(Math.imul.length!==2){ne(Math,\"imul\",function imul(e,t){return ce.Call(Lr,Math,arguments)})}var Fr=function(){var e=S.setTimeout;if(typeof e!==\"function\"&&typeof e!==\"object\"){return}ce.IsPromise=function(e){if(!ce.TypeIsObject(e)){return false}if(typeof e._promise===\"undefined\"){return false}return true};var r=function(e){if(!ce.IsConstructor(e)){throw new TypeError(\"Bad promise constructor\")}var t=this;var r=function(e,r){if(t.resolve!==void 0||t.reject!==void 0){throw new TypeError(\"Bad Promise implementation!\")}t.resolve=e;t.reject=r};t.resolve=void 0;t.reject=void 0;t.promise=new e(r);if(!(ce.IsCallable(t.resolve)&&ce.IsCallable(t.reject))){throw new TypeError(\"Bad promise constructor\")}};var n;if(typeof window!==\"undefined\"&&ce.IsCallable(window.postMessage)){n=function(){var e=[];var t=\"zero-timeout-message\";var r=function(r){M(e,r);window.postMessage(t,\"*\")};var n=function(r){if(r.source===window&&r.data===t){r.stopPropagation();if(e.length===0){return}var n=N(e);n()}};window.addEventListener(\"message\",n,true);return r}}var o=function(){var e=S.Promise;var t=e&&e.resolve&&e.resolve();return t&&function(e){return t.then(e)}};var i=ce.IsCallable(S.setImmediate)?S.setImmediate:typeof process===\"object\"&&process.nextTick?process.nextTick:o()||(ce.IsCallable(n)?n():function(t){e(t,0)});var a=function(e){return e};var u=function(e){throw e};var f=0;var s=1;var c=2;var l=0;var p=1;var v=2;var y={};var h=function(e,t,r){i(function(){g(e,t,r)})};var g=function(e,t,r){var n,o;if(t===y){return e(r)}try{n=e(r);o=t.resolve}catch(i){n=i;o=t.reject}o(n)};var d=function(e,t){var r=e._promise;var n=r.reactionLength;if(n>0){h(r.fulfillReactionHandler0,r.reactionCapability0,t);r.fulfillReactionHandler0=void 0;r.rejectReactions0=void 0;r.reactionCapability0=void 0;if(n>1){for(var o=1,i=0;o<n;o++,i+=3){h(r[i+l],r[i+v],t);e[i+l]=void 0;e[i+p]=void 0;e[i+v]=void 0}}}r.result=t;r.state=s;r.reactionLength=0};var m=function(e,t){var r=e._promise;var n=r.reactionLength;if(n>0){h(r.rejectReactionHandler0,r.reactionCapability0,t);r.fulfillReactionHandler0=void 0;r.rejectReactions0=void 0;r.reactionCapability0=void 0;if(n>1){for(var o=1,i=0;o<n;o++,i+=3){h(r[i+p],r[i+v],t);e[i+l]=void 0;e[i+p]=void 0;e[i+v]=void 0}}}r.result=t;r.state=c;r.reactionLength=0};var O=function(e){var t=false;var r=function(r){var n;if(t){return}t=true;if(r===e){return m(e,new TypeError(\"Self resolution\"))}if(!ce.TypeIsObject(r)){return d(e,r)}try{n=r.then}catch(o){return m(e,o)}if(!ce.IsCallable(n)){return d(e,r)}i(function(){j(e,r,n)})};var n=function(r){if(t){return}t=true;return m(e,r)};return{resolve:r,reject:n}};var w=function(e,r,n,o){if(e===I){t(e,r,n,o,y)}else{t(e,r,n,o)}};var j=function(e,t,r){var n=O(e);var o=n.resolve;var i=n.reject;try{w(r,t,o,i)}catch(a){i(a)}};var T,I;var E=function(){var e=function Promise(t){if(!(this instanceof e)){throw new TypeError('Constructor Promise requires \"new\"')}if(this&&this._promise){throw new TypeError(\"Bad construction\")}if(!ce.IsCallable(t)){throw new TypeError(\"not a valid resolver\")}var r=Ae(this,e,T,{_promise:{result:void 0,state:f,reactionLength:0,fulfillReactionHandler0:void 0,rejectReactionHandler0:void 0,reactionCapability0:void 0}});var n=O(r);var o=n.reject;try{t(n.resolve,o)}catch(i){o(i)}return r};return e}();T=E.prototype;var P=function(e,t,r,n){var o=false;return function(i){if(o){return}o=true;t[e]=i;if(--n.count===0){var a=r.resolve;a(t)}}};var C=function(e,t,r){var n=e.iterator;var o=[];var i={count:1};var a,u;var f=0;while(true){try{a=ce.IteratorStep(n);if(a===false){e.done=true;break}u=a.value}catch(s){e.done=true;throw s}o[f]=void 0;var c=t.resolve(u);var l=P(f,o,r,i);i.count+=1;w(c.then,c,l,r.reject);f+=1}if(--i.count===0){var p=r.resolve;p(o)}return r.promise};var x=function(e,t,r){var n=e.iterator;var o,i,a;while(true){try{o=ce.IteratorStep(n);if(o===false){e.done=true;break}i=o.value}catch(u){e.done=true;throw u}a=t.resolve(i);w(a.then,a,r.resolve,r.reject)}return r.promise};b(E,{all:function all(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Promise is not object\")}var n=new r(t);var o,i;try{o=ce.GetIterator(e);i={iterator:o,done:false};return C(i,t,n)}catch(a){var u=a;if(i&&!i.done){try{ce.IteratorClose(o,true)}catch(f){u=f}}var s=n.reject;s(u);return n.promise}},race:function race(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Promise is not object\")}var n=new r(t);var o,i;try{o=ce.GetIterator(e);i={iterator:o,done:false};return x(i,t,n)}catch(a){var u=a;if(i&&!i.done){try{ce.IteratorClose(o,true)}catch(f){u=f}}var s=n.reject;s(u);return n.promise}},reject:function reject(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Bad promise constructor\")}var n=new r(t);var o=n.reject;o(e);return n.promise},resolve:function resolve(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Bad promise constructor\")}if(ce.IsPromise(e)){var n=e.constructor;if(n===t){return e}}var o=new r(t);var i=o.resolve;i(e);return o.promise}});b(T,{\"catch\":function(e){return this.then(null,e)},then:function then(e,t){var n=this;if(!ce.IsPromise(n)){throw new TypeError(\"not a promise\")}var o=ce.SpeciesConstructor(n,E);var i;var b=arguments.length>2&&arguments[2]===y;if(b&&o===E){i=y}else{i=new r(o)}var g=ce.IsCallable(e)?e:a;var d=ce.IsCallable(t)?t:u;var m=n._promise;var O;if(m.state===f){if(m.reactionLength===0){m.fulfillReactionHandler0=g;m.rejectReactionHandler0=d;m.reactionCapability0=i}else{var w=3*(m.reactionLength-1);m[w+l]=g;m[w+p]=d;m[w+v]=i}m.reactionLength+=1}else if(m.state===s){O=m.result;h(g,i,O)}else if(m.state===c){O=m.result;h(d,i,O)}else{throw new TypeError(\"unexpected Promise state\")}return i.promise}});y=new r(E);I=T.then;return E}();if(S.Promise){delete S.Promise.accept;delete S.Promise.defer;delete S.Promise.prototype.chain}if(typeof Fr===\"function\"){b(S,{Promise:Fr});var Dr=w(S.Promise,function(e){return e.resolve(42).then(function(){})instanceof e});var zr=!i(function(){return S.Promise.reject(42).then(null,5).then(null,W)});var qr=i(function(){return S.Promise.call(3,W)});var Wr=function(e){var t=e.resolve(5);t.constructor={};var r=e.resolve(t);try{r.then(null,W).then(null,W)}catch(n){return true}return t===r}(S.Promise);var Gr=s&&function(){var e=0;var t=Object.defineProperty({},\"then\",{get:function(){e+=1}});Promise.resolve(t);return e===1}();var Hr=function BadResolverPromise(e){var t=new Promise(e);e(3,function(){});this.then=t.then;this.constructor=BadResolverPromise};Hr.prototype=Promise.prototype;Hr.all=Promise.all;var Vr=a(function(){return!!Hr.all([1,2])});if(!Dr||!zr||!qr||Wr||!Gr||Vr){Promise=Fr;ne(S,\"Promise\",Fr)}if(Promise.all.length!==1){var Br=Promise.all;ne(Promise,\"all\",function all(e){return ce.Call(Br,this,arguments)})}if(Promise.race.length!==1){var Ur=Promise.race;ne(Promise,\"race\",function race(e){return ce.Call(Ur,this,arguments)})}if(Promise.resolve.length!==1){var $r=Promise.resolve;ne(Promise,\"resolve\",function resolve(e){return ce.Call($r,this,arguments)})}if(Promise.reject.length!==1){var Jr=Promise.reject;ne(Promise,\"reject\",function reject(e){return ce.Call(Jr,this,arguments)})}Mt(Promise,\"all\");Mt(Promise,\"race\");Mt(Promise,\"resolve\");Mt(Promise,\"reject\");Ce(Promise)}var Xr=function(e){var t=n(p(e,function(e,t){e[t]=true;return e},{}));return e.join(\":\")===t.join(\":\")};var Kr=Xr([\"z\",\"a\",\"bb\"]);var Zr=Xr([\"z\",1,\"a\",\"3\",2]);if(s){var Yr=function fastkey(e,t){if(!t&&!Kr){return null}if(se(e)){return\"^\"+ce.ToString(e)}else if(typeof e===\"string\"){return\"$\"+e}else if(typeof e===\"number\"){if(!Zr){return\"n\"+e}return e}else if(typeof e===\"boolean\"){return\"b\"+e}return null};var Qr=function emptyObject(){return Object.create?Object.create(null):{}};var en=function addIterableToMap(e,n,o){if(r(o)||re.string(o)){l(o,function(e){if(!ce.TypeIsObject(e)){throw new TypeError(\"Iterator value \"+e+\" is not an entry object\")}n.set(e[0],e[1])})}else if(o instanceof e){t(e.prototype.forEach,o,function(e,t){n.set(t,e)})}else{var i,a;if(!se(o)){a=n.set;if(!ce.IsCallable(a)){throw new TypeError(\"bad map\")}i=ce.GetIterator(o)}if(typeof i!==\"undefined\"){while(true){var u=ce.IteratorStep(i);if(u===false){break}var f=u.value;try{if(!ce.TypeIsObject(f)){throw new TypeError(\"Iterator value \"+f+\" is not an entry object\")}t(a,n,f[0],f[1])}catch(s){ce.IteratorClose(i,true);throw s}}}}};var tn=function addIterableToSet(e,n,o){if(r(o)||re.string(o)){l(o,function(e){n.add(e)})}else if(o instanceof e){t(e.prototype.forEach,o,function(e){n.add(e)})}else{var i,a;if(!se(o)){a=n.add;if(!ce.IsCallable(a)){throw new TypeError(\"bad set\")}i=ce.GetIterator(o)}if(typeof i!==\"undefined\"){while(true){var u=ce.IteratorStep(i);if(u===false){break}var f=u.value;try{t(a,n,f)}catch(s){ce.IteratorClose(i,true);throw s}}}}};var rn={Map:function(){var e={};var r=function MapEntry(e,t){this.key=e;this.value=t;this.next=null;this.prev=null};r.prototype.isRemoved=function isRemoved(){return this.key===e};var n=function isMap(e){return!!e._es6map};var o=function requireMapSlot(e,t){if(!ce.TypeIsObject(e)||!n(e)){throw new TypeError(\"Method Map.prototype.\"+t+\" called on incompatible receiver \"+ce.ToString(e))}};var i=function MapIterator(e,t){o(e,\"[[MapIterator]]\");this.head=e._head;this.i=this.head;this.kind=t};i.prototype={isMapIterator:true,next:function next(){if(!this.isMapIterator){throw new TypeError(\"Not a MapIterator\")}var e=this.i;var t=this.kind;var r=this.head;if(typeof this.i===\"undefined\"){return Ke()}while(e.isRemoved()&&e!==r){e=e.prev}var n;while(e.next!==r){e=e.next;if(!e.isRemoved()){if(t===\"key\"){n=e.key}else if(t===\"value\"){n=e.value}else{n=[e.key,e.value]}this.i=e;return Ke(n)}}this.i=void 0;return Ke()}};Me(i.prototype);var a;var u=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}if(this&&this._es6map){throw new TypeError(\"Bad construction\")}var e=Ae(this,Map,a,{_es6map:true,_head:null,_map:G?new G:null,_size:0,_storage:Qr()});var t=new r(null,null);t.next=t.prev=t;e._head=t;if(arguments.length>0){en(Map,e,arguments[0])}return e};a=u.prototype;m.getter(a,\"size\",function(){if(typeof this._size===\"undefined\"){throw new TypeError(\"size method called on incompatible Map\")}return this._size});b(a,{get:function get(e){o(this,\"get\");var t;var r=Yr(e,true);if(r!==null){t=this._storage[r];if(t){return t.value}else{return}}if(this._map){t=V.call(this._map,e);if(t){return t.value}else{return}}var n=this._head;var i=n;while((i=i.next)!==n){if(ce.SameValueZero(i.key,e)){return i.value}}},has:function has(e){o(this,\"has\");var t=Yr(e,true);if(t!==null){return typeof this._storage[t]!==\"undefined\"}if(this._map){return B.call(this._map,e)}var r=this._head;var n=r;while((n=n.next)!==r){if(ce.SameValueZero(n.key,e)){return true}}return false},set:function set(e,t){o(this,\"set\");var n=this._head;var i=n;var a;var u=Yr(e,true);if(u!==null){if(typeof this._storage[u]!==\"undefined\"){this._storage[u].value=t;return this}else{a=this._storage[u]=new r(e,t);i=n.prev}}else if(this._map){if(B.call(this._map,e)){V.call(this._map,e).value=t}else{a=new r(e,t);U.call(this._map,e,a);i=n.prev}}while((i=i.next)!==n){if(ce.SameValueZero(i.key,e)){i.value=t;return this}}a=a||new r(e,t);if(ce.SameValue(-0,e)){a.key=+0}a.next=this._head;a.prev=this._head.prev;a.prev.next=a;a.next.prev=a;this._size+=1;return this},\"delete\":function(t){o(this,\"delete\");var r=this._head;var n=r;var i=Yr(t,true);if(i!==null){if(typeof this._storage[i]===\"undefined\"){return false}n=this._storage[i].prev;delete this._storage[i]}else if(this._map){if(!B.call(this._map,t)){return false}n=V.call(this._map,t).prev;H.call(this._map,t)}while((n=n.next)!==r){if(ce.SameValueZero(n.key,t)){n.key=e;n.value=e;n.prev.next=n.next;n.next.prev=n.prev;this._size-=1;return true}}return false},clear:function clear(){o(this,\"clear\");this._map=G?new G:null;this._size=0;this._storage=Qr();var t=this._head;var r=t;var n=r.next;while((r=n)!==t){r.key=e;r.value=e;n=r.next;r.next=r.prev=t}t.next=t.prev=t},keys:function keys(){o(this,\"keys\");return new i(this,\"key\")},values:function values(){o(this,\"values\");return new i(this,\"value\")},entries:function entries(){o(this,\"entries\");return new i(this,\"key+value\")},forEach:function forEach(e){o(this,\"forEach\");var r=arguments.length>1?arguments[1]:null;var n=this.entries();for(var i=n.next();!i.done;i=n.next()){if(r){t(e,r,i.value[1],i.value[0],this)}else{e(i.value[1],i.value[0],this)}}}});Me(a,a.entries);return u}(),Set:function(){var e=function isSet(e){return e._es6set&&typeof e._storage!==\"undefined\"};var r=function requireSetSlot(t,r){if(!ce.TypeIsObject(t)||!e(t)){throw new TypeError(\"Set.prototype.\"+r+\" called on incompatible receiver \"+ce.ToString(t))}};var o;var i=function Set(){if(!(this instanceof Set)){throw new TypeError('Constructor Set requires \"new\"')}if(this&&this._es6set){throw new TypeError(\"Bad construction\")}var e=Ae(this,Set,o,{_es6set:true,\"[[SetData]]\":null,_storage:Qr()});if(!e._es6set){throw new TypeError(\"bad set\")}if(arguments.length>0){tn(Set,e,arguments[0])}return e};o=i.prototype;var a=function(e){var t=e;if(t===\"^null\"){return null}else if(t===\"^undefined\"){return void 0}else{var r=t.charAt(0);if(r===\"$\"){return C(t,1)}else if(r===\"n\"){return+C(t,1)}else if(r===\"b\"){return t===\"btrue\"}}return+t};var u=function ensureMap(e){if(!e[\"[[SetData]]\"]){var t=new rn.Map;e[\"[[SetData]]\"]=t;l(n(e._storage),function(e){var r=a(e);t.set(r,r)});e[\"[[SetData]]\"]=t}e._storage=null};m.getter(i.prototype,\"size\",function(){r(this,\"size\");if(this._storage){return n(this._storage).length}u(this);return this[\"[[SetData]]\"].size});b(i.prototype,{has:function has(e){r(this,\"has\");var t;if(this._storage&&(t=Yr(e))!==null){return!!this._storage[t]}u(this);return this[\"[[SetData]]\"].has(e)},add:function add(e){r(this,\"add\");var t;if(this._storage&&(t=Yr(e))!==null){this._storage[t]=true;return this}u(this);this[\"[[SetData]]\"].set(e,e);return this},\"delete\":function(e){r(this,\"delete\");var t;if(this._storage&&(t=Yr(e))!==null){var n=z(this._storage,t);return delete this._storage[t]&&n}u(this);return this[\"[[SetData]]\"][\"delete\"](e)},clear:function clear(){r(this,\"clear\");if(this._storage){this._storage=Qr()}if(this[\"[[SetData]]\"]){this[\"[[SetData]]\"].clear()}},values:function values(){r(this,\"values\");u(this);return new f(this[\"[[SetData]]\"].values())},entries:function entries(){r(this,\"entries\");u(this);return new f(this[\"[[SetData]]\"].entries())},forEach:function forEach(e){r(this,\"forEach\");var n=arguments.length>1?arguments[1]:null;var o=this;u(o);this[\"[[SetData]]\"].forEach(function(r,i){if(n){t(e,n,i,i,o)}else{e(i,i,o)}})}});h(i.prototype,\"keys\",i.prototype.values,true);Me(i.prototype,i.prototype.values);var f=function SetIterator(e){this.it=e};f.prototype={isSetIterator:true,next:function next(){if(!this.isSetIterator){throw new TypeError(\"Not a SetIterator\")}return this.it.next()}};Me(f.prototype);return i}()};var nn=S.Set&&!Set.prototype[\"delete\"]&&Set.prototype.remove&&Set.prototype.items&&Set.prototype.map&&Array.isArray((new Set).keys);if(nn){S.Set=rn.Set}if(S.Map||S.Set){var on=a(function(){return new Map([[1,2]]).get(1)===2});if(!on){S.Map=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}var e=new G;if(arguments.length>0){en(Map,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,S.Map.prototype);return e};S.Map.prototype=O(G.prototype);h(S.Map.prototype,\"constructor\",S.Map,true);m.preserveToString(S.Map,G)}var an=new Map;var un=function(){var e=new Map([[1,0],[2,0],[3,0],[4,0]]);e.set(-0,e);return e.get(0)===e&&e.get(-0)===e&&e.has(0)&&e.has(-0)}();var fn=an.set(1,2)===an;if(!un||!fn){ne(Map.prototype,\"set\",function set(e,r){t(U,this,e===0?0:e,r);return this})}if(!un){b(Map.prototype,{get:function get(e){return t(V,this,e===0?0:e)},has:function has(e){return t(B,this,e===0?0:e)}},true);m.preserveToString(Map.prototype.get,V);m.preserveToString(Map.prototype.has,B)}var sn=new Set;var cn=Set.prototype[\"delete\"]&&Set.prototype.add&&Set.prototype.has&&function(e){e[\"delete\"](0);e.add(-0);return!e.has(0)}(sn);var ln=sn.add(1)===sn;if(!cn||!ln){var pn=Set.prototype.add;Set.prototype.add=function add(e){t(pn,this,e===0?0:e);return this};m.preserveToString(Set.prototype.add,pn)}if(!cn){var vn=Set.prototype.has;Set.prototype.has=function has(e){return t(vn,this,e===0?0:e)};m.preserveToString(Set.prototype.has,vn);var yn=Set.prototype[\"delete\"];Set.prototype[\"delete\"]=function SetDelete(e){return t(yn,this,e===0?0:e)};m.preserveToString(Set.prototype[\"delete\"],yn)}var hn=w(S.Map,function(e){var t=new e([]);t.set(42,42);return t instanceof e});var bn=Object.setPrototypeOf&&!hn;var gn=function(){try{return!(S.Map()instanceof S.Map)}catch(e){return e instanceof TypeError}}();if(S.Map.length!==0||bn||!gn){S.Map=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}var e=new G;if(arguments.length>0){en(Map,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,Map.prototype);return e};S.Map.prototype=G.prototype;h(S.Map.prototype,\"constructor\",S.Map,true);m.preserveToString(S.Map,G)}var dn=w(S.Set,function(e){var t=new e([]);t.add(42,42);return t instanceof e});var mn=Object.setPrototypeOf&&!dn;var On=function(){try{return!(S.Set()instanceof S.Set)}catch(e){return e instanceof TypeError}}();if(S.Set.length!==0||mn||!On){var wn=S.Set;S.Set=function Set(){if(!(this instanceof Set)){throw new TypeError('Constructor Set requires \"new\"')}var e=new wn;if(arguments.length>0){tn(Set,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,Set.prototype);return e};S.Set.prototype=wn.prototype;h(S.Set.prototype,\"constructor\",S.Set,true);m.preserveToString(S.Set,wn)}var jn=new S.Map;var Sn=!a(function(){return jn.keys().next().done});if(typeof S.Map.prototype.clear!==\"function\"||(new S.Set).size!==0||jn.size!==0||typeof S.Map.prototype.keys!==\"function\"||typeof S.Set.prototype.keys!==\"function\"||typeof S.Map.prototype.forEach!==\"function\"||typeof S.Set.prototype.forEach!==\"function\"||u(S.Map)||u(S.Set)||typeof jn.keys().next!==\"function\"||Sn||!hn){b(S,{Map:rn.Map,Set:rn.Set},true)}if(S.Set.prototype.keys!==S.Set.prototype.values){h(S.Set.prototype,\"keys\",S.Set.prototype.values,true)}Me(Object.getPrototypeOf((new S.Map).keys()));Me(Object.getPrototypeOf((new S.Set).keys()));if(c&&S.Set.prototype.has.name!==\"has\"){var Tn=S.Set.prototype.has;ne(S.Set.prototype,\"has\",function has(e){return t(Tn,this,e)})}}b(S,rn);Ce(S.Map);Ce(S.Set)}var In=function throwUnlessTargetIsObject(e){if(!ce.TypeIsObject(e)){throw new TypeError(\"target must be an object\")}};var En={apply:function apply(){return ce.Call(ce.Call,null,arguments)},construct:function construct(e,t){if(!ce.IsConstructor(e)){throw new TypeError(\"First argument must be a constructor.\")}var r=arguments.length>2?arguments[2]:e;if(!ce.IsConstructor(r)){throw new TypeError(\"new.target must be a constructor.\")}return ce.Construct(e,t,r,\"internal\")},deleteProperty:function deleteProperty(e,t){In(e);if(s){var r=Object.getOwnPropertyDescriptor(e,t);if(r&&!r.configurable){return false}}return delete e[t]},has:function has(e,t){In(e);return t in e}};if(Object.getOwnPropertyNames){Object.assign(En,{ownKeys:function ownKeys(e){In(e);var t=Object.getOwnPropertyNames(e);if(ce.IsCallable(Object.getOwnPropertySymbols)){x(t,Object.getOwnPropertySymbols(e))}return t}})}var Pn=function ConvertExceptionToBoolean(e){return!i(e)};if(Object.preventExtensions){Object.assign(En,{isExtensible:function isExtensible(e){In(e);return Object.isExtensible(e)},preventExtensions:function preventExtensions(e){In(e);return Pn(function(){return Object.preventExtensions(e)})}})}if(s){var Cn=function get(e,t,r){var n=Object.getOwnPropertyDescriptor(e,t);if(!n){var o=Object.getPrototypeOf(e);if(o===null){return void 0}return Cn(o,t,r)}if(\"value\"in n){return n.value}if(n.get){return ce.Call(n.get,r)}return void 0};var Mn=function set(e,r,n,o){var i=Object.getOwnPropertyDescriptor(e,r);if(!i){var a=Object.getPrototypeOf(e);if(a!==null){return Mn(a,r,n,o)}i={value:void 0,writable:true,enumerable:true,configurable:true}}if(\"value\"in i){if(!i.writable){return false}if(!ce.TypeIsObject(o)){return false}var u=Object.getOwnPropertyDescriptor(o,r);if(u){return ae.defineProperty(o,r,{value:n})}else{return ae.defineProperty(o,r,{value:n,writable:true,enumerable:true,configurable:true})}}if(i.set){t(i.set,o,n);return true}return false};Object.assign(En,{defineProperty:function defineProperty(e,t,r){In(e);return Pn(function(){return Object.defineProperty(e,t,r)})},getOwnPropertyDescriptor:function getOwnPropertyDescriptor(e,t){In(e);return Object.getOwnPropertyDescriptor(e,t)},get:function get(e,t){In(e);var r=arguments.length>2?arguments[2]:e;return Cn(e,t,r)},set:function set(e,t,r){In(e);var n=arguments.length>3?arguments[3]:e;return Mn(e,t,r,n)}})}if(Object.getPrototypeOf){var xn=Object.getPrototypeOf;En.getPrototypeOf=function getPrototypeOf(e){In(e);return xn(e)}}if(Object.setPrototypeOf&&En.getPrototypeOf){var Nn=function(e,t){var r=t;while(r){if(e===r){return true}r=En.getPrototypeOf(r)}return false};Object.assign(En,{setPrototypeOf:function setPrototypeOf(e,t){In(e);if(t!==null&&!ce.TypeIsObject(t)){throw new TypeError(\"proto must be an object or null\")}if(t===ae.getPrototypeOf(e)){return true}if(ae.isExtensible&&!ae.isExtensible(e)){return false}if(Nn(e,t)){return false}Object.setPrototypeOf(e,t);return true}})}var An=function(e,t){if(!ce.IsCallable(S.Reflect[e])){h(S.Reflect,e,t)}else{var r=a(function(){S.Reflect[e](1);S.Reflect[e](NaN);S.Reflect[e](true);return true});if(r){ne(S.Reflect,e,t)}}};Object.keys(En).forEach(function(e){An(e,En[e])});var Rn=S.Reflect.getPrototypeOf;if(c&&Rn&&Rn.name!==\"getPrototypeOf\"){ne(S.Reflect,\"getPrototypeOf\",function getPrototypeOf(e){return t(Rn,S.Reflect,e)})}if(S.Reflect.setPrototypeOf){if(a(function(){S.Reflect.setPrototypeOf(1,{});return true})){ne(S.Reflect,\"setPrototypeOf\",En.setPrototypeOf)}}if(S.Reflect.defineProperty){if(!a(function(){var e=!S.Reflect.defineProperty(1,\"test\",{value:1});var t=typeof Object.preventExtensions!==\"function\"||!S.Reflect.defineProperty(Object.preventExtensions({}),\"test\",{});return e&&t})){ne(S.Reflect,\"defineProperty\",En.defineProperty)}}if(S.Reflect.construct){if(!a(function(){var e=function F(){};return S.Reflect.construct(function(){},[],e)instanceof e})){ne(S.Reflect,\"construct\",En.construct)}}if(String(new Date(NaN))!==\"Invalid Date\"){var _n=Date.prototype.toString;var kn=function toString(){var e=+this;if(e!==e){return\"Invalid Date\"}return ce.Call(_n,this)};ne(Date.prototype,\"toString\",kn)}var Ln={anchor:function anchor(e){return ce.CreateHTML(this,\"a\",\"name\",e)},big:function big(){return ce.CreateHTML(this,\"big\",\"\",\"\")},blink:function blink(){return ce.CreateHTML(this,\"blink\",\"\",\"\")},bold:function bold(){return ce.CreateHTML(this,\"b\",\"\",\"\")},fixed:function fixed(){return ce.CreateHTML(this,\"tt\",\"\",\"\")},fontcolor:function fontcolor(e){return ce.CreateHTML(this,\"font\",\"color\",e)},fontsize:function fontsize(e){return ce.CreateHTML(this,\"font\",\"size\",e)},italics:function italics(){return ce.CreateHTML(this,\"i\",\"\",\"\")},link:function link(e){return ce.CreateHTML(this,\"a\",\"href\",e)},small:function small(){return ce.CreateHTML(this,\"small\",\"\",\"\")},strike:function strike(){return ce.CreateHTML(this,\"strike\",\"\",\"\")},sub:function sub(){return ce.CreateHTML(this,\"sub\",\"\",\"\")},sup:function sub(){return ce.CreateHTML(this,\"sup\",\"\",\"\")}};l(Object.keys(Ln),function(e){var r=String.prototype[e];var n=false;if(ce.IsCallable(r)){var o=t(r,\"\",' \" ');var i=P([],o.match(/\"/g)).length;n=o!==o.toLowerCase()||i>2}else{n=true}if(n){ne(String.prototype,e,Ln[e])}});var Fn=function(){if(!oe){return false}var e=typeof JSON===\"object\"&&typeof JSON.stringify===\"function\"?JSON.stringify:null;if(!e){return false}if(typeof e($())!==\"undefined\"){return true}if(e([$()])!==\"[null]\"){return true}var t={a:$()};t[$()]=true;if(e(t)!==\"{}\"){return true}return false}();var Dn=a(function(){if(!oe){return true}return JSON.stringify(Object($()))===\"{}\"&&JSON.stringify([Object($())])===\"[{}]\"});if(Fn||!Dn){var zn=JSON.stringify;ne(JSON,\"stringify\",function stringify(e){if(typeof e===\"symbol\"){return}var n;if(arguments.length>1){n=arguments[1]}var o=[e];if(!r(n)){var i=ce.IsCallable(n)?n:null;var a=function(e,r){var n=i?t(i,this,e,r):r;if(typeof n!==\"symbol\"){if(re.symbol(n)){return Nt({})(n)}else{return n}}};o.push(a)}else{o.push(n)}if(arguments.length>2){o.push(arguments[2])}return zn.apply(this,o)})}return S});\n//# sourceMappingURL=es6-shim.map\n/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */\n!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return t(e)}:t(e)}(\"undefined\"!=typeof window?window:this,function(C,e){\"use strict\";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return\"function\"==typeof e&&\"number\"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement(\"script\");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?n[o.call(e)]||\"object\":typeof e}var f=\"3.4.1\",k=function(e,t){return new k.fn.init(e,t)},p=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;function d(e){var t=!!e&&\"length\"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&0<t&&t-1 in e)}k.fn=k.prototype={jquery:f,constructor:k,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=k.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return k.each(this,e)},map:function(n){return this.pushStack(k.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},k.extend=k.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for(\"boolean\"==typeof a&&(l=a,a=arguments[s]||{},s++),\"object\"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],\"__proto__\"!==t&&a!==r&&(l&&r&&(k.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||k.isPlainObject(n)?n:{},i=!1,a[t]=k.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},k.extend({expando:\"jQuery\"+(f+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||\"[object Object]\"!==o.call(e))&&(!(t=r(e))||\"function\"==typeof(n=v.call(t,\"constructor\")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t){b(e,{nonce:t&&t.nonce})},each:function(e,t){var n,r=0;if(d(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?\"\":(e+\"\").replace(p,\"\")},makeArray:function(e,t){var n=t||[];return null!=e&&(d(Object(e))?k.merge(n,\"string\"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(d(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g.apply([],a)},guid:1,support:y}),\"function\"==typeof Symbol&&(k.fn[Symbol.iterator]=t[Symbol.iterator]),k.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){n[\"[object \"+t+\"]\"]=t.toLowerCase()});var h=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,k=\"sizzle\"+1*new Date,m=n.document,S=0,r=0,p=ue(),x=ue(),N=ue(),A=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",M=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",I=\"(?:\\\\\\\\.|[\\\\w-]|[^\\0-\\\\xa0])+\",W=\"\\\\[\"+M+\"*(\"+I+\")(?:\"+M+\"*([*^$|!~]?=)\"+M+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+I+\"))|)\"+M+\"*\\\\]\",$=\":(\"+I+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+W+\")*)|.*)\\\\)|)\",F=new RegExp(M+\"+\",\"g\"),B=new RegExp(\"^\"+M+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+M+\"+$\",\"g\"),_=new RegExp(\"^\"+M+\"*,\"+M+\"*\"),z=new RegExp(\"^\"+M+\"*([>+~]|\"+M+\")\"+M+\"*\"),U=new RegExp(M+\"|>\"),X=new RegExp($),V=new RegExp(\"^\"+I+\"$\"),G={ID:new RegExp(\"^#(\"+I+\")\"),CLASS:new RegExp(\"^\\\\.(\"+I+\")\"),TAG:new RegExp(\"^(\"+I+\"|[*])\"),ATTR:new RegExp(\"^\"+W),PSEUDO:new RegExp(\"^\"+$),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+M+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+M+\"*(?:([+-]|)\"+M+\"*(\\\\d+)|))\"+M+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+R+\")$\",\"i\"),needsContext:new RegExp(\"^\"+M+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+M+\"*((?:-\\\\d)?\\\\d*)\"+M+\"*\\\\)|)(?=[^-]|$)\",\"i\")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\\d$/i,K=/^[^{]+\\{\\s*\\[native \\w/,Z=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,ee=/[+~]/,te=new RegExp(\"\\\\\\\\([\\\\da-f]{1,6}\"+M+\"?|(\"+M+\")|.)\",\"ig\"),ne=function(e,t,n){var r=\"0x\"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,ie=function(e,t){return t?\"\\0\"===e?\"\\ufffd\":e.slice(0,-1)+\"\\\\\"+e.charCodeAt(e.length-1).toString(16)+\" \":\"\\\\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&\"fieldset\"===e.nodeName.toLowerCase()},{dir:\"parentNode\",next:\"legend\"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],\"string\"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+\" \"]&&(!v||!v.test(t))&&(1!==p||\"object\"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute(\"id\"))?s=s.replace(re,ie):e.setAttribute(\"id\",s=k),o=(l=h(t)).length;while(o--)l[o]=\"#\"+s+\" \"+xe(l[o]);c=l.join(\",\"),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute(\"id\")}}}return g(t.replace(B,\"$1\"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+\" \")>b.cacheLength&&delete e[r.shift()],e[t+\" \"]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement(\"fieldset\");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split(\"|\"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return\"input\"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return(\"input\"===t||\"button\"===t)&&e.type===n}}function ge(t){return function(e){return\"form\"in e?e.parentNode&&!1===e.disabled?\"label\"in e?\"label\"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:\"label\"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&\"undefined\"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||\"HTML\")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener(\"unload\",oe,!1):n.attachEvent&&n.attachEvent(\"onunload\",oe)),d.attributes=ce(function(e){return e.className=\"i\",!e.getAttribute(\"className\")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment(\"\")),!e.getElementsByTagName(\"*\").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute(\"id\")===t}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t=\"undefined\"!=typeof e.getAttributeNode&&e.getAttributeNode(\"id\");return t&&t.value===n}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return\"undefined\"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if(\"*\"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if(\"undefined\"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML=\"<a id='\"+k+\"'></a><select id='\"+k+\"-\\r\\\\' msallowcapture=''><option selected=''></option></select>\",e.querySelectorAll(\"[msallowcapture^='']\").length&&v.push(\"[*^$]=\"+M+\"*(?:''|\\\"\\\")\"),e.querySelectorAll(\"[selected]\").length||v.push(\"\\\\[\"+M+\"*(?:value|\"+R+\")\"),e.querySelectorAll(\"[id~=\"+k+\"-]\").length||v.push(\"~=\"),e.querySelectorAll(\":checked\").length||v.push(\":checked\"),e.querySelectorAll(\"a#\"+k+\"+*\").length||v.push(\".#.+[+~]\")}),ce(function(e){e.innerHTML=\"<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>\";var t=C.createElement(\"input\");t.setAttribute(\"type\",\"hidden\"),e.appendChild(t).setAttribute(\"name\",\"D\"),e.querySelectorAll(\"[name=d]\").length&&v.push(\"name\"+M+\"*[*^$|!~]?=\"),2!==e.querySelectorAll(\":enabled\").length&&v.push(\":enabled\",\":disabled\"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(\":disabled\").length&&v.push(\":enabled\",\":disabled\"),e.querySelectorAll(\"*,:x\"),v.push(\",.*:\")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,\"*\"),c.call(e,\"[s!='']:x\"),s.push(\"!=\",$)}),v=v.length&&new RegExp(v.join(\"|\")),s=s.length&&new RegExp(s.join(\"|\")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+\" \"]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!==C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!==C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+\"\").replace(re,ie)},se.error=function(e){throw new Error(\"Syntax error, unrecognized expression: \"+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n=\"\",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if(\"string\"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||\"\").replace(te,ne),\"~=\"===e[2]&&(e[3]=\" \"+e[3]+\" \"),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),\"nth\"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*(\"even\"===e[3]||\"odd\"===e[3])),e[5]=+(e[7]+e[8]||\"odd\"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||\"\":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(\")\",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return\"*\"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+\" \"];return t||(t=new RegExp(\"(^|\"+M+\")\"+e+\"(\"+M+\"|$)\"))&&p(e,function(e){return t.test(\"string\"==typeof e.className&&e.className||\"undefined\"!=typeof e.getAttribute&&e.getAttribute(\"class\")||\"\")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?\"!=\"===r:!r||(t+=\"\",\"=\"===r?t===i:\"!=\"===r?t!==i:\"^=\"===r?i&&0===t.indexOf(i):\"*=\"===r?i&&-1<t.indexOf(i):\"$=\"===r?i&&t.slice(-i.length)===i:\"~=\"===r?-1<(\" \"+t.replace(F,\" \")+\" \").indexOf(i):\"|=\"===r&&(t===i||t.slice(0,i.length+1)===i+\"-\"))}},CHILD:function(h,e,t,g,v){var y=\"nth\"!==h.slice(0,3),m=\"last\"!==h.slice(-4),x=\"of-type\"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?\"nextSibling\":\"previousSibling\",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l=\"only\"===h&&!u&&\"nextSibling\"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[S,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[S,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error(\"unsupported pseudo: \"+e);return a[k]?a(o):1<a.length?(t=[e,e,\"\",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace(B,\"$1\"));return s[k]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||\"\")||se.error(\"unsupported lang: \"+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute(\"xml:lang\")||e.getAttribute(\"lang\"))return(t=t.toLowerCase())===n||0===t.indexOf(n+\"-\")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&!!e.checked||\"option\"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&\"button\"===e.type||\"button\"===t},text:function(e){var t;return\"input\"===e.nodeName.toLowerCase()&&\"text\"===e.type&&(null==(t=e.getAttribute(\"type\"))||\"text\"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r=\"\";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&\"parentNode\"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[S,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[k]||(e[k]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===S&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[k]&&(v=Ce(v)),y&&!y[k]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||\"*\",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[\" \"],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[k]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:\" \"===e[s-2].type?\"*\":\"\"})).replace(B,\"$1\"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+\" \"];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace(B,\" \")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=N[e+\" \"];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[k]?i.push(a):o.push(a);(a=N(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l=\"0\",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG(\"*\",i),h=S+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t===C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument===C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(S=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(S=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l=\"function\"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&\"ID\"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=k.split(\"\").sort(D).join(\"\")===k,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement(\"fieldset\"))}),ce(function(e){return e.innerHTML=\"<a href='#'></a>\",\"#\"===e.firstChild.getAttribute(\"href\")})||fe(\"type|href|height|width\",function(e,t,n){if(!n)return e.getAttribute(t,\"type\"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML=\"<input/>\",e.firstChild.setAttribute(\"value\",\"\"),\"\"===e.firstChild.getAttribute(\"value\")})||fe(\"value\",function(e,t,n){if(!n&&\"input\"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute(\"disabled\")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);k.find=h,k.expr=h.selectors,k.expr[\":\"]=k.expr.pseudos,k.uniqueSort=k.unique=h.uniqueSort,k.text=h.getText,k.isXMLDoc=h.isXML,k.contains=h.contains,k.escapeSelector=h.escape;var T=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&k(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},N=k.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var D=/^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):\"string\"!=typeof n?k.grep(e,function(e){return-1<i.call(n,e)!==r}):k.filter(n,e,r)}k.filter=function(e,t,n){var r=t[0];return n&&(e=\":not(\"+e+\")\"),1===t.length&&1===r.nodeType?k.find.matchesSelector(r,e)?[r]:[]:k.find.matches(e,k.grep(t,function(e){return 1===e.nodeType}))},k.fn.extend({find:function(e){var t,n,r=this.length,i=this;if(\"string\"!=typeof e)return this.pushStack(k(e).filter(function(){for(t=0;t<r;t++)if(k.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)k.find(e,i[t],n);return 1<r?k.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,\"string\"==typeof e&&N.test(e)?k(e):e||[],!1).length}});var q,L=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,\"string\"==typeof e){if(!(r=\"<\"===e[0]&&\">\"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(k.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a=\"string\"!=typeof e&&k(e);if(!N.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&k.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?k.uniqueSort(o):o)},index:function(e){return e?\"string\"==typeof e?i.call(k(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(k.uniqueSort(k.merge(this.get(),k(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),k.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return T(e,\"parentNode\")},parentsUntil:function(e,t,n){return T(e,\"parentNode\",n)},next:function(e){return P(e,\"nextSibling\")},prev:function(e){return P(e,\"previousSibling\")},nextAll:function(e){return T(e,\"nextSibling\")},prevAll:function(e){return T(e,\"previousSibling\")},nextUntil:function(e,t,n){return T(e,\"nextSibling\",n)},prevUntil:function(e,t,n){return T(e,\"previousSibling\",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return\"undefined\"!=typeof e.contentDocument?e.contentDocument:(A(e,\"template\")&&(e=e.content||e),k.merge([],e.childNodes))}},function(r,i){k.fn[r]=function(e,t){var n=k.map(this,i,e);return\"Until\"!==r.slice(-5)&&(t=e),t&&\"string\"==typeof t&&(n=k.filter(t,n)),1<this.length&&(O[r]||k.uniqueSort(n),H.test(r)&&n.reverse()),this.pushStack(n)}});var R=/[^\\x20\\t\\r\\n\\f]+/g;function M(e){return e}function I(e){throw e}function W(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}k.Callbacks=function(r){var e,n;r=\"string\"==typeof r?(e=r,n={},k.each(e.match(R)||[],function(e,t){n[t]=!0}),n):k.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:\"\")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){k.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&\"string\"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return k.each(arguments,function(e,t){var n;while(-1<(n=k.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<k.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t=\"\",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=\"\"),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},k.extend({Deferred:function(e){var o=[[\"notify\",\"progress\",k.Callbacks(\"memory\"),k.Callbacks(\"memory\"),2],[\"resolve\",\"done\",k.Callbacks(\"once memory\"),k.Callbacks(\"once memory\"),0,\"resolved\"],[\"reject\",\"fail\",k.Callbacks(\"once memory\"),k.Callbacks(\"once memory\"),1,\"rejected\"]],i=\"pending\",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},\"catch\":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return k.Deferred(function(r){k.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+\"With\"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError(\"Thenable self-resolution\");t=e&&(\"object\"==typeof e||\"function\"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,M,s),l(u,o,I,s)):(u++,t.call(e,l(u,o,M,s),l(u,o,I,s),l(u,o,M,o.notifyWith))):(a!==M&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){k.Deferred.exceptionHook&&k.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==I&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(k.Deferred.getStackHook&&(t.stackTrace=k.Deferred.getStackHook()),C.setTimeout(t))}}return k.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:M,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:M)),o[2][3].add(l(0,e,m(n)?n:I))}).promise()},promise:function(e){return null!=e?k.extend(e,a):a}},s={};return k.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+\"With\"](this===s?void 0:this,arguments),this},s[t[0]+\"With\"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=k.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(W(e,o.done(a(t)).resolve,o.reject,!n),\"pending\"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)W(i[t],a(t),o.reject);return o.promise()}});var $=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;k.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&$.test(e.name)&&C.console.warn(\"jQuery.Deferred exception: \"+e.message,e.stack,t)},k.readyException=function(e){C.setTimeout(function(){throw e})};var F=k.Deferred();function B(){E.removeEventListener(\"DOMContentLoaded\",B),C.removeEventListener(\"load\",B),k.ready()}k.fn.ready=function(e){return F.then(e)[\"catch\"](function(e){k.readyException(e)}),this},k.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--k.readyWait:k.isReady)||(k.isReady=!0)!==e&&0<--k.readyWait||F.resolveWith(E,[k])}}),k.ready.then=F.then,\"complete\"===E.readyState||\"loading\"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(k.ready):(E.addEventListener(\"DOMContentLoaded\",B),C.addEventListener(\"load\",B));var _=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if(\"object\"===w(n))for(s in i=!0,n)_(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(k(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},z=/^-ms-/,U=/-([a-z])/g;function X(e,t){return t.toUpperCase()}function V(e){return e.replace(z,\"ms-\").replace(U,X)}var G=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function Y(){this.expando=k.expando+Y.uid++}Y.uid=1,Y.prototype={cache:function(e){var t=e[this.expando];return t||(t={},G(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if(\"string\"==typeof t)i[V(t)]=n;else for(r in t)i[V(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][V(t)]},access:function(e,t,n){return void 0===t||t&&\"string\"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(V):(t=V(t))in r?[t]:t.match(R)||[]).length;while(n--)delete r[t[n]]}(void 0===t||k.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!k.isEmptyObject(t)}};var Q=new Y,J=new Y,K=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,Z=/[A-Z]/g;function ee(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r=\"data-\"+t.replace(Z,\"-$&\").toLowerCase(),\"string\"==typeof(n=e.getAttribute(r))){try{n=\"true\"===(i=n)||\"false\"!==i&&(\"null\"===i?null:i===+i+\"\"?+i:K.test(i)?JSON.parse(i):i)}catch(e){}J.set(e,t,n)}else n=void 0;return n}k.extend({hasData:function(e){return J.hasData(e)||Q.hasData(e)},data:function(e,t,n){return J.access(e,t,n)},removeData:function(e,t){J.remove(e,t)},_data:function(e,t,n){return Q.access(e,t,n)},_removeData:function(e,t){Q.remove(e,t)}}),k.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=J.get(o),1===o.nodeType&&!Q.get(o,\"hasDataAttrs\"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf(\"data-\")&&(r=V(r.slice(5)),ee(o,r,i[r]));Q.set(o,\"hasDataAttrs\",!0)}return i}return\"object\"==typeof n?this.each(function(){J.set(this,n)}):_(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=J.get(o,n))?t:void 0!==(t=ee(o,n))?t:void 0;this.each(function(){J.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){J.remove(this,e)})}}),k.extend({queue:function(e,t,n){var r;if(e)return t=(t||\"fx\")+\"queue\",r=Q.get(e,t),n&&(!r||Array.isArray(n)?r=Q.access(e,t,k.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||\"fx\";var n=k.queue(e,t),r=n.length,i=n.shift(),o=k._queueHooks(e,t);\"inprogress\"===i&&(i=n.shift(),r--),i&&(\"fx\"===t&&n.unshift(\"inprogress\"),delete o.stop,i.call(e,function(){k.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+\"queueHooks\";return Q.get(e,n)||Q.access(e,n,{empty:k.Callbacks(\"once memory\").add(function(){Q.remove(e,[t+\"queue\",n])})})}}),k.fn.extend({queue:function(t,n){var e=2;return\"string\"!=typeof t&&(n=t,t=\"fx\",e--),arguments.length<e?k.queue(this[0],t):void 0===n?this:this.each(function(){var e=k.queue(this,t,n);k._queueHooks(this,t),\"fx\"===t&&\"inprogress\"!==e[0]&&k.dequeue(this,t)})},dequeue:function(e){return this.each(function(){k.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||\"fx\",[])},promise:function(e,t){var n,r=1,i=k.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};\"string\"!=typeof e&&(t=e,e=void 0),e=e||\"fx\";while(a--)(n=Q.get(o[a],e+\"queueHooks\"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var te=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,ne=new RegExp(\"^(?:([+-])=|)(\"+te+\")([a-z%]*)$\",\"i\"),re=[\"Top\",\"Right\",\"Bottom\",\"Left\"],ie=E.documentElement,oe=function(e){return k.contains(e.ownerDocument,e)},ae={composed:!0};ie.getRootNode&&(oe=function(e){return k.contains(e.ownerDocument,e)||e.getRootNode(ae)===e.ownerDocument});var se=function(e,t){return\"none\"===(e=t||e).style.display||\"\"===e.style.display&&oe(e)&&\"none\"===k.css(e,\"display\")},ue=function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];for(o in i=n.apply(e,r||[]),t)e.style[o]=a[o];return i};function le(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return k.css(e,t,\"\")},u=s(),l=n&&n[3]||(k.cssNumber[t]?\"\":\"px\"),c=e.nodeType&&(k.cssNumber[t]||\"px\"!==l&&+u)&&ne.exec(k.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)k.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,k.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ce={};function fe(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?(\"none\"===n&&(l[c]=Q.get(r,\"display\")||null,l[c]||(r.style.display=\"\")),\"\"===r.style.display&&se(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ce[s])||(o=a.body.appendChild(a.createElement(s)),u=k.css(o,\"display\"),o.parentNode.removeChild(o),\"none\"===u&&(u=\"block\"),ce[s]=u)))):\"none\"!==n&&(l[c]=\"none\",Q.set(r,\"display\",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}k.fn.extend({show:function(){return fe(this,!0)},hide:function(){return fe(this)},toggle:function(e){return\"boolean\"==typeof e?e?this.show():this.hide():this.each(function(){se(this)?k(this).show():k(this).hide()})}});var pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i,he=/^$|^module$|\\/(?:java|ecma)script/i,ge={option:[1,\"<select multiple='multiple'>\",\"</select>\"],thead:[1,\"<table>\",\"</table>\"],col:[2,\"<table><colgroup>\",\"</colgroup></table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:[0,\"\",\"\"]};function ve(e,t){var n;return n=\"undefined\"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):\"undefined\"!=typeof e.querySelectorAll?e.querySelectorAll(t||\"*\"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Q.set(e[n],\"globalEval\",!t||Q.get(t[n],\"globalEval\"))}ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;var me,xe,be=/<|&#?\\w+;/;function we(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if(\"object\"===w(o))k.merge(p,o.nodeType?[o]:o);else if(be.test(o)){a=a||f.appendChild(t.createElement(\"div\")),s=(de.exec(o)||[\"\",\"\"])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+k.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;k.merge(p,a.childNodes),(a=f.firstChild).textContent=\"\"}else p.push(t.createTextNode(o));f.textContent=\"\",d=0;while(o=p[d++])if(r&&-1<k.inArray(o,r))i&&i.push(o);else if(l=oe(o),a=ve(f.appendChild(o),\"script\"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||\"\")&&n.push(o)}return f}me=E.createDocumentFragment().appendChild(E.createElement(\"div\")),(xe=E.createElement(\"input\")).setAttribute(\"type\",\"radio\"),xe.setAttribute(\"checked\",\"checked\"),xe.setAttribute(\"name\",\"t\"),me.appendChild(xe),y.checkClone=me.cloneNode(!0).cloneNode(!0).lastChild.checked,me.innerHTML=\"<textarea>x</textarea>\",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==(\"focus\"===t)}function Ae(e,t,n,r,i,o){var a,s;if(\"object\"==typeof t){for(s in\"string\"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&(\"string\"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return\"undefined\"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||\"\").match(R)||[\"\"]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(\".\")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||\"\").match(R)||[\"\"]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&(\"**\"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,\"handle events\")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,\"events\")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t<arguments.length;t++)u[t]=arguments[t];if(s.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,s)){a=k.event.handlers.call(this,s,l),t=0;while((i=a[t++])&&!s.isPropagationStopped()){s.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!s.isImmediatePropagationStopped())s.rnamespace&&!1!==o.namespace&&!s.rnamespace.test(o.namespace)||(s.handleObj=o,s.data=o.data,void 0!==(r=((k.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,u))&&!1===(s.result=r)&&(s.preventDefault(),s.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,s),s.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!(\"click\"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&(\"click\"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+\" \"]&&(a[i]=r.needsContext?-1<k(i,this).index(l):k.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(k.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[k.expando]?e:new k.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,\"input\")&&De(t,\"click\",ke),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,\"input\")&&De(t,\"click\"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,\"input\")&&Q.get(t,\"click\")||A(t,\"a\")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},k.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},k.Event=function(e,t){if(!(this instanceof k.Event))return new k.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?ke:Se,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&k.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[k.expando]=!0},k.Event.prototype={constructor:k.Event,isDefaultPrevented:Se,isPropagationStopped:Se,isImmediatePropagationStopped:Se,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=ke,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=ke,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=ke,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},k.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,\"char\":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&Te.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&Ce.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},k.event.addProp),k.each({focus:\"focusin\",blur:\"focusout\"},function(e,t){k.event.special[e]={setup:function(){return De(this,e,Ne),!1},trigger:function(){return De(this,e),!0},delegateType:t}}),k.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(e,i){k.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||k.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),k.fn.extend({on:function(e,t,n,r){return Ae(this,e,t,n,r)},one:function(e,t,n,r){return Ae(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,k(e.delegateTarget).off(r.namespace?r.origType+\".\"+r.namespace:r.origType,r.selector,r.handler),this;if(\"object\"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&\"function\"!=typeof t||(n=t,t=void 0),!1===n&&(n=Se),this.each(function(){k.event.remove(this,e,n,t)})}});var je=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)[^>]*)\\/>/gi,qe=/<script|<style|<link/i,Le=/checked\\s*(?:[^=]|=\\s*.checked.)/i,He=/^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;function Oe(e,t){return A(e,\"table\")&&A(11!==t.nodeType?t:t.firstChild,\"tr\")&&k(e).children(\"tbody\")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute(\"type\"))+\"/\"+e.type,e}function Re(e){return\"true/\"===(e.type||\"\").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute(\"type\"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n<r;n++)k.event.add(t,i,l[i][n]);J.hasData(e)&&(s=J.access(e),u=k.extend({},s),J.set(t,u))}}function Ie(n,r,i,o){r=g.apply([],r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&\"string\"==typeof d&&!y.checkClone&&Le.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Ie(t,r,i,o)});if(f&&(t=(e=we(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=k.map(ve(e,\"script\"),Pe)).length;c<f;c++)u=e,c!==p&&(u=k.clone(u,!0,!0),s&&k.merge(a,ve(u,\"script\"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,k.map(a,Re),c=0;c<s;c++)u=a[c],he.test(u.type||\"\")&&!Q.access(u,\"globalEval\")&&k.contains(l,u)&&(u.src&&\"module\"!==(u.type||\"\").toLowerCase()?k._evalUrl&&!u.noModule&&k._evalUrl(u.src,{nonce:u.nonce||u.getAttribute(\"nonce\")}):b(u.textContent.replace(He,\"\"),u,l))}return n}function We(e,t,n){for(var r,i=t?k.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||k.cleanData(ve(r)),r.parentNode&&(n&&oe(r)&&ye(ve(r,\"script\")),r.parentNode.removeChild(r));return e}k.extend({htmlPrefilter:function(e){return e.replace(je,\"<$1></$2>\")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,\"input\"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:\"input\"!==l&&\"textarea\"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Me(o[r],a[r]);else Me(e,c);return 0<(a=ve(c,\"script\")).length&&ye(a,!f&&ve(e,\"script\")),c},cleanData:function(e){for(var t,n,r,i=k.event.special,o=0;void 0!==(n=e[o]);o++)if(G(n)){if(t=n[Q.expando]){if(t.events)for(r in t.events)i[r]?k.event.remove(n,r):k.removeEvent(n,r,t.handle);n[Q.expando]=void 0}n[J.expando]&&(n[J.expando]=void 0)}}}),k.fn.extend({detach:function(e){return We(this,e,!0)},remove:function(e){return We(this,e)},text:function(e){return _(this,function(e){return void 0===e?k.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Ie(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Oe(this,e).appendChild(e)})},prepend:function(){return Ie(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Oe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(k.cleanData(ve(e,!1)),e.textContent=\"\");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return k.clone(this,e,t)})},html:function(e){return _(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if(\"string\"==typeof e&&!qe.test(e)&&!ge[(de.exec(e)||[\"\",\"\"])[1].toLowerCase()]){e=k.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(k.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Ie(this,arguments,function(e){var t=this.parentNode;k.inArray(this,n)<0&&(k.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),k.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(e,a){k.fn[e]=function(e){for(var t,n=[],r=k(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),k(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var $e=new RegExp(\"^(\"+te+\")(?!px)[a-z%]+$\",\"i\"),Fe=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},Be=new RegExp(re.join(\"|\"),\"i\");function _e(e,t,n){var r,i,o,a,s=e.style;return(n=n||Fe(e))&&(\"\"!==(a=n.getPropertyValue(t)||n[t])||oe(e)||(a=k.style(e,t)),!y.pixelBoxStyles()&&$e.test(a)&&Be.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+\"\":a}function ze(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(u){s.style.cssText=\"position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0\",u.style.cssText=\"position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%\",ie.appendChild(s).appendChild(u);var e=C.getComputedStyle(u);n=\"1%\"!==e.top,a=12===t(e.marginLeft),u.style.right=\"60%\",o=36===t(e.right),r=36===t(e.width),u.style.position=\"absolute\",i=12===t(u.offsetWidth/3),ie.removeChild(s),u=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s=E.createElement(\"div\"),u=E.createElement(\"div\");u.style&&(u.style.backgroundClip=\"content-box\",u.cloneNode(!0).style.backgroundClip=\"\",y.clearCloneStyle=\"content-box\"===u.style.backgroundClip,k.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),a},scrollboxSize:function(){return e(),i}}))}();var Ue=[\"Webkit\",\"Moz\",\"ms\"],Xe=E.createElement(\"div\").style,Ve={};function Ge(e){var t=k.cssProps[e]||Ve[e];return t||(e in Xe?e:Ve[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Ue.length;while(n--)if((e=Ue[n]+t)in Xe)return e}(e)||e)}var Ye=/^(none|table(?!-c[ea]).+)/,Qe=/^--/,Je={position:\"absolute\",visibility:\"hidden\",display:\"block\"},Ke={letterSpacing:\"0\",fontWeight:\"400\"};function Ze(e,t,n){var r=ne.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||\"px\"):t}function et(e,t,n,r,i,o){var a=\"width\"===t?1:0,s=0,u=0;if(n===(r?\"border\":\"content\"))return 0;for(;a<4;a+=2)\"margin\"===n&&(u+=k.css(e,n+re[a],!0,i)),r?(\"content\"===n&&(u-=k.css(e,\"padding\"+re[a],!0,i)),\"margin\"!==n&&(u-=k.css(e,\"border\"+re[a]+\"Width\",!0,i))):(u+=k.css(e,\"padding\"+re[a],!0,i),\"padding\"!==n?u+=k.css(e,\"border\"+re[a]+\"Width\",!0,i):s+=k.css(e,\"border\"+re[a]+\"Width\",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e[\"offset\"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function tt(e,t,n){var r=Fe(e),i=(!y.boxSizingReliable()||n)&&\"border-box\"===k.css(e,\"boxSizing\",!1,r),o=i,a=_e(e,t,r),s=\"offset\"+t[0].toUpperCase()+t.slice(1);if($e.test(a)){if(!n)return a;a=\"auto\"}return(!y.boxSizingReliable()&&i||\"auto\"===a||!parseFloat(a)&&\"inline\"===k.css(e,\"display\",!1,r))&&e.getClientRects().length&&(i=\"border-box\"===k.css(e,\"boxSizing\",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+et(e,t,n||(i?\"border\":\"content\"),o,r,a)+\"px\"}function nt(e,t,n,r,i){return new nt.prototype.init(e,t,n,r,i)}k.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=_e(e,\"opacity\");return\"\"===n?\"1\":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=V(t),u=Qe.test(t),l=e.style;if(u||(t=Ge(s)),a=k.cssHooks[t]||k.cssHooks[s],void 0===n)return a&&\"get\"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];\"string\"===(o=typeof n)&&(i=ne.exec(n))&&i[1]&&(n=le(e,t,i),o=\"number\"),null!=n&&n==n&&(\"number\"!==o||u||(n+=i&&i[3]||(k.cssNumber[s]?\"\":\"px\")),y.clearCloneStyle||\"\"!==n||0!==t.indexOf(\"background\")||(l[t]=\"inherit\"),a&&\"set\"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=V(t);return Qe.test(t)||(t=Ge(s)),(a=k.cssHooks[t]||k.cssHooks[s])&&\"get\"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=_e(e,t,r)),\"normal\"===i&&t in Ke&&(i=Ke[t]),\"\"===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),k.each([\"height\",\"width\"],function(e,u){k.cssHooks[u]={get:function(e,t,n){if(t)return!Ye.test(k.css(e,\"display\"))||e.getClientRects().length&&e.getBoundingClientRect().width?tt(e,u,n):ue(e,Je,function(){return tt(e,u,n)})},set:function(e,t,n){var r,i=Fe(e),o=!y.scrollboxSize()&&\"absolute\"===i.position,a=(o||n)&&\"border-box\"===k.css(e,\"boxSizing\",!1,i),s=n?et(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e[\"offset\"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-et(e,u,\"border\",!1,i)-.5)),s&&(r=ne.exec(t))&&\"px\"!==(r[3]||\"px\")&&(e.style[u]=t,t=k.css(e,u)),Ze(0,t,s)}}}),k.cssHooks.marginLeft=ze(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(_e(e,\"marginLeft\"))||e.getBoundingClientRect().left-ue(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+\"px\"}),k.each({margin:\"\",padding:\"\",border:\"Width\"},function(i,o){k.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r=\"string\"==typeof e?e.split(\" \"):[e];t<4;t++)n[i+re[t]+o]=r[t]||r[t-2]||r[0];return n}},\"margin\"!==i&&(k.cssHooks[i+o].set=Ze)}),k.fn.extend({css:function(e,t){return _(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Fe(e),i=t.length;a<i;a++)o[t[a]]=k.css(e,t[a],!1,r);return o}return void 0!==n?k.style(e,t,n):k.css(e,t)},e,t,1<arguments.length)}}),((k.Tween=nt).prototype={constructor:nt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||k.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(k.cssNumber[n]?\"\":\"px\")},cur:function(){var e=nt.propHooks[this.prop];return e&&e.get?e.get(this):nt.propHooks._default.get(this)},run:function(e){var t,n=nt.propHooks[this.prop];return this.options.duration?this.pos=t=k.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):nt.propHooks._default.set(this),this}}).init.prototype=nt.prototype,(nt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=k.css(e.elem,e.prop,\"\"))&&\"auto\"!==t?t:0},set:function(e){k.fx.step[e.prop]?k.fx.step[e.prop](e):1!==e.elem.nodeType||!k.cssHooks[e.prop]&&null==e.elem.style[Ge(e.prop)]?e.elem[e.prop]=e.now:k.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=nt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},k.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:\"swing\"},k.fx=nt.prototype.init,k.fx.step={};var rt,it,ot,at,st=/^(?:toggle|show|hide)$/,ut=/queueHooks$/;function lt(){it&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(lt):C.setTimeout(lt,k.fx.interval),k.fx.tick())}function ct(){return C.setTimeout(function(){rt=void 0}),rt=Date.now()}function ft(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i[\"margin\"+(n=re[r])]=i[\"padding\"+n]=e;return t&&(i.opacity=i.width=e),i}function pt(e,t,n){for(var r,i=(dt.tweeners[t]||[]).concat(dt.tweeners[\"*\"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function dt(o,e,t){var n,a,r=0,i=dt.prefilters.length,s=k.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=rt||ct(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:k.extend({},e),opts:k.extend(!0,{specialEasing:{},easing:k.easing._default},t),originalProperties:e,originalOptions:t,startTime:rt||ct(),duration:t.duration,tweens:[],createTween:function(e,t){var n=k.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=V(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=k.cssHooks[r])&&\"expand\"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=dt.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(k._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return k.map(c,pt,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),k.fx.timer(k.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}k.Animation=k.extend(dt,{tweeners:{\"*\":[function(e,t){var n=this.createTween(e,t);return le(n.elem,e,ne.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=[\"*\"]):e=e.match(R);for(var n,r=0,i=e.length;r<i;r++)n=e[r],dt.tweeners[n]=dt.tweeners[n]||[],dt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f=\"width\"in t||\"height\"in t,p=this,d={},h=e.style,g=e.nodeType&&se(e),v=Q.get(e,\"fxshow\");for(r in n.queue||(null==(a=k._queueHooks(e,\"fx\")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,k.queue(e,\"fx\").length||a.empty.fire()})})),t)if(i=t[r],st.test(i)){if(delete t[r],o=o||\"toggle\"===i,i===(g?\"hide\":\"show\")){if(\"show\"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||k.style(e,r)}if((u=!k.isEmptyObject(t))||!k.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Q.get(e,\"display\")),\"none\"===(c=k.css(e,\"display\"))&&(l?c=l:(fe([e],!0),l=e.style.display||l,c=k.css(e,\"display\"),fe([e]))),(\"inline\"===c||\"inline-block\"===c&&null!=l)&&\"none\"===k.css(e,\"float\")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l=\"none\"===c?\"\":c)),h.display=\"inline-block\")),n.overflow&&(h.overflow=\"hidden\",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?\"hidden\"in v&&(g=v.hidden):v=Q.access(e,\"fxshow\",{display:l}),o&&(v.hidden=!g),g&&fe([e],!0),p.done(function(){for(r in g||fe([e]),Q.remove(e,\"fxshow\"),d)k.style(e,r,d[r])})),u=pt(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?dt.prefilters.unshift(e):dt.prefilters.push(e)}}),k.speed=function(e,t,n){var r=e&&\"object\"==typeof e?k.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return k.fx.off?r.duration=0:\"number\"!=typeof r.duration&&(r.duration in k.fx.speeds?r.duration=k.fx.speeds[r.duration]:r.duration=k.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue=\"fx\"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&k.dequeue(this,r.queue)},r},k.fn.extend({fadeTo:function(e,t,n,r){return this.filter(se).css(\"opacity\",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=k.isEmptyObject(t),o=k.speed(e,n,r),a=function(){var e=dt(this,k.extend({},t),o);(i||Q.get(this,\"finish\"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return\"string\"!=typeof i&&(o=e,e=i,i=void 0),e&&!1!==i&&this.queue(i||\"fx\",[]),this.each(function(){var e=!0,t=null!=i&&i+\"queueHooks\",n=k.timers,r=Q.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&ut.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||k.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||\"fx\"),this.each(function(){var e,t=Q.get(this),n=t[a+\"queue\"],r=t[a+\"queueHooks\"],i=k.timers,o=n?n.length:0;for(t.finish=!0,k.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),k.each([\"toggle\",\"show\",\"hide\"],function(e,r){var i=k.fn[r];k.fn[r]=function(e,t,n){return null==e||\"boolean\"==typeof e?i.apply(this,arguments):this.animate(ft(r,!0),e,t,n)}}),k.each({slideDown:ft(\"show\"),slideUp:ft(\"hide\"),slideToggle:ft(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(e,r){k.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),k.timers=[],k.fx.tick=function(){var e,t=0,n=k.timers;for(rt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||k.fx.stop(),rt=void 0},k.fx.timer=function(e){k.timers.push(e),k.fx.start()},k.fx.interval=13,k.fx.start=function(){it||(it=!0,lt())},k.fx.stop=function(){it=null},k.fx.speeds={slow:600,fast:200,_default:400},k.fn.delay=function(r,e){return r=k.fx&&k.fx.speeds[r]||r,e=e||\"fx\",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},ot=E.createElement(\"input\"),at=E.createElement(\"select\").appendChild(E.createElement(\"option\")),ot.type=\"checkbox\",y.checkOn=\"\"!==ot.value,y.optSelected=at.selected,(ot=E.createElement(\"input\")).value=\"t\",ot.type=\"radio\",y.radioValue=\"t\"===ot.value;var ht,gt=k.expr.attrHandle;k.fn.extend({attr:function(e,t){return _(this,k.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){k.removeAttr(this,e)})}}),k.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return\"undefined\"==typeof e.getAttribute?k.prop(e,t,n):(1===o&&k.isXMLDoc(e)||(i=k.attrHooks[t.toLowerCase()]||(k.expr.match.bool.test(t)?ht:void 0)),void 0!==n?null===n?void k.removeAttr(e,t):i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+\"\"),n):i&&\"get\"in i&&null!==(r=i.get(e,t))?r:null==(r=k.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&\"radio\"===t&&A(e,\"input\")){var n=e.value;return e.setAttribute(\"type\",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(R);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),ht={set:function(e,t,n){return!1===t?k.removeAttr(e,n):e.setAttribute(n,n),n}},k.each(k.expr.match.bool.source.match(/\\w+/g),function(e,t){var a=gt[t]||k.find.attr;gt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=gt[o],gt[o]=r,r=null!=a(e,t,n)?o:null,gt[o]=i),r}});var vt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;function mt(e){return(e.match(R)||[]).join(\" \")}function xt(e){return e.getAttribute&&e.getAttribute(\"class\")||\"\"}function bt(e){return Array.isArray(e)?e:\"string\"==typeof e&&e.match(R)||[]}k.fn.extend({prop:function(e,t){return _(this,k.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[k.propFix[e]||e]})}}),k.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&k.isXMLDoc(e)||(t=k.propFix[t]||t,i=k.propHooks[t]),void 0!==n?i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&\"get\"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=k.find.attr(e,\"tabindex\");return t?parseInt(t,10):vt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{\"for\":\"htmlFor\",\"class\":\"className\"}}),y.optSelected||(k.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),k.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){k.propFix[this.toLowerCase()]=this}),k.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).addClass(t.call(this,e,xt(this)))});if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&\" \"+mt(i)+\" \"){a=0;while(o=e[a++])r.indexOf(\" \"+o+\" \")<0&&(r+=o+\" \");i!==(s=mt(r))&&n.setAttribute(\"class\",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).removeClass(t.call(this,e,xt(this)))});if(!arguments.length)return this.attr(\"class\",\"\");if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&\" \"+mt(i)+\" \"){a=0;while(o=e[a++])while(-1<r.indexOf(\" \"+o+\" \"))r=r.replace(\" \"+o+\" \",\" \");i!==(s=mt(r))&&n.setAttribute(\"class\",s)}return this},toggleClass:function(i,t){var o=typeof i,a=\"string\"===o||Array.isArray(i);return\"boolean\"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){k(this).toggleClass(i.call(this,e,xt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=k(this),r=bt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&\"boolean\"!==o||((e=xt(this))&&Q.set(this,\"__className__\",e),this.setAttribute&&this.setAttribute(\"class\",e||!1===i?\"\":Q.get(this,\"__className__\")||\"\"))})},hasClass:function(e){var t,n,r=0;t=\" \"+e+\" \";while(n=this[r++])if(1===n.nodeType&&-1<(\" \"+mt(xt(n))+\" \").indexOf(t))return!0;return!1}});var wt=/\\r/g;k.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,k(this).val()):n)?t=\"\":\"number\"==typeof t?t+=\"\":Array.isArray(t)&&(t=k.map(t,function(e){return null==e?\"\":e+\"\"})),(r=k.valHooks[this.type]||k.valHooks[this.nodeName.toLowerCase()])&&\"set\"in r&&void 0!==r.set(this,t,\"value\")||(this.value=t))})):t?(r=k.valHooks[t.type]||k.valHooks[t.nodeName.toLowerCase()])&&\"get\"in r&&void 0!==(e=r.get(t,\"value\"))?e:\"string\"==typeof(e=t.value)?e.replace(wt,\"\"):null==e?\"\":e:void 0}}),k.extend({valHooks:{option:{get:function(e){var t=k.find.attr(e,\"value\");return null!=t?t:mt(k.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a=\"select-one\"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,\"optgroup\"))){if(t=k(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=k.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<k.inArray(k.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),k.each([\"radio\",\"checkbox\"],function(){k.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<k.inArray(k(e).val(),t)}},y.checkOn||(k.valHooks[this].get=function(e){return null===e.getAttribute(\"value\")?\"on\":e.value})}),y.focusin=\"onfocusin\"in C;var Tt=/^(?:focusinfocus|focusoutblur)$/,Ct=function(e){e.stopPropagation()};k.extend(k.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,\"type\")?e.type:e,h=v.call(e,\"namespace\")?e.namespace.split(\".\"):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!Tt.test(d+k.event.triggered)&&(-1<d.indexOf(\".\")&&(d=(h=d.split(\".\")).shift(),h.sort()),u=d.indexOf(\":\")<0&&\"on\"+d,(e=e[k.expando]?e:new k.Event(d,\"object\"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join(\".\"),e.rnamespace=e.namespace?new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:k.makeArray(t,[e]),c=k.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,Tt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Q.get(o,\"events\")||{})[e.type]&&Q.get(o,\"handle\"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&G(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!G(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),k.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,Ct),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,Ct),k.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=k.extend(new k.Event,n,{type:e,isSimulated:!0});k.event.trigger(r,null,t)}}),k.fn.extend({trigger:function(e,t){return this.each(function(){k.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return k.event.trigger(e,t,n,!0)}}),y.focusin||k.each({focus:\"focusin\",blur:\"focusout\"},function(n,r){var i=function(e){k.event.simulate(r,e.target,k.event.fix(e))};k.event.special[r]={setup:function(){var e=this.ownerDocument||this,t=Q.access(e,r);t||e.addEventListener(n,i,!0),Q.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this,t=Q.access(e,r)-1;t?Q.access(e,r,t):(e.removeEventListener(n,i,!0),Q.remove(e,r))}}});var Et=C.location,kt=Date.now(),St=/\\?/;k.parseXML=function(e){var t;if(!e||\"string\"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,\"text/xml\")}catch(e){t=void 0}return t&&!t.getElementsByTagName(\"parsererror\").length||k.error(\"Invalid XML: \"+e),t};var Nt=/\\[\\]$/,At=/\\r?\\n/g,Dt=/^(?:submit|button|image|reset|file)$/i,jt=/^(?:input|select|textarea|keygen)/i;function qt(n,e,r,i){var t;if(Array.isArray(e))k.each(e,function(e,t){r||Nt.test(n)?i(n,t):qt(n+\"[\"+(\"object\"==typeof t&&null!=t?e:\"\")+\"]\",t,r,i)});else if(r||\"object\"!==w(e))i(n,e);else for(t in e)qt(n+\"[\"+t+\"]\",e[t],r,i)}k.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+\"=\"+encodeURIComponent(null==n?\"\":n)};if(null==e)return\"\";if(Array.isArray(e)||e.jquery&&!k.isPlainObject(e))k.each(e,function(){i(this.name,this.value)});else for(n in e)qt(n,e[n],t,i);return r.join(\"&\")},k.fn.extend({serialize:function(){return k.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=k.prop(this,\"elements\");return e?k.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!k(this).is(\":disabled\")&&jt.test(this.nodeName)&&!Dt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=k(this).val();return null==n?null:Array.isArray(n)?k.map(n,function(e){return{name:t.name,value:e.replace(At,\"\\r\\n\")}}):{name:t.name,value:n.replace(At,\"\\r\\n\")}}).get()}});var Lt=/%20/g,Ht=/#.*$/,Ot=/([?&])_=[^&]*/,Pt=/^(.*?):[ \\t]*([^\\r\\n]*)$/gm,Rt=/^(?:GET|HEAD)$/,Mt=/^\\/\\//,It={},Wt={},$t=\"*/\".concat(\"*\"),Ft=E.createElement(\"a\");function Bt(o){return function(e,t){\"string\"!=typeof e&&(t=e,e=\"*\");var n,r=0,i=e.toLowerCase().match(R)||[];if(m(t))while(n=i[r++])\"+\"===n[0]?(n=n.slice(1)||\"*\",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function _t(t,i,o,a){var s={},u=t===Wt;function l(e){var r;return s[e]=!0,k.each(t[e]||[],function(e,t){var n=t(i,o,a);return\"string\"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s[\"*\"]&&l(\"*\")}function zt(e,t){var n,r,i=k.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&k.extend(!0,e,r),e}Ft.href=Et.href,k.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Et.href,type:\"GET\",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Et.protocol),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":$t,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":JSON.parse,\"text xml\":k.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,k.ajaxSettings),t):zt(k.ajaxSettings,e)},ajaxPrefilter:Bt(It),ajaxTransport:Bt(Wt),ajax:function(e,t){\"object\"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=k.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?k(y):k.event,x=k.Deferred(),b=k.Callbacks(\"once memory\"),w=v.statusCode||{},a={},s={},u=\"canceled\",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Pt.exec(p))n[t[1].toLowerCase()+\" \"]=(n[t[1].toLowerCase()+\" \"]||[]).concat(t[2])}t=n[e.toLowerCase()+\" \"]}return null==t?null:t.join(\", \")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Et.href)+\"\").replace(Mt,Et.protocol+\"//\"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||\"*\").toLowerCase().match(R)||[\"\"],null==v.crossDomain){r=E.createElement(\"a\");try{r.href=v.url,r.href=r.href,v.crossDomain=Ft.protocol+\"//\"+Ft.host!=r.protocol+\"//\"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&\"string\"!=typeof v.data&&(v.data=k.param(v.data,v.traditional)),_t(It,v,t,T),h)return T;for(i in(g=k.event&&v.global)&&0==k.active++&&k.event.trigger(\"ajaxStart\"),v.type=v.type.toUpperCase(),v.hasContent=!Rt.test(v.type),f=v.url.replace(Ht,\"\"),v.hasContent?v.data&&v.processData&&0===(v.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&(v.data=v.data.replace(Lt,\"+\")):(o=v.url.slice(f.length),v.data&&(v.processData||\"string\"==typeof v.data)&&(f+=(St.test(f)?\"&\":\"?\")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Ot,\"$1\"),o=(St.test(f)?\"&\":\"?\")+\"_=\"+kt+++o),v.url=f+o),v.ifModified&&(k.lastModified[f]&&T.setRequestHeader(\"If-Modified-Since\",k.lastModified[f]),k.etag[f]&&T.setRequestHeader(\"If-None-Match\",k.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader(\"Content-Type\",v.contentType),T.setRequestHeader(\"Accept\",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+(\"*\"!==v.dataTypes[0]?\", \"+$t+\"; q=0.01\":\"\"):v.accepts[\"*\"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u=\"abort\",b.add(v.complete),T.done(v.success),T.fail(v.error),c=_t(Wt,v,t,T)){if(T.readyState=1,g&&m.trigger(\"ajaxSend\",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort(\"timeout\")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,\"No Transport\");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||\"\",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while(\"*\"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader(\"Content-Type\"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+\" \"+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if(\"*\"===o)o=u;else if(\"*\"!==u&&u!==o){if(!(a=l[u+\" \"+o]||l[\"* \"+o]))for(i in l)if((s=i.split(\" \"))[1]===o&&(a=l[u+\" \"+s[0]]||l[\"* \"+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e[\"throws\"])t=a(t);else try{t=a(t)}catch(e){return{state:\"parsererror\",error:a?e:\"No conversion from \"+u+\" to \"+o}}}return{state:\"success\",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader(\"Last-Modified\"))&&(k.lastModified[f]=u),(u=T.getResponseHeader(\"etag\"))&&(k.etag[f]=u)),204===e||\"HEAD\"===v.type?l=\"nocontent\":304===e?l=\"notmodified\":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l=\"error\",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+\"\",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?\"ajaxSuccess\":\"ajaxError\",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger(\"ajaxComplete\",[T,v]),--k.active||k.event.trigger(\"ajaxStop\")))}return T},getJSON:function(e,t,n){return k.get(e,t,n,\"json\")},getScript:function(e,t){return k.get(e,void 0,t,\"script\")}}),k.each([\"get\",\"post\"],function(e,i){k[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),k.ajax(k.extend({url:e,type:i,dataType:r,data:t,success:n},k.isPlainObject(e)&&e))}}),k._evalUrl=function(e,t){return k.ajax({url:e,type:\"GET\",dataType:\"script\",cache:!0,async:!1,global:!1,converters:{\"text script\":function(){}},dataFilter:function(e){k.globalEval(e,t)}})},k.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=k(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){k(this).wrapInner(n.call(this,e))}):this.each(function(){var e=k(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){k(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not(\"body\").each(function(){k(this).replaceWith(this.childNodes)}),this}}),k.expr.pseudos.hidden=function(e){return!k.expr.pseudos.visible(e)},k.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},k.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var Ut={0:200,1223:204},Xt=k.ajaxSettings.xhr();y.cors=!!Xt&&\"withCredentials\"in Xt,y.ajax=Xt=!!Xt,k.ajaxTransport(function(i){var o,a;if(y.cors||Xt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e[\"X-Requested-With\"]||(e[\"X-Requested-With\"]=\"XMLHttpRequest\"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,\"abort\"===e?r.abort():\"error\"===e?\"number\"!=typeof r.status?t(0,\"error\"):t(r.status,r.statusText):t(Ut[r.status]||r.status,r.statusText,\"text\"!==(r.responseType||\"text\")||\"string\"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o(\"error\"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o(\"abort\");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),k.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),k.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(e){return k.globalEval(e),e}}}),k.ajaxPrefilter(\"script\",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type=\"GET\")}),k.ajaxTransport(\"script\",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=k(\"<script>\").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on(\"load error\",i=function(e){r.remove(),i=null,e&&t(\"error\"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\\?(?=&|$)|\\?\\?/;k.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var e=Gt.pop()||k.expando+\"_\"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter(\"json jsonp\",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?\"url\":\"string\"==typeof e.data&&0===(e.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&Yt.test(e.data)&&\"data\");if(a||\"jsonp\"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,\"$1\"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?\"&\":\"?\")+e.jsonp+\"=\"+r),e.converters[\"script json\"]=function(){return o||k.error(r+\" was not called\"),o[0]},e.dataTypes[0]=\"json\",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),\"script\"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument(\"\").body).innerHTML=\"<form></form><form></form>\",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return\"string\"!=typeof e?[]:(\"boolean\"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument(\"\")).createElement(\"base\")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(\" \");return-1<s&&(r=mt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&\"object\"==typeof t&&(i=\"POST\"),0<a.length&&k.ajax({url:e,type:i||\"GET\",dataType:\"html\",data:t}).done(function(e){o=arguments,a.html(r?k(\"<div>\").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,\"position\"),c=k(e),f={};\"static\"===l&&(e.style.position=\"relative\"),s=c.offset(),o=k.css(e,\"top\"),u=k.css(e,\"left\"),(\"absolute\"===l||\"fixed\"===l)&&-1<(o+u).indexOf(\"auto\")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),\"using\"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if(\"fixed\"===k.css(r,\"position\"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&\"static\"===k.css(e,\"position\"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,\"borderTopWidth\",!0),i.left+=k.css(e,\"borderLeftWidth\",!0))}return{top:t.top-i.top-k.css(r,\"marginTop\",!0),left:t.left-i.left-k.css(r,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&\"static\"===k.css(e,\"position\"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(t,i){var o=\"pageYOffset\"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each([\"top\",\"left\"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+\"px\":t})}),k.each({Height:\"height\",Width:\"width\"},function(a,s){k.each({padding:\"inner\"+a,content:s,\"\":\"outer\"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||\"boolean\"!=typeof e),i=r||(!0===e||!0===t?\"margin\":\"border\");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf(\"outer\")?e[\"inner\"+a]:e.document.documentElement[\"client\"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body[\"scroll\"+a],r[\"scroll\"+a],e.body[\"offset\"+a],r[\"offset\"+a],r[\"client\"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each(\"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu\".split(\" \"),function(e,n){k.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}}),k.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),k.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)}}),k.proxy=function(e,t){var n,r,i;if(\"string\"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||k.guid++,i},k.holdReady=function(e){e?k.readyWait++:k.ready(!0)},k.isArray=Array.isArray,k.parseJSON=JSON.parse,k.nodeName=A,k.isFunction=m,k.isWindow=x,k.camelCase=V,k.type=w,k.now=Date.now,k.isNumeric=function(e){var t=k.type(e);return(\"number\"===t||\"string\"===t)&&!isNaN(e-parseFloat(e))},\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return k});var Qt=C.jQuery,Jt=C.$;return k.noConflict=function(e){return C.$===k&&(C.$=Jt),e&&C.jQuery===k&&(C.jQuery=Qt),k},e||(C.jQuery=C.$=k),k});\n/*\n * jQuery throttle / debounce - v1.1 - 3/7/2010\n * http://benalman.com/projects/jquery-throttle-debounce-plugin/\n * \n * Copyright (c) 2010 \"Cowboy\" Ben Alman\n * Dual licensed under the MIT and GPL licenses.\n * http://benalman.com/about/license/\n */\n(function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!==\"boolean\"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this);\n/*!\n * imagesLoaded PACKAGED v4.1.0\n * JavaScript is all like \"You images are done yet or what?\"\n * MIT License\n */\n!function(t,e){\"function\"==typeof define&&define.amd?define(\"ev-emitter/ev-emitter\",e):\"object\"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}(this,function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var i=this._events=this._events||{},n=i[t]=i[t]||[];return-1==n.indexOf(e)&&n.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var i=this._onceEvents=this._onceEvents||{},n=i[t]=i[t]||[];return n[e]=!0,this}},e.off=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=i.indexOf(e);return-1!=n&&i.splice(n,1),this}},e.emitEvent=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=0,o=i[n];e=e||[];for(var r=this._onceEvents&&this._onceEvents[t];o;){var s=r&&r[o];s&&(this.off(t,o),delete r[o]),o.apply(this,e),n+=s?0:1,o=i[n]}return this}},t}),function(t,e){\"use strict\";\"function\"==typeof define&&define.amd?define([\"ev-emitter/ev-emitter\"],function(i){return e(t,i)}):\"object\"==typeof module&&module.exports?module.exports=e(t,require(\"ev-emitter\")):t.imagesLoaded=e(t,t.EvEmitter)}(window,function(t,e){function i(t,e){for(var i in e)t[i]=e[i];return t}function n(t){var e=[];if(Array.isArray(t))e=t;else if(\"number\"==typeof t.length)for(var i=0;i<t.length;i++)e.push(t[i]);else e.push(t);return e}function o(t,e,r){return this instanceof o?(\"string\"==typeof t&&(t=document.querySelectorAll(t)),this.elements=n(t),this.options=i({},this.options),\"function\"==typeof e?r=e:i(this.options,e),r&&this.on(\"always\",r),this.getImages(),h&&(this.jqDeferred=new h.Deferred),void setTimeout(function(){this.check()}.bind(this))):new o(t,e,r)}function r(t){this.img=t}function s(t,e){this.url=t,this.element=e,this.img=new Image}var h=t.jQuery,a=t.console;o.prototype=Object.create(e.prototype),o.prototype.options={},o.prototype.getImages=function(){this.images=[],this.elements.forEach(this.addElementImages,this)},o.prototype.addElementImages=function(t){\"IMG\"==t.nodeName&&this.addImage(t),this.options.background===!0&&this.addElementBackgroundImages(t);var e=t.nodeType;if(e&&d[e]){for(var i=t.querySelectorAll(\"img\"),n=0;n<i.length;n++){var o=i[n];this.addImage(o)}if(\"string\"==typeof this.options.background){var r=t.querySelectorAll(this.options.background);for(n=0;n<r.length;n++){var s=r[n];this.addElementBackgroundImages(s)}}}};var d={1:!0,9:!0,11:!0};return o.prototype.addElementBackgroundImages=function(t){var e=getComputedStyle(t);if(e)for(var i=/url\\((['\"])?(.*?)\\1\\)/gi,n=i.exec(e.backgroundImage);null!==n;){var o=n&&n[2];o&&this.addBackground(o,t),n=i.exec(e.backgroundImage)}},o.prototype.addImage=function(t){var e=new r(t);this.images.push(e)},o.prototype.addBackground=function(t,e){var i=new s(t,e);this.images.push(i)},o.prototype.check=function(){function t(t,i,n){setTimeout(function(){e.progress(t,i,n)})}var e=this;return this.progressedCount=0,this.hasAnyBroken=!1,this.images.length?void this.images.forEach(function(e){e.once(\"progress\",t),e.check()}):void this.complete()},o.prototype.progress=function(t,e,i){this.progressedCount++,this.hasAnyBroken=this.hasAnyBroken||!t.isLoaded,this.emitEvent(\"progress\",[this,t,e]),this.jqDeferred&&this.jqDeferred.notify&&this.jqDeferred.notify(this,t),this.progressedCount==this.images.length&&this.complete(),this.options.debug&&a&&a.log(\"progress: \"+i,t,e)},o.prototype.complete=function(){var t=this.hasAnyBroken?\"fail\":\"done\";if(this.isComplete=!0,this.emitEvent(t,[this]),this.emitEvent(\"always\",[this]),this.jqDeferred){var e=this.hasAnyBroken?\"reject\":\"resolve\";this.jqDeferred[e](this)}},r.prototype=Object.create(e.prototype),r.prototype.check=function(){var t=this.getIsImageComplete();return t?void this.confirm(0!==this.img.naturalWidth,\"naturalWidth\"):(this.proxyImage=new Image,this.proxyImage.addEventListener(\"load\",this),this.proxyImage.addEventListener(\"error\",this),this.img.addEventListener(\"load\",this),this.img.addEventListener(\"error\",this),void(this.proxyImage.src=this.img.src))},r.prototype.getIsImageComplete=function(){return this.img.complete&&void 0!==this.img.naturalWidth},r.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent(\"progress\",[this,this.img,e])},r.prototype.handleEvent=function(t){var e=\"on\"+t.type;this[e]&&this[e](t)},r.prototype.onload=function(){this.confirm(!0,\"onload\"),this.unbindEvents()},r.prototype.onerror=function(){this.confirm(!1,\"onerror\"),this.unbindEvents()},r.prototype.unbindEvents=function(){this.proxyImage.removeEventListener(\"load\",this),this.proxyImage.removeEventListener(\"error\",this),this.img.removeEventListener(\"load\",this),this.img.removeEventListener(\"error\",this)},s.prototype=Object.create(r.prototype),s.prototype.check=function(){this.img.addEventListener(\"load\",this),this.img.addEventListener(\"error\",this),this.img.src=this.url;var t=this.getIsImageComplete();t&&(this.confirm(0!==this.img.naturalWidth,\"naturalWidth\"),this.unbindEvents())},s.prototype.unbindEvents=function(){this.img.removeEventListener(\"load\",this),this.img.removeEventListener(\"error\",this)},s.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent(\"progress\",[this,this.element,e])},o.makeJQueryPlugin=function(e){e=e||t.jQuery,e&&(h=e,h.fn.imagesLoaded=function(t,e){var i=new o(this,t,e);return i.jqDeferred.promise(h(this))})},o.makeJQueryPlugin(),o});\n/*! lz-string-1.3.3-min.js | (c) 2013 Pieroxy | Licensed under a WTFPL license */\nvar LZString={_keyStr:\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\",_f:String.fromCharCode,compressToBase64:function(e){if(e==null)return\"\";var t=\"\";var n,r,i,s,o,u,a;var f=0;e=LZString.compress(e);while(f<e.length*2){if(f%2==0){n=e.charCodeAt(f/2)>>8;r=e.charCodeAt(f/2)&255;if(f/2+1<e.length)i=e.charCodeAt(f/2+1)>>8;else i=NaN}else{n=e.charCodeAt((f-1)/2)&255;if((f+1)/2<e.length){r=e.charCodeAt((f+1)/2)>>8;i=e.charCodeAt((f+1)/2)&255}else r=i=NaN}f+=3;s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+LZString._keyStr.charAt(s)+LZString._keyStr.charAt(o)+LZString._keyStr.charAt(u)+LZString._keyStr.charAt(a)}return t},decompressFromBase64:function(e){if(e==null)return\"\";var t=\"\",n=0,r,i,s,o,u,a,f,l,c=0,h=LZString._f;e=e.replace(/[^A-Za-z0-9\\+\\/\\=]/g,\"\");while(c<e.length){u=LZString._keyStr.indexOf(e.charAt(c++));a=LZString._keyStr.indexOf(e.charAt(c++));f=LZString._keyStr.indexOf(e.charAt(c++));l=LZString._keyStr.indexOf(e.charAt(c++));i=u<<2|a>>4;s=(a&15)<<4|f>>2;o=(f&3)<<6|l;if(n%2==0){r=i<<8;if(f!=64){t+=h(r|s)}if(l!=64){r=o<<8}}else{t=t+h(r|i);if(f!=64){r=s<<8}if(l!=64){t+=h(r|o)}}n+=3}return LZString.decompress(t)},compressToUTF16:function(e){if(e==null)return\"\";var t=\"\",n,r,i,s=0,o=LZString._f;e=LZString.compress(e);for(n=0;n<e.length;n++){r=e.charCodeAt(n);switch(s++){case 0:t+=o((r>>1)+32);i=(r&1)<<14;break;case 1:t+=o(i+(r>>2)+32);i=(r&3)<<13;break;case 2:t+=o(i+(r>>3)+32);i=(r&7)<<12;break;case 3:t+=o(i+(r>>4)+32);i=(r&15)<<11;break;case 4:t+=o(i+(r>>5)+32);i=(r&31)<<10;break;case 5:t+=o(i+(r>>6)+32);i=(r&63)<<9;break;case 6:t+=o(i+(r>>7)+32);i=(r&127)<<8;break;case 7:t+=o(i+(r>>8)+32);i=(r&255)<<7;break;case 8:t+=o(i+(r>>9)+32);i=(r&511)<<6;break;case 9:t+=o(i+(r>>10)+32);i=(r&1023)<<5;break;case 10:t+=o(i+(r>>11)+32);i=(r&2047)<<4;break;case 11:t+=o(i+(r>>12)+32);i=(r&4095)<<3;break;case 12:t+=o(i+(r>>13)+32);i=(r&8191)<<2;break;case 13:t+=o(i+(r>>14)+32);i=(r&16383)<<1;break;case 14:t+=o(i+(r>>15)+32,(r&32767)+32);s=0;break}}return t+o(i+32)},decompressFromUTF16:function(e){if(e==null)return\"\";var t=\"\",n,r,i=0,s=0,o=LZString._f;while(s<e.length){r=e.charCodeAt(s)-32;switch(i++){case 0:n=r<<1;break;case 1:t+=o(n|r>>14);n=(r&16383)<<2;break;case 2:t+=o(n|r>>13);n=(r&8191)<<3;break;case 3:t+=o(n|r>>12);n=(r&4095)<<4;break;case 4:t+=o(n|r>>11);n=(r&2047)<<5;break;case 5:t+=o(n|r>>10);n=(r&1023)<<6;break;case 6:t+=o(n|r>>9);n=(r&511)<<7;break;case 7:t+=o(n|r>>8);n=(r&255)<<8;break;case 8:t+=o(n|r>>7);n=(r&127)<<9;break;case 9:t+=o(n|r>>6);n=(r&63)<<10;break;case 10:t+=o(n|r>>5);n=(r&31)<<11;break;case 11:t+=o(n|r>>4);n=(r&15)<<12;break;case 12:t+=o(n|r>>3);n=(r&7)<<13;break;case 13:t+=o(n|r>>2);n=(r&3)<<14;break;case 14:t+=o(n|r>>1);n=(r&1)<<15;break;case 15:t+=o(n|r);i=0;break}s++}return LZString.decompress(t)},compress:function(e){if(e==null)return\"\";var t,n,r={},i={},s=\"\",o=\"\",u=\"\",a=2,f=3,l=2,c=\"\",h=0,p=0,d,v=LZString._f;for(d=0;d<e.length;d+=1){s=e.charAt(d);if(!Object.prototype.hasOwnProperty.call(r,s)){r[s]=f++;i[s]=true}o=u+s;if(Object.prototype.hasOwnProperty.call(r,o)){u=o}else{if(Object.prototype.hasOwnProperty.call(i,u)){if(u.charCodeAt(0)<256){for(t=0;t<l;t++){h=h<<1;if(p==15){p=0;c+=v(h);h=0}else{p++}}n=u.charCodeAt(0);for(t=0;t<8;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}else{n=1;for(t=0;t<l;t++){h=h<<1|n;if(p==15){p=0;c+=v(h);h=0}else{p++}n=0}n=u.charCodeAt(0);for(t=0;t<16;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}delete i[u]}else{n=r[u];for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}r[o]=f++;u=String(s)}}if(u!==\"\"){if(Object.prototype.hasOwnProperty.call(i,u)){if(u.charCodeAt(0)<256){for(t=0;t<l;t++){h=h<<1;if(p==15){p=0;c+=v(h);h=0}else{p++}}n=u.charCodeAt(0);for(t=0;t<8;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}else{n=1;for(t=0;t<l;t++){h=h<<1|n;if(p==15){p=0;c+=v(h);h=0}else{p++}n=0}n=u.charCodeAt(0);for(t=0;t<16;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}delete i[u]}else{n=r[u];for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}}n=2;for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}while(true){h=h<<1;if(p==15){c+=v(h);break}else p++}return c},decompress:function(e){if(e==null)return\"\";if(e==\"\")return null;var t=[],n,r=4,i=4,s=3,o=\"\",u=\"\",a,f,l,c,h,p,d,v=LZString._f,m={string:e,val:e.charCodeAt(0),position:32768,index:1};for(a=0;a<3;a+=1){t[a]=a}l=0;h=Math.pow(2,2);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}switch(n=l){case 0:l=0;h=Math.pow(2,8);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}d=v(l);break;case 1:l=0;h=Math.pow(2,16);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}d=v(l);break;case 2:return\"\"}t[3]=d;f=u=d;while(true){if(m.index>m.string.length){return\"\"}l=0;h=Math.pow(2,s);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}switch(d=l){case 0:l=0;h=Math.pow(2,8);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}t[i++]=v(l);d=i-1;r--;break;case 1:l=0;h=Math.pow(2,16);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}t[i++]=v(l);d=i-1;r--;break;case 2:return u}if(r==0){r=Math.pow(2,s);s++}if(t[d]){o=t[d]}else{if(d===i){o=f+f.charAt(0)}else{return null}}u+=o;t[i++]=f+o.charAt(0);r--;f=o;if(r==0){r=Math.pow(2,s);s++}}}};if(typeof module!==\"undefined\"&&module!=null){module.exports=LZString}\n/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */\nvar saveAs=saveAs||navigator.msSaveBlob&&navigator.msSaveBlob.bind(navigator)||function(e){\"use strict\";var t=e.document,n=function(){return e.URL||e.webkitURL||e},r=e.URL||e.webkitURL||e,i=t.createElementNS(\"http://www.w3.org/1999/xhtml\",\"a\"),s=\"download\"in i,o=function(n){var r=t.createEvent(\"MouseEvents\");r.initMouseEvent(\"click\",true,false,e,0,0,0,0,0,false,false,false,false,0,null);n.dispatchEvent(r)},u=e.webkitRequestFileSystem,a=e.requestFileSystem||u||e.mozRequestFileSystem,f=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},l=\"application/octet-stream\",c=0,h=[],p=function(){var e=h.length;while(e--){var t=h[e];if(typeof t===\"string\"){r.revokeObjectURL(t)}else{t.remove()}}h.length=0},d=function(e,t,n){t=[].concat(t);var r=t.length;while(r--){var i=e[\"on\"+t[r]];if(typeof i===\"function\"){try{i.call(e,n||e)}catch(s){f(s)}}}},v=function(t,r){var f=this,p=t.type,v=false,m,g,y=function(){var e=n().createObjectURL(t);h.push(e);return e},b=function(){d(f,\"writestart progress write writeend\".split(\" \"))},w=function(){if(v||!m){m=y(t)}if(g){g.location.href=m}else{window.open(m,\"_blank\")}f.readyState=f.DONE;b()},E=function(e){return function(){if(f.readyState!==f.DONE){return e.apply(this,arguments)}}},S={create:true,exclusive:false},x;f.readyState=f.INIT;if(!r){r=\"download\"}if(s){m=y(t);i.href=m;i.download=r;o(i);f.readyState=f.DONE;b();return}if(e.chrome&&p&&p!==l){x=t.slice||t.webkitSlice;t=x.call(t,0,t.size,l);v=true}if(u&&r!==\"download\"){r+=\".download\"}if(p===l||u){g=e}if(!a){w();return}c+=t.size;a(e.TEMPORARY,c,E(function(e){e.root.getDirectory(\"saved\",S,E(function(e){var n=function(){e.getFile(r,S,E(function(e){e.createWriter(E(function(n){n.onwriteend=function(t){g.location.href=e.toURL();h.push(e);f.readyState=f.DONE;d(f,\"writeend\",t)};n.onerror=function(){var e=n.error;if(e.code!==e.ABORT_ERR){w()}};\"writestart progress write abort\".split(\" \").forEach(function(e){n[\"on\"+e]=f[\"on\"+e]});n.write(t);f.abort=function(){n.abort();f.readyState=f.DONE};f.readyState=f.WRITING}),w)}),w)};e.getFile(r,{create:false},E(function(e){e.remove();n()}),E(function(e){if(e.code===e.NOT_FOUND_ERR){n()}else{w()}}))}),w)}),w)},m=v.prototype,g=function(e,t){return new v(e,t)};m.abort=function(){var e=this;e.readyState=e.DONE;d(e,\"abort\")};m.readyState=m.INIT=0;m.WRITING=1;m.DONE=2;m.error=m.onwritestart=m.onprogress=m.onwrite=m.onabort=m.onerror=m.onwriteend=null;e.addEventListener(\"unload\",p,false);return g}(self)\n/*! seedrandom.js v2.3.3 | (c) 2013 David Bau, all rights reserved. | Licensed under a BSD-style license */\n!function(a,b,c,d,e,f,g,h,i){function j(a){var b,c=a.length,e=this,f=0,g=e.i=e.j=0,h=e.S=[];for(c||(a=[c++]);d>f;)h[f]=f++;for(f=0;d>f;f++)h[f]=h[g=r&g+a[f%c]+(b=h[f])],h[g]=b;(e.g=function(a){for(var b,c=0,f=e.i,g=e.j,h=e.S;a--;)b=h[f=r&f+1],c=c*d+h[r&(h[f]=h[g=r&g+b])+(h[g]=b)];return e.i=f,e.j=g,c})(d)}function k(a,b){var c,d=[],e=typeof a;if(b&&\"object\"==e)for(c in a)try{d.push(k(a[c],b-1))}catch(f){}return d.length?d:\"string\"==e?a:a+\"\\0\"}function l(a,b){for(var c,d=a+\"\",e=0;e<d.length;)b[r&e]=r&(c^=19*b[r&e])+d.charCodeAt(e++);return n(b)}function m(c){try{return a.crypto.getRandomValues(c=new Uint8Array(d)),n(c)}catch(e){return[+new Date,a,(c=a.navigator)&&c.plugins,a.screen,n(b)]}}function n(a){return String.fromCharCode.apply(0,a)}var o=c.pow(d,e),p=c.pow(2,f),q=2*p,r=d-1,s=c[\"seed\"+i]=function(a,f,g){var h=[],r=l(k(f?[a,n(b)]:null==a?m():a,3),h),s=new j(h);return l(n(s.S),b),(g||function(a,b,d){return d?(c[i]=a,b):a})(function(){for(var a=s.g(e),b=o,c=0;p>a;)a=(a+c)*d,b*=d,c=s.g(1);for(;a>=q;)a/=2,b/=2,c>>>=1;return(a+c)/b},r,this==c)};l(c[i](),b),g&&g.exports?g.exports=s:h&&h.amd&&h(function(){return s})}(this,[],Math,256,6,52,\"object\"==typeof module&&module,\"function\"==typeof define&&define,\"random\");\n/*! console_hack.js | (c) 2015 Thomas Michael Edwards | Licensed under SugarCube's Simple BSD license */\n!function(){for(var methods=[\"assert\",\"clear\",\"count\",\"debug\",\"dir\",\"dirxml\",\"error\",\"exception\",\"group\",\"groupCollapsed\",\"groupEnd\",\"info\",\"log\",\"markTimeline\",\"profile\",\"profileEnd\",\"table\",\"time\",\"timeEnd\",\"timeline\",\"timelineEnd\",\"timeStamp\",\"trace\",\"warn\"],length=methods.length,noop=function(){},console=window.console=window.console||{};length--;){var method=methods[length];console[method]||(console[method]=noop)}}();\n}else{document.documentElement.setAttribute(\"data-init\", \"lacking\");}\n</script>\n<style id=\"style-normalize\" type=\"text/css\">/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\n\n/**\n * 1. Set default font family to sans-serif.\n * 2. Prevent iOS and IE text size adjust after device orientation change,\n *    without disabling user zoom.\n */\n\nhtml {\n  font-family: sans-serif; /* 1 */\n  -ms-text-size-adjust: 100%; /* 2 */\n  -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/**\n * Remove default margin.\n */\n\nbody {\n  margin: 0;\n}\n\n/* HTML5 display definitions\n   ========================================================================== */\n\n/**\n * Correct `block` display not defined for any HTML5 element in IE 8/9.\n * Correct `block` display not defined for `details` or `summary` in IE 10/11\n * and Firefox.\n * Correct `block` display not defined for `main` in IE 11.\n */\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\n\n/**\n * 1. Correct `inline-block` display not defined in IE 8/9.\n * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n */\n\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block; /* 1 */\n  vertical-align: baseline; /* 2 */\n}\n\n/**\n * Prevent modern browsers from displaying `audio` without controls.\n * Remove excess height in iOS 5 devices.\n */\n\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n\n/**\n * Address `[hidden]` styling not present in IE 8/9/10.\n * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.\n */\n\n[hidden],\ntemplate {\n  display: none;\n}\n\n/* Links\n   ========================================================================== */\n\n/**\n * Remove the gray background color from active links in IE 10.\n */\n\na {\n  background-color: transparent;\n}\n\n/**\n * Improve readability of focused elements when they are also in an\n * active/hover state.\n */\n\na:active,\na:hover {\n  outline: 0;\n}\n\n/* Text-level semantics\n   ========================================================================== */\n\n/**\n * Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n */\n\nabbr[title] {\n  border-bottom: 1px dotted;\n}\n\n/**\n * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n */\n\nb,\nstrong {\n  font-weight: bold;\n}\n\n/**\n * Address styling not present in Safari and Chrome.\n */\n\ndfn {\n  font-style: italic;\n}\n\n/**\n * Address variable `h1` font-size and margin within `section` and `article`\n * contexts in Firefox 4+, Safari, and Chrome.\n */\n\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\n/**\n * Address styling not present in IE 8/9.\n */\n\nmark {\n  background: #ff0;\n  color: #000;\n}\n\n/**\n * Address inconsistent and variable font size in all browsers.\n */\n\nsmall {\n  font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` affecting `line-height` in all browsers.\n */\n\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\n/* Embedded content\n   ========================================================================== */\n\n/**\n * Remove border when inside `a` element in IE 8/9/10.\n */\n\nimg {\n  border: 0;\n}\n\n/**\n * Correct overflow not hidden in IE 9/10/11.\n */\n\nsvg:not(:root) {\n  overflow: hidden;\n}\n\n/* Grouping content\n   ========================================================================== */\n\n/**\n * Address margin not present in IE 8/9 and Safari.\n */\n\nfigure {\n  margin: 1em 40px;\n}\n\n/**\n * Address differences between Firefox and other browsers.\n */\n\nhr {\n  box-sizing: content-box;\n  height: 0;\n}\n\n/**\n * Contain overflow in all browsers.\n */\n\npre {\n  overflow: auto;\n}\n\n/**\n * Address odd `em`-unit font size rendering in all browsers.\n */\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\n\n/* Forms\n   ========================================================================== */\n\n/**\n * Known limitation: by default, Chrome and Safari on OS X allow very limited\n * styling of `select`, unless a `border` property is set.\n */\n\n/**\n * 1. Correct color not being inherited.\n *    Known issue: affects color of disabled elements.\n * 2. Correct font properties not being inherited.\n * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit; /* 1 */\n  font: inherit; /* 2 */\n  margin: 0; /* 3 */\n}\n\n/**\n * Address `overflow` set to `hidden` in IE 8/9/10/11.\n */\n\nbutton {\n  overflow: visible;\n}\n\n/**\n * Address inconsistent `text-transform` inheritance for `button` and `select`.\n * All other form control elements do not inherit `text-transform` values.\n * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n * Correct `select` style inheritance in Firefox.\n */\n\nbutton,\nselect {\n  text-transform: none;\n}\n\n/**\n * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n *    and `video` controls.\n * 2. Correct inability to style clickable `input` types in iOS.\n * 3. Improve usability and consistency of cursor style between image-type\n *    `input` and others.\n */\n\nbutton,\nhtml input[type=\"button\"], /* 1 */\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button; /* 2 */\n  cursor: pointer; /* 3 */\n}\n\n/**\n * Re-set default cursor for disabled elements.\n */\n\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\n\n/**\n * Remove inner padding and border in Firefox 4+.\n */\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\n\n/**\n * Address Firefox 4+ setting `line-height` on `input` using `!important` in\n * the UA stylesheet.\n */\n\ninput {\n  line-height: normal;\n}\n\n/**\n * It's recommended that you don't attempt to style these elements.\n * Firefox's implementation doesn't respect box-sizing, padding, or width.\n *\n * 1. Address box sizing set to `content-box` in IE 8/9/10.\n * 2. Remove excess padding in IE 8/9/10.\n */\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Fix the cursor style for Chrome's increment/decrement buttons. For certain\n * `font-size` values of the `input`, it causes the cursor style of the\n * decrement button to change from `default` to `text`.\n */\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\n/**\n * 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.\n */\n\ninput[type=\"search\"] {\n  -webkit-appearance: textfield; /* 1 */\n  box-sizing: content-box; /* 2 */\n}\n\n/**\n * Remove inner padding and search cancel button in Safari and Chrome on OS X.\n * Safari (but not Chrome) clips the cancel button when the search input has\n * padding (and `textfield` appearance).\n */\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n/**\n * Define consistent border, margin, and padding.\n */\n\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\n\n/**\n * 1. Correct `color` not being inherited in IE 8/9/10/11.\n * 2. Remove padding so people aren't caught out if they zero out fieldsets.\n */\n\nlegend {\n  border: 0; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Remove default vertical scrollbar in IE 8/9/10/11.\n */\n\ntextarea {\n  overflow: auto;\n}\n\n/**\n * Don't inherit the `font-weight` (applied by a rule above).\n * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n */\n\noptgroup {\n  font-weight: bold;\n}\n\n/* Tables\n   ========================================================================== */\n\n/**\n * Remove most spacing between table cells.\n */\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\ntd,\nth {\n  padding: 0;\n}\n</style>\n<style id=\"style-init-screen\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/init-screen.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n@-webkit-keyframes init-loading-spin {\n\t0%   { -webkit-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); }\n}\n\n@-o-keyframes init-loading-spin {\n\t0%   { -o-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -o-transform: rotate(360deg); transform: rotate(360deg); }\n}\n\n@keyframes init-loading-spin {\n\t0%   { -webkit-transform: rotate(0deg); -o-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -webkit-transform: rotate(360deg); -o-transform: rotate(360deg); transform: rotate(360deg); }\n}\n#init-screen {\n\tdisplay: none;\n\tz-index: 500000;\n\tposition: fixed;\n\ttop: 0px;\n\tleft: 0px;\n\theight: 100%;\n\twidth: 100%;\n\tfont: 28px/1 Helmet, Freesans, sans-serif;\n\tfont-weight: bold;\n\tcolor: #eee;\n\tbackground-color: #111;\n\ttext-align: center;\n}\n#init-screen > div {\n\tdisplay: none;\n\tposition: relative;\n\tmargin: 0 auto;\n\tmax-width: 1136px;\n\ttop: 25%;\n}\nhtml[data-init=\"no-js\"] #init-screen, html[data-init=\"lacking\"] #init-screen, html[data-init=\"loading\"] #init-screen {\n\tdisplay: block;\n}\nhtml[data-init=\"no-js\"] #init-no-js, html[data-init=\"lacking\"] #init-lacking {\n\tdisplay: block;\n\tpadding: 0 1em;\n}\nhtml[data-init=\"no-js\"] #init-no-js {\n\tcolor: red;\n}\nhtml[data-init=\"loading\"] #init-loading {\n\tdisplay: block;\n\tborder: 24px solid transparent;\n\tborder-radius: 50%;\n\tborder-top-color: #7f7f7f;\n\tborder-bottom-color: #7f7f7f;\n\twidth: 100px;\n\theight: 100px;\n\t-webkit-animation: init-loading-spin 2s linear infinite;\n\t     -o-animation: init-loading-spin 2s linear infinite;\n\t        animation: init-loading-spin 2s linear infinite;\n}\nhtml[data-init=\"loading\"] #init-loading > div {\n\ttext-indent: 9999em;\n\toverflow: hidden;\n\twhite-space: nowrap;\n}\nhtml[data-init=\"loading\"] #ui-bar, html[data-init=\"loading\"] #passages {\n\tdisplay: none;\n}\n</style>\n<style id=\"style-font\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/font.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n@font-face {\n\t/*\n\t\ttme-fa-icons (2020-03-27)\n\n\t\t`tme-fa-icons` is a subset of the Font Awesome font v4.7.0 by Dave Gandy (http://fontawesome.com)\n\t\tand is licensed under the SIL OFL 1.1 (http://scripts.sil.org/OFL).\n\t*/\n\tfont-family: \"tme-fa-icons\";\n\tsrc: url('data:application/octet-stream;base64,d09GRgABAAAAADLAAA8AAAAAWHgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABWAAAADsAAABUIIslek9TLzIAAAGUAAAAQwAAAFY+IEkIY21hcAAAAdgAAAG8AAAF3rob9jFjdnQgAAADlAAAABMAAAAgBtX/BGZwZ20AAAOoAAAFkAAAC3CKkZBZZ2FzcAAACTgAAAAIAAAACAAAABBnbHlmAAAJQAAAI6gAADv+gJOpzGhlYWQAACzoAAAAMwAAADYY1IZaaGhlYQAALRwAAAAgAAAAJAfCBClobXR4AAAtPAAAAJEAAAFMBfb/0WxvY2EAAC3QAAAAqAAAAKhjiHI5bWF4cAAALngAAAAgAAAAIAFjDA9uYW1lAAAumAAAAY0AAAL94+zEpHBvc3QAADAoAAACHAAAA11cG/YjcHJlcAAAMkQAAAB6AAAAhuVBK7x4nGNgZGBg4GIwYLBjYHJx8wlh4MtJLMljkGJgYYAAkDwymzEnMz2RgQPGA8qxgGkOIGaDiAIAJjsFSAB4nGNgZNZgnMDAysDAVMW0h4GBoQdCMz5gMGRkAooysDIzYAUBaa4pDA4vGF4EMgf9z2KIYg5imAYUZgTJAQDSIQumAHic7dTVbltRAETR7dpNCikzQ8rMzMxt/M39mHnsU1/TfZz5jFpaV7pXJunMDLAZmOqaZjD5y4Tx+uPTyeL5lG2L5zN+L94zG8+ztr7ulXH1fra4bvK9M79xiWW2sNXPbWeFHexkF7vZw172sZ8DHOQQhznCUY5xnBOc5BSnOcNZVjnHeS5wkUtc5gpX/f3r3OAmt7jNHe5yj/s84CGPeMwTnvKM57zgJa94zRve8o73fOAjn/jMF77yje/84Ce/WGPun1zi/2tlXKbp3Xyc44bFyZanSWokJDXOOjXSk/LUSXn+pEwCKTNBaqQqZU5IjX+XMjukTBEp80TKZJEyY6RMGylzR8oEkjKLpEwlKfNJyqSSMrOkTC8pc0zKRJMy26RMOSnzTsrkk7IDpGwDKXtByoaQsiukbA0p+0PKJpGyU6RsFyl7RmosQcrukbKFpOwjKZtJyo6Ssq2k7C0pG0zKLpOy1aTsNymbTsrOk7L9pNwBUi4CKbeBlCtByr0g5XKQckNIuSak3BVSLgwpt4aUq0PK/SHlEpFyk0i5TqTcKVIuFim3i5QrRso9I+WykXLjXOYNzP8BuAPUwHicY2BAAxIQyBz0PwuEARJsA90AeJytVml300YUHXlJnIQsJQstamHExGmwRiZswYAJQbJjIF2crZWgixQ76b7xid/gX/Nk2nPoN35a7xsvJJC053Cak6N3583VzNtlElqS2AvrkZSbL8XU1iaN7DwJ6YZNy1F8KDt7IWWKyd8FURCtltq3HYdERCJQta6wRBD7HlmaZHzoUUbLtqRXTcotPekuW+NBvVXffho6yrE7oaRmM3RoPbIlVRhVokimPVLSpmWo+itJK7y/wsxXzVDCiE4iabwZxtBI3htntMpoNbbjKIpsstwoUiSa4UEUeZTVEufkigkMygfNkPLKpxHlw/yIrNijnFawS7bT/L4vead3OT+xX29RtuRAH8iO7ODsdCVfhFtbYdy0k+0oVBF213dCbNnsVP9mj/KaRgO3KzK90IxgqXyFECs/ocz+IVktnE/5kkejWrKRE0HrZU7sSz6B1uOIKXHNGFnQ3dEJEdT9kjMM9pg+Hvzx3imWCxMCeBzLekclnAgTKWFzNEnaMHJgJWWLKqn1rpg45XVaxFvCfu3a0ZfOaONQd2I8Ww8dWzlRyfFoUqeZTJ3aSc2jKQ2ilHQmeMyvAyg/oklebWM1iZVH0zhmxoREIgIt3EtTQSw7saQpBM2jGb25G6a5di1apMkD9dyj9/TmVri501PaDvSzRn9Wp2I62AvT6WnkL/Fp2uUiRen66Rl+TOJB1gIykS02w5SDB2/9DtLL15YchdcG2O7t8yuofdZE8KQB+xvQHk/VKQlMhZhViFZAYq1rWZbJ1awWqcjUd0OaVr6s0wSKchwXx76Mcf1fMzOWmBK+34nTsyMuPXPtSwjTHHybdT2a16nFcgFxZnlOp1mW7+s0x/IDneZZntfpCEtbp6MsP9RpgeVHOh1jeUELmnTfwZCLMOQCDpAwhKUDQ1hegiEsFQxhuQhDWBZhCMslGMLyYxjCchmGsLysZdXUU0nj2plYBmxCYGKOHrnMReVqKrlUQrtoVGpDnhJulVQUz6p/ZaBePPKGObAWSJfIml8xzpWPRuX41hUtbxo7V8Cx6m8fjvY58VLWi4U/Bf/V1lQlvWLNw5Or8BuGnmwnqjapeHRNl89VPbr+X1RUWAv0G0iFWCjKsmxwZyKEjzqdhmqglUPMbMw8tOt1y5qfw/03MUIWUP34NxQaC9yDTllJWe3grNXX27LcO4NyOBMsSTE38/pW+CIjs9J+kVnKno98HnAFjEpl2GoDrRW82ScxD5neJM8EcVtRNkja2M4EiQ0c84B5850EJmHqqg3kTuGGDfgFYW7BeSdconqjLIfuRezzKKT8W6fiRPaoaIzAs9kbYa/vQspvcQwkNPmlfgxUFaGpGDUV0DRSbqgGX8bZum1Cxg70Iyp2w7Ks4sPHFveVkm0ZhHykiNWjo5/WXqJOqtx+ZhSX752+BcEgNTF/e990cZDKu1rJMkdtA1O3GpVT15pD41WH6uZR9b3j7BM5a5puuiceel/TqtvBxVwssPZtDtJSJhfU9WGFDaLLxaVQ6mU0Se+4BxgWGNDvUIqN/6v62HyeK1WF0XEk307Ut9HnYAz8D9h/R/UD0Pdj6HINLs/3mhOfbvThbJmuohfrp+g3MGutuVm6BtzQdAPiIUetjrjKDXynBnF6pLkc6SHgY90V4gHAJoDF4BPdtYzmUwCj+Yw5PsDnzGHQZA6DLeYw2GbOGsAOcxjsMofBHnMYfMGcdYAvmcMgZA6DiDkMnjAnAHjKHAZfMYfB18xh8A1z7gN8yxwGMXMYJMxhsK/p1jDMLV7QXaC2QVWgA1NPWNzD4lBTZcj+jheG/b1BzP7BIKb+qOn2kPoTLwz1Z4OY+otBTP1V050h9TdeGOrvBjH1D4OY+ky/GMtlBr+MfJcKB5RdbD7n74n3D9vFQLkAAQAB//8AD3icrXsLcFzlleZ//v+++nb37dfte/VotVrdrW5JltuKpO6WJVluPyXbsmOEbGRjO4KVjWPZlsM4QIU4IYGlgCE2yxqKIQkJg2GreKQCTCZb1CZkiswjzOwOmSTATNVWTZLdDUwSMrVDsomD23vOf69assFAqgbk+773P4//nPOdc/5mwNjFl8WjosbaWblmxiOmIlTGYXzb11M7Z2ohAMbZCcZ5iG9prZl4whfwGju05xtttitUdwXYEUgkbQtWga5lC+XBaqJI285qpb8dVEc8Gnm5L5QM/f58yAlB399a7dD0mWAmdAqaMvBmKPKX9TdDwSjod9yhx03FAPcvI6Gk2lV33XoXUtKgL8C6Wa0WSzXbVjhg6JoqIPShCK0FOvOuE48K1V4B1VUQAVevugmP7Fz2CmTzW5/8+ZGP/+Kp7h/8oI4MuOZ7M5B9IvujH2Wf+PnCAjzn8ZK6AieMKRcvXnxWWSWCzGARlPcqtqs21WZzEBFgYIVDAYWzVJIrXBlH+hXGlWNM00GAJmYZ8sKBzTJFVZVppijqDFMVdTIWLa0o5JrdaHusPZGIG1IjFhQGK2mAZEe56kJnR1bTY7ZT7eivFGODBTdma3pHtlCNDVbwmgMHx/aO4R8ffeet5/ZCG6TfuV03IaSJU3oIzKsGO9+5PV+BwU5xqnOQx1aO8fW71yvD9fPn55/fA22PmsaFvfSgwZ8wzPiFvZ2DUMnzJ2hHVDMmHucPsSRrq7UQo4DMAV/AW7CANw/Zru3NIx20bBEpXwukArlxxOPReibaG63/SyQyiftzcBy3k1HuOHgjEgFHnkYfh4VodDJC4138Ff8hv5PlWbrWmm2O6grNEgGNCWGnbFtRm1Z04gzQPPWvkqMWF4eWU8DB267Df+gNe84bBvfRpfNI5Ny5yAmHDh5/PPLuByMlekDS9DsRR73nWHetwBShSO5PqCBQONO4E2wGlSvYZG6gMzeQ09SWFZC0tWION3oOVVXGTbGM+hrAzQj0O25yoN8R8YzzRsaZdzLwhpsGPEm783hAJ9+kq286eDX5pn/VydDjvk7i8EuchU21JJ3DNOqFzeABmywPcNXxhu/wB+3whrqwVw7Cn1j8vPfdDH6O7PR3fDV/Cb85wua/waSit309grZJHHOhHEQ9CA7zTGVCUb0ZvXzc1lrRe5Af+4An0aSL9op0IU9y6vRFtAYGKy7KJGFbQrdg2dXqGAwWilld0zUy9xLqd6A/zeFuy7gzYFmBOwOhZ6NNhZakm8YTI7S1pyM1mM032V26qevXGlzZ8+TKvROlB/BBkO9ACDalB7OZuBnuC5tRcAItpalENNOfhajVH1A2a1HjbHZ4N4r54oWLz4qPoe4jrMo2sonapm5QRQBQ3XycKVxwRRxjQuVCnWc6mrzOZ5FvBiraOmia5FubYRpok8n0ioRTKOQMNbWiszxYWAFZrQ1sB+dDJTFYghzyiBN3oB857ndIAha4Se/+YGUtjAkXXUO2xPE2eoe3TWPeMOXmzNi+j9w1HghvVbSAmu4c6nFac6MgbzXFU2baDr1241+98TfHtU/9t7df+MzU4msmfPYj06Wbw8Gqohda0/FkSyiyvtPGG/FsMKq1pLqmPvndkye/+y+08eYIHEJZpFmJra2Nop/VWuKcCwPvgRhnGlOFps6iIdAEmFVAKh53jblZyBU6nAFdbfX03tGwioZ9oGnEyDSWTQCyFzhoR+s/jdjgWLmc3L2K21zEmXCsM5aDm4g9Ny5v0PZVb+dY9Rcd/sl5eTiPj0nTaeiU+BhhW2qbuzJcUy2Nc2gCrjBkxWCqZiArGgOuwSzjAlDb5L91XfpvfYbpij6ZRIUWYoVcLqC2+UqNLddsMrekY3GZztVl2uQjpl4xjedIM+Uybc/r5viShuHgcgXuwQtpuoMHz8utCe/s8S+Y/7xMaYu2DX1yDrez3lp3cyyKdop+HLcLi878Uh9SKOSlj73cOIUFRVKVKHhaSS9JP452RCcYoJ3w85bz8Ckp9VN4xeZj9atpH4FnPCV4OtiDNIVYCrWwsbauK81VxUlaQnA+riFBisoUsiU0LbQpASCmmRAwg1MNJoH19uQ6WpriUV1jIQjphA5QjosiTfiy1tF+kPJKMTFYpAu6lkx40odnTv7VjYtC/QtTJyGH9HmMnKamGrcaqmaagRsMUwR9WeLmwsQREvIRevSvYa8uVFXo9Sc0w5A8/Rp5+jcxhXLuYAOIx/pbY+ggFp0FV8lNoLNAEQvyDkwBZR9T1ZC6xR0qFgsybix3DJcR7iIGwCsCHHQM0nYKVSBXQZPnqG7KDZiqrn8K524gpN9ghAx42k4GsvF3nohnA0kbnglkC9mrl7h4Db2TommKcVE1QOPRd97K5WJxsKO5nIjHbHtx/og3kK8iWys1he/EkKlqCbFOB6iKQp5Q5Yp6DB0AsjmPvHEFSGsoFraPaVpI2zLc2lmudErjJ/eeQwbKPoRBZulcwhwXYc6i1SdiEpiCF+KrFOIrAzKaHdhQ79tw4MAGuJv4rt8sQQu80jloGnnDfNVJBa+vn1WjSg1d8NHrg44FbTgdJ5+T77yy/gDI5wY7633yTbI7+CdyMDyEL2paDd0BvZjyfIYXH2/H+aqjDfXUisgnk3rFYMePoyZBegWanQpM5hKdlUSU1JnoQH2iG1d90IYADi0JPV2/oxMEeB7apm+aBngFw/ObMjzHzv7dgzyOh48fHZnmO9c8Wv+2RAGwHiP20UNnzx46mvYxyaMixDpZX22lQqQgRDqG4kYcMo92cpypAOo0Ti+iSYXJRGc5l8wvQhPfqpE0SYa7nDwkeQyh26OOlbecqVumoCwJ8+mDm+9/5T4eOyOt+4wk8WjavYTIG+7nD5Li2cWv8zGkMYoz51q2u3Y1JQSwfcumSn9JUxW0CZIWQ5isqKCo8zoGFPybx/lyHD2w4AaCBw7Ap1HIxAaHyZlr1tXG1owMt7h5Ox5QmxF4Iv6vDhaQoTFAYADuYIlnLa7b7RwtiOBDtVK1dbyCMXXxn5azOIIKfLFKaQP9K3HKIMYEQosvhkIWH23TQ9wIpCq9M4WxycnJsQIUYrEJ/bPGuOZohfHVzdmMaAmHm418c7DU3xdoyYPebFktPJtpHu7fefjw4R0VHiNTa06ZUTPe09a1sdTUVNrYtbo3nth11VW7tBa1d/U1a1t71rdG2u1IJNkWDYdbUs0pnnFT+OloWzISsdsjqVpvy9prqrNjed41POfPx2+J7TIXaWP5Wgf5bvToBEvpppQYOXPOJoda4gTQE6TsNK8sAvUSSHBFygfnfM9wL+8aK/Bddv0tZ8SufyKZ7ml7s20iCWdsPpPu4YVaXuur/2M6WX8riReTE21vtPUAnn4iyTxdf0vJ+/QM0pwsUL4D5BmUBQEeXpaU4W6RtExzN1In7eT9qHPpIoUdqAzSrdyHIPo1JNRps1uioCWJyIm2U/JG8oO4aZMXozF8b4RupRd5JJv7Nn8ZeUyxjlrakhJHcwO2gHMUDgGLR0MmS0GrIoMRWos0K81LUnPZYgmkw6sM8HtCoQTaT9y0Wu3f/MZuCYfijhMPhUVQNdL2hY8kMroS/8UvEqqeSfC/xzPV07k3vsqyrL+2ykYnhJjEz45OLIdbu4ncrbrWhImzltU7oqqaXAEdMWiHxPsSdvuF70K6/xf6FejjL13YBvFVP+UXrkwnyelZjBcltoLypQIoEmsoiDUw4C2QFS/I/J6yx5ybWOOqaMad0kJlKo+ElAdLqvRTMqOsgucuM64j3hgHU1H1mIkQ084Oje3eXT1lZwL1nwaD0BZMNfFTcHpv+sf7v6LEo4oZMlRbFNqH9tb60nEN0UkQ0mYawZNpR878eFuD1lWsl/Jb9J5iMbPlDKnkh3raBmS66U1M9Jm5rKUmMel1dKLOcxrVSgf5dJqU4o0g0pJyTlV37x4bytpCATOG8VUT4+m9cPoURiakE34ZMes/wbB0Roun+2p7h9oLSlwzQqZq2eIr+xe2/Rhp5QF8hHn5Hh/FfM9ibs32UrNG+l22ZbrnJ8N+fERAcD6YCp6nuPc2Aq/vWXiMfzKaye/BDfzTLPwe33MT8ns4P/y0uiLBdyZw3qRvNvGZegjF6H+escXvreOnkD7zm7IkADTbJEkU4sdw1jmwzpTj42smHLB82ijenjfx9YsXkccR+B5+I1azGtQk+4maTpnLlsBL75E7O1IPea+mzfPmUwQt00FJoG+nPxN/zruZzZprTljyx2GpXiHdYWBZtcINeB+2xVP16/GT9euDwf00TbqgK5gK7QvCmfp/wPn15WDa3BcM1l/Hy8F9wZQ31nf4Q2IjjrXyG+BnzXnMmqXiTuB5CLa01gINjvb8mesSTwHuSAEtzm8anp+uvwbdprkfhUs0wCNIxH6TP1l/vf6aPDThK0TXI5I+tjj+SX/8wIcaPxWX4y+CqsCiEIiAIzhsKrgfh+6qv+4L4RETPl6/zqMKukki9AA96OseZb3Zk7UKVKxZKt65tpR1J9p1sTGgP5Z4ah+KEzl73R/xEfr+I8H5fchlN/Jr0n0c3fSGkrz+vbhd5m2ZWltThDeKUaKh3WTZXWauS+WomBdMkjGvOCRuT9YfcIZxk0x24/5cT3q8redxe8TpTsLn03b9LIaFo/I0eQ7uxtjQm6rffI4elnTcJfbwX/qRFyG+Vw+SaJdyFIpugk0WXCcnaZFo1323viNAWHZPvk1+ugfjTf2sbcPR5LDT442bhwPj6Z5z9qi9wr8B85Ji51yXb3tISxlpSUtaZEYnFX8ZbHI6C8vk4ll2h5/YdRQbM0CUbSmXHsd5rH5zWz7fBnc/5iA1NLANwyQZ2+5JjiYfQ4mle+BxJA1prT9g+770dv4zTz9RnTPp+JlY4DJKoroOucmyT4fnsGIeFC3H9EtmB+qnGyP6413tPvs4BhIwipskDKakeIg+KKTgbl92JBkkHn1J3c8t+9ia2vBKhMFkGBJtEjrGDIzKE1SeAgTJiDAVRYpKmSGwMlksJor5gUWgjKlXYS0gurS4neaYflXJnaWBUjDKNAVhkWoF1WhHz7uJ2PapE8NHJkulySPD62/qVmLapMq10a997JqvnphQarc8dO3UQ2smYr38pfOWszK6fTs+eBKfHy4j8t2uWNrWnbDx5CNfe+TkxrHVE/EEW4ynxM9H2FhtpAeE2tnGFUH1J4xXChxD5hACLNXbLgOA3WU353rI37Y44SipbwdxwED/mEC0rOmuIzmlGkw7SBzNxZ6NN3519+zXRhV1Uosp3TdtGD68s4eXJo8uzHVtjyXc85gC9MYmRh+euuaRk+vhAG43Tm3RLGW7Clp52Oesq3N7dKVjnW9KxCdWjyFvi/nUs+Ja5CnPxtn+2t4NnVwLrELw76JqDMz1MacMGJoR0I5RVsA1lR/DLEdonLJLQWnOMcSamKlrszLnWWZ3mzcVOjsrnYWynTfVNmQ6aQFxrWtL9SQtgjqsojbxf5lp+qquSF1rVGyk02qZZEEKRkPdlv9ff3LVQ6MTFMas8xSft3fNVbd+vqg1KaF5w7RwBsirUye24UVXDS3oIcj/nz+56mF6qQlUAQ++gGoNytcxFG7P98DWMXMoHIL/6l/Z7p1riv8ko2oiyiru129WsSrmUjO1XdtWc0Pr7miOoWOV9YUQ07WQPmsCisWYDge5puAUAI3NIk6EQACmaQ+BGRaAwOSemV1TH90+vnlDrZBNFOi/nEUlLL96lYx5VZLqB5zDQLFQzGm6KuUX89L6YqxRuaPsCwXYTlJE1EVJt9ycWTo8bereoW7Wv38ewfOzmgI/N42Kn53LatjTxUCv85zbEyg+Y5hTcDddq99M2ysc8/51lABfjZ++8KvSxvUlnpCj7U+mIG3vR8yhXSbXEbaB3cDmatdds4lrhi9Z8hskNo2hkI+RQHWN6fMIUwKGFZiNhDmCNq6BoR1gejCoTzNdD86woB6cPDh33YFr91w99dHJLePr1tp525NylKZkzJtthLplN+ADzhOxjpiN1trRPwb/vhKfqIcMg8Mr3DDqd38o4cM36y9KWa+Tsn7v4/ocj134Vcg2TZsf/ABFKH4tYwrtObZYYxoF3QiQC+PjATwUho5+W8MkQlOOqUDxnlMNjZpsfB8zjJCxZe2afKeTjXeuboqT2XcOlsACB6XROFhWch7AeNy/VsZfx4fO5Aj8EjTVRPjLdtrmTS1NX7Azce6kmjZnnHf+1iuBiG0duzsmQTiZPzfjEoTGAqZ7xqt/nmmai8gXOWb0/sG9z8vyyPNOZjKDf9DlRgmQR93keVlHOU/9RTkfH8W8ieTQzWpsc21DGRM0Xw4soAUWDEDPtMB0oS9I5qeXC0PhMySPyTWjuYFctn9JEgWLp6FSXdz71TeSgzuQBmnXVHPXGqWhIhXkF+H2lQXxVqiSO5OthN9CQQSazmBOhdycwSgoZRJvQ28Yz8SVltDiwd3PUxMLN9De1dWehinH5783RvA9xhpyoHgnWAfGvE3sqtqOFT25rGIoMB4GBa0NAaepg2KYyiwVijQqFKGtopEeUFFYgQCboj0jZ8cCk7U1Q2W3MBBLjMRi0SCKxO0od6gD6Muon6Q35JGLDZS9DEpfLNZTA4aqrmrD0rwHCAO8Cs/Ur4a3J0Lql9WU4RfBJiYySfg+cviqaczLvipt59LuhbjXflPdSuRLUUd/9VV422jRv6SF/NbehYrcQ1p2AZ6jd80L5+kSRwE3WV+OVGTs9GvnU6yLDbJsrZ2aE+iijskqPtuHgTAktgz0r+xtaUaslZRRH6FKlRJrBwO9bK+lef8YXipg7j8GSJjM+GRPmSApRv6n//T4VrH3qqbRaNxoqoxSNMfwD6MV18yPulftrX+xZ7gXeka7vMCPgf2aQ8+N4bPuaKz7lg2LIGjjTT3x4T4jvubPYKL+cFtPTxscwm0DA+yVNaMjbFNt/cE9k+sUpoxgas8Gu1qjhG7GqUu+oAFel8B2gTDcgt+54If2XXv1VVsmVvRkM4m4TnnrYCGLtt5foc4F2rWO/NrIbxENvBHUy0WJBYqEg8hbyklAxoATvupfHMCZ3wAHaASEAFz/Y7pUPh+ZumWK7z65G1KGftgMJro0NbIzrOvbm1sCuhL9tBGKtrof1aLaZkdRjS4zYhzSDTDVw4bldnrPGtubWgKGiH0adR1JuR9VI/qErSgB72HMk0emp2+anr6F7kfTydZ+zdKSO0EdDRuTqaip3xAIjapaLa1aWqg/kmqNQEiXzza3ZFbqId3euezR4Iiqbkj5j7ZEIeTX7X4n9vLvLmKL2mAXILVUp0WPoyLCVJVGQ+/yNlGhjP8PNLq4y9vNy9rPrn+eW36OaPmdX0nTF7EIpu9XPlvW1XMgOiHbSHIL1ji1nsbpBdbAyXtlTRwjSHuCqyJvkjfAVEiMe317oeLEURlNKa/CI7tfVLxLp5qb4tFwUFVYJ3R6/STHqy1Xi1R9RLvvd6lSPIba14rZoo6zwa3w/7L18OGzRwC+N7B52+HD2zYPfA8OP3iIH9kyjkd4Fdwj9x85skUPzfXhQd9cSN96mB+97yjgoYUXvZ7kxYu/UW7mL7Eo+rwKK9byTKWsSWWz6N8VBaZxB5ShgDJZHerscm0J6L1at2fNGPH4CqQNZ+gAGTeaPZVNBB52IJ7nt/uI3N/B0707Do+8vmEH37rpdTLX8eEDd47Xr564Y3aIj+67azM8Q4dwYHjpHbJoOu1/8OkH++lk4s59Y2Lo+tsevG1ukA/N3uHb9f9TbkFebNRET61I/GEuOEtdCkxKcdfISpPptmSn01kdVNF4Y4NjHF1rWnh0cxWZKImsJdKcKPPIkZR5RIoYkcJ7dh665dDOHqV/4jgc2ILXkYz77zgwypGsH1zKst/L+ir6nJVsPdtR2zaC4aQTZC9CR4p0jigDQ6gmexJcUeeXdbS0xY7WslzDdpPF8uryAPX0L+tqoVNFD5QrFi7rbKGXwYnkJGCpwra4XMZe1th6JZcOCL0VgV445HepqL+l5jVdKMHP1VeH89a/WtYaK2/9Z/g4noyFYduzjf6WpSS0FIKDRovrC4aaQ9ZArQ9b1r/K58P0Yhi/4Msl4WPhFbUuzCTBb1OitsjmCVsAn+Qs3eokTJ1FeEQlI1nGXNlfnbS8tcc/sYz4wU8vsbd+lr/UII5u7mncOYBJ+WKc+5jsETe/L03AXCfmN4IlTVnCOYiVSxyWr5h45up7d/Lpu568c7ey4zRcu6yjzk9P3Xvu3im5qb9yaf98ab2AwZIsy0Zrq6nXxkG22zi121ScGiC71IoiZwcZqlAmzUCmvaU5GgkkzaQfoNCjlKimWnxvGhtR5b4r0roYFX59BZLFsvVB5NMRIVAGQ65bJoBsRuaFbLJM/0n3nZCLlZaWYKj+efWy88WezKv+yiG5dKnN23mX2uUJbi5bY+Rc4XgxBrHXGnlYb637gwLPEuXVBmD1ViiIyzgRfl5f9NddvfoB9NDxw0clWD9KV0FbdhMMjzfc+H7uJXEG8fo6Ns4O1q5fU+KCCq16PhXG3JuJcczFw6GwEaLSBXkQwNwF4DgLs1AgHDqA2FToAXEgCDpj+jTudDaDgUmnGsaG9bWx1UOVctJGzBlDf2HJWgZyh1HHkeV53RK5WC6Gc8fr45AzKSByxwlWHShTsxydSgfVLhALUZsXOiS8w0TlVOdJ006bC4ZayA43j7cN9WCqeCgYDTvGJzKnKG0Jn7ou6KSC18Frs8FUk2Jch1frv65/kWLdMMbf2fWfDKac4HFdaYpb8HY9ZDXZhnEylEgHP7t2L6YMcO46M22b111HA113zoFBDJQUpy/WLx6B36K+MxQdmlHBKerm0BIJKqUu68GgoLY0VSpexdChJiDC1WpC9qwK1cQYpS7U0BW0JAzeMrX6P+hRI2Dy4z/hqqmb4gS3jG8GLT77P1Ue5E4wfOFTFoioAS8NYVYZhv9umJapaPV6hct6wHdkHiowcqVYnvUivt5Qa+3vK/X2dBXy2Uy6pclBE4pR4XkwxWHTtq93vH+tv0l2U6pFvbNRePWrv51uBFbBWmgHbw/upXv+0LnRc1AxL/RjLrVgmvx/yP0Fq1KJxarV2A+PHct2HDvWwbvxJIYX60/THfzHrcdGH7shQm/iC2l6E/fXRumtaPU/ybeyx+p34UkVL0LJv9PAUHOomzL1w8q9uZaYoV3SIOoujHBKKii60eKMxhJHXUMgTQW0InVqqErq22AbYN6BHOMkFCMtlpWLDDc/0NM23tYLZ1uGMX5ZrWfPtkQj+chQ61lZiH+gZSiai0Sbz4JhDbeswXd2PSVr8E/twqtr8KXdu690Q2KpI6jHMMuhBjdRdbG9iQslEae6YVhDV7gBdOiHgK4iKtSERkv4yOpAP8ZMpimmNqtSRuUFG50FDD2AeaYRNrasGS0P2LTwuGDncpRJNtZ5Fpev85SVhMY6T3ewBJrtjAFIs8XZi95eSXOXLJkW75wKaXmE7afkst1TsjBDJxP3v3I//kG6Z9R+ce7WnfcfrvHRo6fPnT46CpteTMJZ7yXKMb2XTlHieMpspgUYLz+k3UsJV/LFTWNH7vvT08eHlfWHHtx+69yLSbZMRhHWhDn2SG0oYCC3qE/B0qAKuZqPg+b5XkErlwWmYkKlMkNY2eLmUAqF3OJinmKjrPIhuK1/W/IJ6z8kh5K1D2aK+/UTWqOzkz1fC4xVOgKKKqgjZqKV9nhTGGOgUGnZjiK4Mq8jJFKOMwJ0UxSLdlO/Ymvrtq8H3/UG+nBNcG0e7Vh79xt/yOf37KklDMPYaeyc3LZ1y8hwT671KoP8BApooL9agOqYUm2FATeRptTcdeQGxexmC3pWyw2u5ZSr4l9xsLCKW+DaaeqxVskXZql+XdTggY9NDrcHk331MoTzqZSj3fGlCe3GxJQT6IsGjeBkQOGQO53v+VKSb9E1EVMQ5vKs2/R7axiimWAmiVCh4/MZ1eYrecvvMWx9oa71KppmNkVhBs6G6m+veHkw8amOFi0QFY4pTI7RrikRxSd1jgBaCeytDEHmYSsUN/HTEEyqQVQ6ppY4937ER/nPmMXaWK6W8TvQy1cj+s28wcIlS70LHqQsSoS5rB18abP70ubwv0VMqrRhJALnb2SJXZ76vg7pAPc9++oF2+s8XzLyZUMt/3ajhy35encPGy4n+lIy4Xvvou1JERMJFmTa8zqHldSwlaBa9k6VC63heDzM/3cYttfndDMiKlbIwCN7eV2F8FS61toUNZhCzHltUoKChwg/yah6WVnr8jIXJer+ultoizj14CWn/GfvvEU5uIjTdtnx8nw86K1TlzWF5QsXBhYXGlw+3rLk/5IB/G8+gzZuYUagPa8ByoUaWfiRIuA35I4CrJOMVariLtOCaKD+Ryq3gvWTwSDci1AAfVtQi7zzsmWE4F5Vq/+RPKDe8714vX5SVSVGuXjxa2K/iCyN42qyOkbLkXwt6FIjmt5sRsHC11VB2yANZQl1HL+GWjFC9Em4Vx7Q2oKTeB2+oKkeL3xEkBU015zWlri4VEBrpICIlwZ7Eso2mgSVKs8GLeJN5YsLnmn7Lh7/45KS6ncSg5I/Por8NcaWi7UW27Te2JeyTGPqPg3VS9j2CzJyeznjn1qaGXCrpsq8ro655n7+1zi3WwkBRkGuRl5e3eMyi6L0TvDJcnYwTnM14fWG5Xyh5nXVLya56BmNJRUi25oYoiGRJBGXdaO+Rb1Y9R861mlZYzodsf21K8/wZ1mC8I75Hr9viTsF+fsW5BzxTSO1IFQNz6DJvnC/lPv9L6Ab4KcvfJU6gC94y9NfMP31s7i5XY5RIn6LJqKRxjAKDuOVppiQA65ycUhaEvVeQya8dVuF6uCYKClVFADVGd5FyGt9RTWAAgg50ahiNFm2YkcCarHv3QTW/6Jna0TY0VA0FEpnMkbciKJ0RGSrrMN/XzzKfy7p3saOsq21cUl7FVQ2Dboqxg8D38S4hnxooL2bGRU1qurqAtP1Q1M7xzd3Sd4MKlx9aN7cxtWq/1OQAi25ohrK0s0ilVHwbgmKVNGWD1T/IMmcmd2u68h5MhPsLpW6Mf7ZEUPfceC+0zfhdXy9uTm5cQffujnZrMQFzmZdv+n0HyDOnl33Z4RjOcFoIL338N50IIpBxBEd9+2+7fV+vGGHQ5Y18NCTDw1EwkITYRu/JwZe9fPMI+IfxFUsyjbSqvKhAcwt168pdedsTBbTzZxTnRzRxQyV/if8uggP8y2VcpqWw7iyTmgJOy3GuEu5oK35P5xC0L6GZFag308hopD9/6r3KyoE7rKG5Tqi3D9z8s6TM/3+7mEeeCxiPDanxdWDjxmRxwKIeebmVFVePajGtTl5VaWLcGDdLdMVpbTvxD0n9pWUyvQtew1RfioQFOU/1vU/Lotg4KmyMEz9nnuM2OINTVu8ETPuuUeXPuNZUcFYEmd9rFRbYSxfVUjLiN9dFerqyvd2yKWFBEEB548Fup3m1PWnBQHUERnjyKYur0O1v1pBfvl30u2Hnj4EwydOw/CBOyd23vd4+YefpuUbvHb84elmO9HXD1P3Tq1f48YM5VZ17msH5/d1fPtmWQndeOwTd1EnZNeXbtwsoBRbcbJ29T3T0GbGDO+3J95aen6KxViWDVCHL8i5wsPAxPLfE1FDb55RmQnmCYgrEoijOyX+6KeDoE66Tt5ONjkSgheKBA9LqL6qpqchU0E7QaSYtJ3+irSVimrrmpLJU3ej0gsK6vTRXbdlEXtnb9u17Z9B+Un9m9Hg5rmoE93YF4zCPwZ31H9b/6f6b3cEgzvAgAIYO4IwfMe64Q03nOX3fXzD8Lo7brzrLtiCz85tCkajwb6N0b9LJD738MOfSxTs2x7mj3yGsEgjzzBYB9Xw2hGCYAZOzYWG2uR6nFlvxlJeEZfO732ziNsX84be4ffMGz7/gRmQb1dyTX8Q/dtArU8Hb8Wybmgod53NBlQOilxbg9mPCIstK3sTAzE7O5BMJuTKkvJgwfulBskXM0CBMymXLQrpkSoDMVmJ6aA2QjGG4SJkRk38g5sd61dtYGoQ4St+jHY+U23r4aVWOEjtseoMnDgvfwCEm2+hp6r/X91AK4zYkU3HMVEaxnR3qBfqPzn+/wHPnsOreJxjYGRgYABi1vIsoXh+m68M3MwvgCIMt5YoxkDp2P9f/2exVDAHAbkcDEwgUQAz1Qu/AHicY2BkYGAO+p/FwMBS9v/r/68sFQxAERQQDACh8QbyeJxdT0sVwzAMy49AkAxAkbT3UQiAITGAISmAYQiA9th4ttUs7Q568UeSlVidiwSkB3PUPg+ESd6ZD/+8v7HyrtzwghY89ZB6BcyrYqc6RZhw48YhaA1Wc/v1PQtdeXJ/HppUmFM597nvBVK7D+Z+E8/uQZLBgDyaz3Llvxx02S3c/Hv813JrznryZP4F+6lSfQAAAAAAAAAAUAC2ATABaAGyAfoCJAKwAzYDmgQSBFwExgUyBbQF/AZOBvwHRAe2B/YISgigCPIJGglCCWQJignACgAKQAp2CroLAAtGC4oL8gxcDPINng5iDuYPag/6EF4RIBGGEeQSShKYEyQTbhOyFAoUYhS+FVoVphYoFooXHBeGGFoYnhjGGOwZChlOGXgZrBneGhwaWhqgGtIbLhvyHHQc2B1QHZ4d/wABAAAAUwBtAAYAAAAAAAIAIAAwAHMAAAB2C3AAAAAAeJx1kN9q2zAUh39q0441YxcbjN3tXJWWEcc1lEGvWkLbXZeSu8JUV/6T2VKQlY48w95ifYa9zt6jd/vFESUUYiP5O5/O8ZEE4AP+QWH9nHKsWeEdozXv4A0uIu/Sf488IN9G3sMQPyLv0/+MfICv+BV5iI/4wz+owVtGM/yNrPBZfYm8g/fqW+Rd+svIA/Jd5D18UovI+/S/Ix9gqp4iD3GoniduvvR1WQU5mhxLlmap3C/FUdVWN6IXoXK+k3MpnA2maVySuza0ZlToUZ07292YctFov6k2eWp8VzsrJ0m6qa+NNV4H87Dq1j2WWQiFFN61chX7yNy7mclDUoUwPxuPN/tjAoc5lvCoUaJCgOCI9pjfDGk/BPfMEGaus2pYaDQ0GgtWVP1Kx/ico2BkaQ0zGnKCnHNL09KNuK451721rLqhLfmfht5vzdrmp7Sr3nUfC07YL92afU1r+wrd7/Dh5WwdHrmLjDawanUK3+9acPXqPML7Wq3NaHL6pL+1QHuGMd8t5/8PvPGO3QAAAHicbZLnlpswEIV9DRiwvZtseu89Ib333vvmBWRZYMVC0pHEEufpg8BO/kTncOfTaLgMOtPr97o17P1/baKPACEiDBAjQYohRhhjDevYhu3YwA7sxC7sxh7sxT7sxwEcxCEcxhEcxTEcxwmcxCmcxhmcxTmcxwVcxCVkuIwruIpruI4buIlbuI07uIt7uI8HeIhHeIwneIpneI4XeIlXeI03eIt3eI8P+IhP+Iwv+Ipv+I5N/OiF1hEz9JKxUrtFrDl1lWF9NR9QIikToRaVjUouKxvOmNBjLxnlhgo2DbnM1djLKrNGnGPScSUzItzGv93yPP2bSQSX84z9cqFQdJ56yZRmMhW8mLlJJSaBI0XYPDaZKDUviZmvr6DrNjJMi0WcK1MTM02mqpbZlJtEsNx5SI238jSodJtoS7qv+BpPw67IY9xU+dg5TXjROTWwdGrIOzWhT+uA0jolxqjaZrSOnCF2Nmq16651EYpMm1fakAul9SJQeR5QVYQlk1VkZ8SwoVNFIVjWnKQrlBGdMToftdoZjrs77DajqXKrS02YEFxbbtdWkG0x44JJVUS5aBqKSlJwmhDrmOF2Hv9Wqsy4TNqoKhfmSrrQKuNSL5nvPG6p0s0AkEWkSWVZMy1Kx3ljk03qLuZ14lTmB8gNGmByGrGfjLrhlhJV2f7SaIneNF1ypQNbybBUSgZswQaWEUNngeay1/sD4l/60HicY/DewXAiKGIjI2Nf5AbGnRwMHAzJBRsZWJ02MTAyaIEYm7mYGDkgLD4GMIvNaRfTAaA0J5DN7rSLwQHCZmZw2ajC2BEYscGhI2Ijc4rLRjUQbxdHAwMji0NHckgESEkkEGzmYWLk0drB+L91A0vvRiYGFwAMdiP0AAA=') format('woff');\n}\n</style>\n<style id=\"style-core\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\nhtml {\n\t/*\n\t\tWe define the base font size and line height here as they affect the layout\n\t\tof the base page elements (i.e. `#ui-bar`, `#ui-dialog`, and `#story`).\n\t*/\n\tfont: 16px/1 Helmet, Freesans, sans-serif;\n}\n\n/* Story data styling. */\n#store-area, tw-storydata {\n\tdisplay: none !important;\n\tz-index: 0;\n}\n\n/* Special no transition styling. */\n.no-transition {\n\t-o-transition: none !important;\n\ttransition: none !important;\n}\n\n\n/*\n\tFullscreen appearance styles.\n*/\n*:-webkit-full-screen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\n*:-moz-full-screen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\n*:-ms-fullscreen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\n*:fullscreen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\nbody::-ms-backdrop { /* Prevent IE 11 from hiding the `body` element's background. */\n\tbackground: none;\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n*:focus {\n\toutline: thin dotted;\n}\n*:disabled {\n\tcursor: not-allowed !important;\n}\nbody {\n\tcolor: #eee;\n\tbackground-color: #111;\n\toverflow: auto;\n}\na {\n\tcursor: pointer;\n\tcolor: #68d;\n\ttext-decoration: none;\n\t-o-transition-duration: 200ms;\n\t   transition-duration: 200ms;\n}\na:hover {\n\tcolor: #8af;\n\ttext-decoration: underline;\n}\na.link-broken {\n\tcolor: #c22;\n}\na.link-broken:hover {\n\tcolor: #e44;\n}\na[disabled], span.link-disabled {\n\tcolor: #aaa;\n\tcursor: not-allowed !important;\n\t/*\n\t\tNOTE: Do not use `pointer-events` here as it disables\n\t\tthe display of a cursor in some browsers.\n\n\t\tpointer-events: none;\n\t*/\n\ttext-decoration: none;\n}\narea {\n\tcursor: pointer;\n}\nbutton {\n\tcursor: pointer;\n\tcolor: #eee;\n\tbackground-color: #35a;\n\tborder: 1px solid #57c;\n\tline-height: normal;\n\tpadding: 0.4em;\n\t-o-transition-duration: 200ms;\n\t   transition-duration: 200ms;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\nbutton:hover {\n\tbackground-color: #57c;\n\tborder-color: #79e;\n}\nbutton:disabled {\n\tbackground-color: #444;\n\tborder: 1px solid #666;\n}\ninput, select, textarea {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tpadding: 0.4em;\n}\nselect {\n\tpadding: 0.34em 0.4em;\n}\ninput[type=\"text\"] {\n\tmin-width: 18em;\n}\ntextarea {\n\tmin-width: 30em;\n\tresize: vertical;\n}\ninput[type=\"checkbox\"], input[type=\"file\"], input[type=\"radio\"], select {\n\tcursor: pointer;\n}\n/* BEGIN: input[type=\"range\"] */\ninput[type=\"range\"] {\n\t-webkit-appearance: none;\n\tmin-height: 1.2em;\n}\ninput[type=\"range\"]:focus {\n\toutline: none;\n}\ninput[type=\"range\"]::-webkit-slider-runnable-track {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: 100%;\n}\ninput[type=\"range\"]::-webkit-slider-thumb {\n\t-webkit-appearance: none;\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 18px;\n\t/*\n\t\tNOTE: Ideally, `margin-top` should be `0` for Edge/Spartan (ca. v17), but\n\t\treal WebKit/Blink-based browsers need it.  Since there's more of them and\n\t\tEdge is co-opting the prefix anyway, we cater to them.  Edge will simply\n\t\thave to look ever so slightly off.\n\t*/\n\tmargin-top: -5px;\n\twidth: 33px;\n}\ninput[type=\"range\"]:focus::-webkit-slider-runnable-track {\n\tbackground: #222;\n}\ninput[type=\"range\"]::-moz-range-track {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: 100%;\n}\ninput[type=\"range\"]::-moz-range-thumb {\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 18px;\n\twidth: 33px;\n}\ninput[type=\"range\"]::-ms-track {\n\tbackground: transparent;\n\tborder-color: transparent;\n\tcolor: transparent;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: calc(100% - 1px);\n}\ninput[type=\"range\"]::-ms-fill-lower {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n}\ninput[type=\"range\"]::-ms-fill-upper {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n}\ninput[type=\"range\"]::-ms-thumb {\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 16px;\n\twidth: 33px;\n}\n/* END: input[type=\"range\"] */\ninput:not(:disabled):focus, select:not(:disabled):focus, textarea:not(:disabled):focus,\ninput:not(:disabled):hover, select:not(:disabled):hover, textarea:not(:disabled):hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\nhr {\n\tdisplay: block;\n\theight: 1px;\n\tborder: none;\n\tborder-top: 1px solid #eee;\n\tmargin: 1em 0;\n\tpadding: 0;\n}\naudio, canvas, progress, video {\n\tmax-width: 100%;\n\tvertical-align: middle;\n}\n\n.error-view {\n\tbackground-color: #511;\n\tborder-left: 0.5em solid #c22;\n\tdisplay: inline-block;\n\tmargin: 0.1em;\n\tmax-width: 100%;\n\tpadding: 0 0.25em;\n\tposition: relative;\n}\n.error-view > .error-toggle {\n\tbackground-color: transparent;\n\tborder: none;\n\tline-height: inherit;\n\tleft: 0;\n\tpadding: 0;\n\tposition: absolute;\n\ttop: 0;\n\twidth: 1.75em;\n}\n.error-view > .error {\n\tdisplay: inline-block;\n\tmargin-left: 0.25em;\n}\n.error-view > .error-toggle + .error {\n\tmargin-left: 1.5em;\n}\n.error-view > .error-source[hidden] {\n\tdisplay: none;\n}\n.error-view > .error-source:not([hidden]) {\n\tbackground-color: rgba(0, 0, 0, 0.2);\n\tdisplay: block;\n\tmargin: 0 0 0.25em;\n\toverflow-x: auto;\n\tpadding: 0.25em;\n}\n\n.highlight, .marked {\n\tcolor: yellow;\n\tfont-weight: bold;\n\tfont-style: italic;\n}\n.nobr {\n\twhite-space: nowrap;\n}\n\n[data-icon]:before,\n[data-icon-before]:before,\n[data-icon-after]:after,\n.error-view > .error-toggle:before,\n.error-view > .error:before,\na.link-external:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n[data-icon]:before {\n\tcontent: attr(data-icon);\n}\n[data-icon-before]:before {\n\tcontent: attr(data-icon-before) \"\\00a0\";\n}\n[data-icon-after]:after {\n\tcontent: \"\\00a0\" attr(data-icon-after);\n}\n.error-view > .error-toggle:before {\n\tcontent: \"\\e81a\";\n}\n.error-view > .error-toggle.enabled:before {\n\tcontent: \"\\e818\";\n}\n.error-view > .error:before {\n\tcontent: \"\\e80d\\00a0\\00a0\";\n}\na.link-external:after {\n\tcontent: \"\\00a0\\e80e\";\n}\n</style>\n<style id=\"style-core-display\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-display.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\n#story {\n\tz-index: 10;\n\tmargin: 2.5em;\n}\n@media screen and (max-width: 1136px) {\n\t#story {\n\t\tmargin-right: 1.5em;\n\t}\n}\n#passages {\n\tmax-width: 54em;\n\tmargin: 0 auto;\n}\n</style>\n<style id=\"style-core-passage\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-passage.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault appearance styles.\n*/\n.passage {\n\tline-height: 1.75;\n\ttext-align: left;\n\t-o-transition: opacity 400ms ease-in;\n\ttransition: opacity 400ms ease-in;\n}\n.passage-in {\n\topacity: 0;\n}\n.passage ul, .passage ol {\n\tmargin-left: 0.5em;\n\tpadding-left: 1.5em;\n}\n.passage table {\n\tmargin: 1em 0;\n\tborder-collapse: collapse;\n\tfont-size: 100%;\n}\n.passage tr, .passage th, .passage td, .passage caption {\n\tpadding: 3px;\n}\n</style>\n<style id=\"style-core-macro\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-macro.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault appearance styles.\n*/\n.macro-linkappend-insert,\n.macro-linkprepend-insert,\n.macro-linkreplace-insert,\n.macro-append-insert,\n.macro-prepend-insert,\n.macro-replace-insert,\n.macro-repeat-insert,\n.macro-timed-insert {\n\t-o-transition: opacity 400ms ease-in;\n\ttransition: opacity 400ms ease-in;\n}\n.macro-linkappend-in,\n.macro-linkprepend-in,\n.macro-linkreplace-in,\n.macro-append-in,\n.macro-prepend-in,\n.macro-replace-in,\n.macro-repeat-in,\n.macro-timed-in {\n\topacity: 0;\n}\n</style>\n<style id=\"style-ui-dialog\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-dialog.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tPatches to the core styles.\n*/\nhtml[data-dialog] body {\n\toverflow: hidden;\n}\n\n\n/*\n\tDefault structural styles.\n*/\n#ui-overlay.open {\n\tvisibility: visible;\n\t-o-transition: opacity 200ms ease-in;\n\ttransition: opacity 200ms ease-in;\n}\n#ui-overlay:not(.open) {\n\t-o-transition: visibility 200ms step-end, opacity 200ms ease-in;\n\ttransition: visibility 200ms step-end, opacity 200ms ease-in;\n}\n#ui-overlay {\n\tvisibility: hidden;\n\topacity: 0;\n\tz-index: 100000;\n\tposition: fixed;\n\t/*\n\ttop: -50vh;\n\tleft: -50vw;\n\theight: 200vh;\n\twidth: 200vw;\n\t*/\n\ttop: -50%;\n\tleft: -50%;\n\theight: 200%;\n\twidth: 200%;\n}\n#ui-dialog.open {\n\tdisplay: block;\n\t-o-transition: opacity 200ms ease-in;\n\ttransition: opacity 200ms ease-in;\n}\n/*\n\tWe do not animate `#ui-dialog:not(.open)` for various reasons.  Chief among\n\tthem, however, is so that the dialog isn't in the middle of its animation\n\twhen other page updates happen.\n\n\te.g. The restoration of `overflow` on `body` would cause the still animating\n\t     dialog to jump around a little if a scrollbar were to pop in.\n\n\t     Any dialog action which performs a task which has its own animations\n\t     (e.g. passage display) or causes the page to reload in addition to\n\t     closing the dialog could cause display shenanigans.\n*/\n#ui-dialog {\n\tdisplay: none;\n\topacity: 0;\n\tz-index: 100100;\n\tposition: fixed;\n\ttop: 50px;\n\tmargin: 0;\n\tpadding: 0;\n}\n#ui-dialog > * {\n\tbox-sizing: border-box;\n}\n#ui-dialog-titlebar {\n\tposition: relative;\n}\n#ui-dialog-close {\n\tdisplay: block;\n\tposition: absolute;\n\tright: 0;\n\ttop: 0;\n\twhite-space: nowrap;\n}\n#ui-dialog-body {\n\toverflow: auto;\n\tmin-width: 280px;\n\theight: 92%; /* fallback for browsers without support for calc() */\n\theight: calc(100% - 2.1em); /* parent - title(2.1em) */\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n#ui-overlay {\n\tbackground-color: #000;\n}\n#ui-overlay.open {\n\topacity: 0.8;\n}\n#ui-dialog {\n\tmax-width: 66em;\n}\n#ui-dialog.open {\n\topacity: 1;\n}\n#ui-dialog-titlebar {\n\tbackground-color: #444;\n\tmin-height: 24px;\n}\n#ui-dialog-title {\n\tmargin: 0;\n\tpadding: 0.2em 3.5em 0.2em 0.5em;\n\tfont-size: 1.5em;\n\ttext-align: center;\n\ttext-transform: uppercase;\n}\n#ui-dialog-close {\n\tcursor: pointer;\n\tfont-size: 120%;\n\tmargin: 0;\n\tpadding: 0;\n\twidth: 3.6em;\n\theight: 92%;\n\tbackground-color: transparent;\n\tborder: 1px solid transparent;\n\t-o-transition-duration: 200ms;\n\t   transition-duration: 200ms;\n}\n#ui-dialog-close:hover {\n\tbackground-color: #b44;\n\tborder-color: #d66;\n}\n#ui-dialog-body {\n\tbackground-color: #111;\n\tborder: 1px solid #444;\n\ttext-align: left;\n\tline-height: 1.5;\n\tpadding: 1em;\n}\n#ui-dialog-body > *:first-child {\n\tmargin-top: 0;\n}\n#ui-dialog-body hr {\n\tbackground-color: #444;\n}\n\n/* Default dialog button bar styling. */\n#ui-dialog-body ul.buttons {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n#ui-dialog-body ul.buttons li {\n\tdisplay: inline-block;\n\tmargin: 0;\n\tpadding: 0.4em 0.4em 0 0;\n}\n#ui-dialog-body ul.buttons > li + li > button {\n\tmargin-left: 1em;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-dialog-close {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-dialog-close {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n</style>\n<style id=\"style-ui\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\n/* Settings dialog styling. */\n#ui-dialog-body.settings [id|=\"setting-body\"] > div:first-child {\n\tdisplay: table;\n\twidth: 100%;\n}\n#ui-dialog-body.settings [id|=\"setting-label\"] {\n\tdisplay: table-cell;\n\tpadding: 0.4em 2em 0.4em 0;\n}\n#ui-dialog-body.settings [id|=\"setting-label\"] + div {\n\tdisplay: table-cell;\n\tmin-width: 8em;\n\ttext-align: right;\n\tvertical-align: middle;\n\twhite-space: nowrap;\n}\n\n\n/*\n\tBuilt-in dialog appearance styles.\n*/\n/* List-based dialog styling (primarily for the Jumpto & Share dialogs). */\n#ui-dialog-body.list {\n\tpadding: 0;\n}\n#ui-dialog-body.list ul {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n\tborder: 1px solid transparent;\n}\n#ui-dialog-body.list li {\n\tmargin: 0;\n}\n#ui-dialog-body.list li:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.list li a {\n\tdisplay: block;\n\tpadding: 0.25em 0.75em;\n\tborder: 1px solid transparent;\n\tcolor: #eee;\n\ttext-decoration: none;\n}\n#ui-dialog-body.list li a:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n\n/* Saves dialog styling. */\n#ui-dialog-body.saves {\n\tpadding: 0 0 1px; /* Webkit/Blink need 1px bottom padding or they'll trigger the scroll bar */\n}\n#ui-dialog-body.saves > *:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.saves table {\n\tborder-spacing: 0;\n\twidth: 100%;\n}\n#ui-dialog-body.saves tr:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.saves td {\n\tpadding: 0.33em 0.33em;\n}\n#ui-dialog-body.saves td:first-child {\n\tmin-width: 1.5em;\n\ttext-align: center;\n}\n#ui-dialog-body.saves td:nth-child(3) {\n\tline-height: 1.2;\n}\n#ui-dialog-body.saves td:last-child {\n\ttext-align: right;\n}\n#ui-dialog-body.saves .empty {\n\tcolor: #999;\n\tspeak: none;\n\ttext-align: center;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n#ui-dialog-body.saves .datestamp {\n\tfont-size: 75%;\n\tmargin-left: 1em;\n}\n#ui-dialog-body.saves ul.buttons li {\n\tpadding: 0.4em;\n}\n#ui-dialog-body.saves ul.buttons > li + li > button {\n\tmargin-left: 0.2em;\n}\n#ui-dialog-body.saves ul.buttons li:last-child {\n\t/*\n\t\tUsing `position:absolute;right:0;` here can produce poor results,\n\t\tso we use `float:right` instead.\n\t*/\n\tfloat: right;\n}\n\n/* Settings dialog styling. */\n#ui-dialog-body.settings div[id|=\"header-body\"] {\n\tmargin: 1em 0;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"]:first-child {\n\tmargin-top: 0;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"]:not(:first-child) {\n\tborder-top: 1px solid #444;\n\tpadding-top: 1em;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"] > * {\n\tmargin: 0;\n}\n#ui-dialog-body.settings h2[id|=\"header-heading\"] {\n\tfont-size: 1.375em;\n}\n#ui-dialog-body.settings p[id|=\"header-desc\"],\n#ui-dialog-body.settings p[id|=\"setting-desc\"] {\n\tfont-size: 87.5%;\n\tmargin: 0 0 0 0.5em;\n}\n#ui-dialog-body.settings div[id|=\"setting-body\"] + div[id|=\"setting-body\"] {\n\tmargin: 1em 0;\n}\n#ui-dialog-body.settings [id|=\"setting-control\"] {\n\twhite-space: nowrap;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"] {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tpadding: 0.4em;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"]:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled {\n\tbackground-color: #282;\n\tborder-color: #4a4;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:hover {\n\tbackground-color: #4a4;\n\tborder-color: #6c6;\n}\n#ui-dialog-body.settings input[type=\"range\"][id|=\"setting-control\"] {\n\tmax-width: 35vw;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-dialog-body.list a,\n#ui-dialog-body.settings span[id|=\"setting-input\"] {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-dialog-body.saves button[id=\"saves-export\"]:before,\n#ui-dialog-body.saves button[id=\"saves-import\"]:before,\n#ui-dialog-body.saves button[id=\"saves-clear\"]:before,\n#ui-dialog-body.settings button[id|=\"setting-control\"]:after,\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#ui-dialog-body.saves button[id=\"saves-export\"]:before {\n\tcontent: \"\\e829\\00a0\";\n}\n#ui-dialog-body.saves button[id=\"saves-import\"]:before {\n\tcontent: \"\\e82a\\00a0\";\n}\n#ui-dialog-body.saves button[id=\"saves-clear\"]:before {\n\tcontent: \"\\e827\\00a0\";\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"]:after {\n\tcontent: \"\\00a0\\00a0\\e830\";\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:after {\n\tcontent: \"\\00a0\\00a0\\e831\";\n}\n</style>\n<style id=\"style-ui-bar\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-bar.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tPatches to the core styles.\n*/\n#story {\n\tmargin-left: 20em;\n\t-o-transition: margin-left 200ms ease-in;\n\ttransition: margin-left 200ms ease-in;\n}\n#ui-bar.stowed ~ #story {\n\tmargin-left: 4.5em;\n}\n@media screen and (max-width: 1136px) {\n\t#story {\n\t\tmargin-left: 19em;\n\t}\n\t#ui-bar.stowed ~ #story {\n\t\tmargin-left: 3.5em;\n\t}\n}\n/*\n\tAt very narrow viewport widths, set `#story{margin-left}` equal to the value\n\tof `#ui-bar.stowed~#story{margin-left}`, so that `#ui-bar` will side over top\n\tof `#story` when unstowed, rather than shoving it over.\n*/\n@media screen and (max-width: 768px) {\n\t#story {\n\t\tmargin-left: 3.5em;\n\t}\n}\n\n\n/*\n\tDefault structural styles.\n*/\n#ui-bar {\n\tposition: fixed;\n\tz-index: 50;\n\ttop: 0;\n\tleft: 0;\n\twidth: 17.5em;\n\theight: 100%;\n\tmargin: 0;\n\tpadding: 0;\n\t-o-transition: left 200ms ease-in;\n\ttransition: left 200ms ease-in;\n}\n#ui-bar.stowed {\n\tleft: -15.5em;\n}\n#ui-bar-tray {\n\tposition: absolute;\n\ttop: 0.2em;\n\tleft: 0;\n\tright: 0;\n}\n#ui-bar-body {\n\theight: 90%; /* fallback for browsers without support for calc() */\n\theight: calc(100% - 2.5em);\n\tmargin: 2.5em 0;\n\tpadding: 0 1.5em;\n}\n#ui-bar.stowed #ui-bar-history,\n#ui-bar.stowed #ui-bar-body {\n\tvisibility: hidden;\n\t-o-transition: visibility 200ms step-end;\n\ttransition: visibility 200ms step-end;\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n#ui-bar {\n\tbackground-color: #222;\n\tborder-right: 1px solid #444;\n\ttext-align: center;\n}\n#ui-bar a {\n\ttext-decoration: none;\n}\n#ui-bar hr {\n\tborder-color: #444;\n}\n#ui-bar-toggle,\n#ui-bar-history [id|=\"history\"] {\n\tfont-size: 1.2em;\n\tline-height: inherit;\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n}\n#ui-bar-toggle {\n\tdisplay: block;\n\tposition: absolute;\n\ttop: 0;\n\tright: 0;\n\tborder-right: none;\n\tpadding: 0.3em 0.45em 0.25em;\n}\n#ui-bar.stowed #ui-bar-toggle {\n\tpadding: 0.3em 0.35em 0.25em 0.55em;\n}\n#ui-bar-toggle:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n#ui-bar-history {\n\tmargin: 0 auto;\n}\n#ui-bar-history [id|=\"history\"] {\n\tpadding: 0.2em 0.45em 0.35em;\n}\n#ui-bar-history #history-jumpto {\n\tpadding: 0.2em 0.665em 0.35em;\n}\n#ui-bar-history [id|=\"history\"]:not(:first-child) {\n\tmargin-left: 1.2em;\n}\n#ui-bar-history [id|=\"history\"]:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n#ui-bar-history [id|=\"history\"]:disabled {\n\tcolor: #444;\n\tbackground-color: transparent;\n\tborder-color: #444;\n}\n#ui-bar-body {\n\tline-height: 1.5;\n\toverflow: auto;\n}\n#ui-bar-body > :not(:first-child) {\n\tmargin-top: 2em;\n}\n#story-title {\n\tmargin: 0;\n\tfont-size: 162.5%;\n}\n#story-author {\n\tmargin-top: 2em;\n\tfont-weight: bold;\n}\n#menu ul {\n\tmargin: 1em 0 0;\n\tpadding: 0;\n\tlist-style: none;\n\tborder: 1px solid #444;\n}\n#menu ul:empty {\n\tdisplay: none;\n}\n#menu li {\n\tmargin: 0;\n}\n#menu li:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#menu li a {\n\tdisplay: block;\n\tpadding: 0.25em 0.75em;\n\tborder: 1px solid transparent;\n\tcolor: #eee;\n\ttext-transform: uppercase;\n}\n#menu li a:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-bar-history [id|=\"history\"],\n#ui-bar-toggle,\n#menu a {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-bar-toggle:before,\n#ui-bar-history [id|=\"history\"],\n#menu-core li[id|=\"menu-item\"] a:before {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#ui-bar-toggle:before {\n\tcontent: \"\\e81d\";\n}\n#ui-bar.stowed #ui-bar-toggle:before {\n\tcontent: \"\\e81e\";\n}\n#menu-item-saves a:before {\n\tcontent: \"\\e82b\\00a0\";\n}\n#menu-item-settings a:before {\n\tcontent: \"\\e82d\\00a0\";\n}\n#menu-item-restart a:before {\n\tcontent: \"\\e82c\\00a0\";\n}\n#menu-item-share a:before {\n\tcontent: \"\\e82f\\00a0\";\n}\n</style>\n<style id=\"style-ui-debug\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-debug.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault debug bar styles.\n*/\n#debug-bar {\n\tbackground-color: #222;\n\tborder-left: 1px solid #444;\n\tborder-top: 1px solid #444;\n\tbottom: 0;\n\tmargin: 0;\n\tmax-height: 75%;\n\t/* max-width: 28em;\n\tmin-width: 22em; */\n\tpadding: 0.5em;\n\tposition: fixed;\n\tright: 0;\n\tz-index: 99900;\n}\n#debug-bar > div:not([id]) + div {\n\tmargin-top: 0.5em;\n}\n#debug-bar > div > label {\n\tmargin-right: 0.5em;\n}\n#debug-bar > div > input[type=\"text\"] {\n\tmin-width: 0;\n\twidth: 8em;\n}\n#debug-bar > div > select {\n\twidth: 15em;\n}\n\n#debug-bar-toggle {\n\tcolor: #eee;\n\tbackground-color: #222;\n\tborder: 1px solid #444;\n\theight: 101%; /* fallback for browsers without support for calc() */\n\theight: calc(100% + 1px);\n\tleft: -2em; /* fallback for browsers without support for calc() */\n\tleft: calc(-2em - 1px);\n\tposition: absolute;\n\ttop: -1px;\n\twidth: 2em;\n}\n#debug-bar-toggle:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n\n#debug-bar-hint {\n\tbottom: 0.175em;\n\tfont-size: 4.5em;\n\topacity: 0.33;\n\tpointer-events: none;\n\tposition: fixed;\n\tright: 0.6em;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n\twhite-space: nowrap;\n}\n\n#debug-bar-watch {\n\tbackground-color: #222;\n\tborder-left: 1px solid #444;\n\tborder-top: 1px solid #444;\n\tbottom: 102%; /* fallback for browsers without support for calc() */\n\tbottom: calc(100% + 1px);\n\tfont-size: 0.9em;\n\tleft: -1px;\n\tmax-height: 650%; /* fallback for browsers without support for vh units */\n\tmax-height: 65vh;\n\tposition: absolute;\n\toverflow-x: hidden;\n\toverflow-y: scroll;\n\tright: 0;\n\tz-index: 99800;\n}\n#debug-bar-watch[hidden] {\n\tdisplay: none;\n}\n#debug-bar-watch div {\n\tcolor: #999;\n\tfont-style: italic;\n\tmargin: 1em auto;\n\ttext-align: center;\n}\n#debug-bar-watch table {\n\twidth: 100%;\n}\n#debug-bar-watch tr:nth-child(2n) {\n\tbackground-color: rgba(127, 127, 127, 0.15);\n}\n#debug-bar-watch td {\n\tpadding: 0.2em 0;\n}\n#debug-bar-watch td:first-child + td {\n\tpadding: 0.2em 0.3em 0.2em 0.1em;\n}\n#debug-bar-watch .watch-delete {\n\tbackground-color: transparent;\n\tborder: none;\n\tcolor: #c00;\n}\n#debug-bar-watch-all,\n#debug-bar-watch-none {\n\tmargin-left: 0.5em;\n}\n#debug-bar-watch-toggle,\n#debug-bar-views-toggle {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tmargin-right: 1em;\n\tpadding: 0.4em;\n}\n#debug-bar-watch-toggle:hover,\n#debug-bar-views-toggle:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle,\nhtml[data-debug-view] #debug-bar-views-toggle {\n\tbackground-color: #282;\n\tborder-color: #4a4;\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle:hover,\nhtml[data-debug-view] #debug-bar-views-toggle:hover {\n\tbackground-color: #4a4;\n\tborder-color: #6c6;\n}\n\n#debug-bar-toggle:before,\n#debug-bar-hint:after,\n#debug-bar-watch .watch-delete:before,\n#debug-bar-watch-add:before,\n#debug-bar-watch-all:before,\n#debug-bar-watch-none:before,\n#debug-bar-watch-toggle:after,\n#debug-bar-views-toggle:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#debug-bar-toggle:before {\n\tcontent: \"\\e838\";\n}\n#debug-bar-hint:after {\n\tcontent: \"\\e838\\202f\\e822\";\n}\n#debug-bar-watch .watch-delete:before {\n\tcontent: \"\\e804\";\n}\n#debug-bar-watch-add:before {\n\tcontent: \"\\e805\";\n}\n#debug-bar-watch-all:before {\n\tcontent: \"\\e83a\";\n}\n#debug-bar-watch-none:before {\n\tcontent: \"\\e827\";\n}\n#debug-bar-watch-toggle:after,\n#debug-bar-views-toggle:after {\n\tcontent: \"\\00a0\\00a0\\e830\";\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle:after,\nhtml[data-debug-view] #debug-bar-views-toggle:after {\n\tcontent: \"\\00a0\\00a0\\e831\";\n}\n\n\n/*\n\tDefault debug view styles.\n*/\nhtml[data-debug-view] .debug {\n\tpadding: 0.25em;\n\tbackground-color: #234; /* #541, #151 */\n}\nhtml[data-debug-view] .debug[title] {\n\tcursor: help;\n}\nhtml[data-debug-view] .debug.block {\n\tdisplay: inline-block;\n\tvertical-align: middle;\n}\nhtml[data-debug-view] .debug.invalid {\n\ttext-decoration: line-through;\n}\nhtml[data-debug-view] .debug.hidden,\nhtml[data-debug-view] .debug.hidden .debug {\n\tbackground-color: #555;\n}\nhtml:not([data-debug-view]) .debug.hidden {\n\tdisplay: none;\n}\n\nhtml[data-debug-view] .debug[data-name][data-type]:before,\nhtml[data-debug-view] .debug[data-name][data-type].nonvoid:after {\n\tbackground-color: rgba(0,0,0,0.25);\n\tfont-family: monospace, monospace;\n\twhite-space: pre;\n}\nhtml[data-debug-view] .debug[data-name][data-type]:before {\n\tcontent: attr(data-name);\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"macro\"]:before {\n\tcontent: \"<<\" attr(data-name) \">>\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"macro\"].nonvoid:after {\n\tcontent: \"<</\" attr(data-name) \">>\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"html\"]:before {\n\tcontent: \"<\" attr(data-name) \">\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"html\"].nonvoid:after {\n\tcontent: \"</\" attr(data-name) \">\";\n}\nhtml[data-debug-view] .debug[data-name][data-type]:not(:empty):before {\n\tmargin-right: 0.25em;\n}\nhtml[data-debug-view] .debug[data-name][data-type].nonvoid:not(:empty):after {\n\tmargin-left: 0.25em;\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"special\"],\nhtml[data-debug-view] .debug[data-name][data-type|=\"special\"]:before {\n\tdisplay: block;\n}\n</style>\n</head>\n<body>\n\t<div id=\"init-screen\">\n\t\t<div id=\"init-no-js\"><noscript>JavaScript is required. Please enable it to continue.</noscript></div>\n\t\t<div id=\"init-lacking\">Your browser lacks required capabilities. Please upgrade it or switch to another to continue.</div>\n\t\t<div id=\"init-loading\"><div>Loading&hellip;</div></div>\n\t</div>\n\t{{STORY_DATA}}\n\t<script id=\"script-sugarcube\" type=\"text/javascript\">\n\t/*! SugarCube JS */\n\tif(document.documentElement.getAttribute(\"data-init\")===\"loading\"){window.TWINE1=false;\nwindow.DEBUG=false;\n(function (window, document, jQuery, undefined) {\n\"use strict\";\n\n/***********************************************************************************************************************\n\n\tlib/alert.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tTODO: This regular expression should be elsewhere.\n\n\tError prologs by engine/browser: (ca. 2018)\n\t\tChrome, Opera, & Vivaldi → `Uncaught \\w*Error: …`\n\t\tEdge & IE                → `…`\n\t\tFirefox                  → `Error: …`\n\t\tOpera (Presto)           → `Uncaught exception: \\w*(?:Error|Exception): …`\n\t\tSafari (ca. v5.1)        → `\\w*(?:Error|_ERR): …`\n*/\nvar errorPrologRegExp = /^(?:(?:uncaught\\s+(?:exception:\\s+)?)?\\w*(?:error|exception|_err):\\s+)+/i; // eslint-disable-line no-unused-vars, no-var\n\nvar Alert = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tError Functions.\n\t*******************************************************************************************************************/\n\tfunction _alertMesg(type, where, what, error) {\n\t\tconst isFatal = type === 'fatal';\n\t\tlet mesg = `Apologies! ${isFatal ? 'A fatal' : 'An'} error has occurred.`;\n\n\t\tif (isFatal) {\n\t\t\tmesg += ' Aborting.';\n\t\t}\n\t\telse {\n\t\t\tmesg += ' You may be able to continue, but some parts may not work properly.';\n\t\t}\n\n\t\tif (where != null || what != null) { // lazy equality for null\n\t\t\tmesg += '\\n\\nError';\n\n\t\t\tif (where != null) { // lazy equality for null\n\t\t\t\tmesg += ` [${where}]`;\n\t\t\t}\n\n\t\t\tif (what != null) { // lazy equality for null\n\t\t\t\tmesg += `: ${what.replace(errorPrologRegExp, '')}.`;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tmesg += ': unknown error.';\n\t\t\t}\n\t\t}\n\n\t\tif (typeof error === 'object' && error !== null && error.stack) {\n\t\t\tmesg += `\\n\\nStack Trace:\\n${error.stack}`;\n\t\t}\n\n\t\twindow.alert(mesg); // eslint-disable-line no-alert\n\t}\n\n\tfunction alertError(where, what, error) {\n\t\t_alertMesg(null, where, what, error);\n\t}\n\n\tfunction alertFatal(where, what, error) {\n\t\t_alertMesg('fatal', where, what, error);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tError Event.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSet up a global error handler for uncaught exceptions.\n\t*/\n\t(origOnError => {\n\t\twindow.onerror = function (what, source, lineNum, colNum, error) {\n\t\t\t// Uncaught exceptions during play may be recoverable/ignorable.\n\t\t\tif (document.readyState === 'complete') {\n\t\t\t\talertError(null, what, error);\n\t\t\t}\n\n\t\t\t// Uncaught exceptions during startup should be fatal.\n\t\t\telse {\n\t\t\t\talertFatal(null, what, error);\n\t\t\t\twindow.onerror = origOnError;\n\n\t\t\t\tif (typeof window.onerror === 'function') {\n\t\t\t\t\twindow.onerror.apply(this, arguments);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t})(window.onerror);\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\terror : { value : alertError },\n\t\tfatal : { value : alertFatal }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/patterns.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tTODO: Move all markup patterns into here.\n*/\n\nvar Patterns = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tPatterns.\n\t*******************************************************************************************************************/\n\t/*\n\t\tWhitespace patterns.\n\n\t\tSpace class (equivalent to `\\s`):\n\t\t\t[\\u0020\\f\\n\\r\\t\\v\\u00a0\\u1680\\u180e\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000\\ufeff]\n\t\tSpace class, sans line terminators:\n\t\t\t[\\u0020\\f\\t\\v\\u00a0\\u1680\\u180e\\u2000-\\u200a\\u202f\\u205f\\u3000\\ufeff]\n\t\tLine Terminator class:\n\t\t\t[\\n\\r\\u2028\\u2029]\n\t*/\n\tconst space = (() => {\n\t\t/*\n\t\t\tSome browsers still supported by SugarCube have faulty space classes (`\\s`).\n\t\t\tWe check for that lossage here and, if necessary, build our own class from\n\t\t\tthe component pieces.\n\t\t*/\n\t\tconst wsMap = new Map([\n\t\t\t['\\u0020', '\\\\u0020'],\n\t\t\t['\\f', '\\\\f'],\n\t\t\t['\\n', '\\\\n'],\n\t\t\t['\\r', '\\\\r'],\n\t\t\t['\\t', '\\\\t'],\n\t\t\t['\\v', '\\\\v'],\n\t\t\t['\\u00a0', '\\\\u00a0'],\n\t\t\t['\\u1680', '\\\\u1680'],\n\t\t\t['\\u180e', '\\\\u180e'],\n\t\t\t['\\u2000', '\\\\u2000'],\n\t\t\t['\\u2001', '\\\\u2001'],\n\t\t\t['\\u2002', '\\\\u2002'],\n\t\t\t['\\u2003', '\\\\u2003'],\n\t\t\t['\\u2004', '\\\\u2004'],\n\t\t\t['\\u2005', '\\\\u2005'],\n\t\t\t['\\u2006', '\\\\u2006'],\n\t\t\t['\\u2007', '\\\\u2007'],\n\t\t\t['\\u2008', '\\\\u2008'],\n\t\t\t['\\u2009', '\\\\u2009'],\n\t\t\t['\\u200a', '\\\\u200a'],\n\t\t\t['\\u2028', '\\\\u2028'],\n\t\t\t['\\u2029', '\\\\u2029'],\n\t\t\t['\\u202f', '\\\\u202f'],\n\t\t\t['\\u205f', '\\\\u205f'],\n\t\t\t['\\u3000', '\\\\u3000'],\n\t\t\t['\\ufeff', '\\\\ufeff']\n\t\t]);\n\t\tconst wsRe = /^\\s$/;\n\t\tlet missing = '';\n\n\t\twsMap.forEach((pat, char) => {\n\t\t\tif (!wsRe.test(char)) {\n\t\t\t\tmissing += pat;\n\t\t\t}\n\t\t});\n\n\t\treturn missing ? `[\\\\s${missing}]` : '\\\\s';\n\t})();\n\tconst spaceNoTerminator = '[\\\\u0020\\\\f\\\\t\\\\v\\\\u00a0\\\\u1680\\\\u180e\\\\u2000-\\\\u200a\\\\u202f\\\\u205f\\\\u3000\\\\ufeff]';\n\tconst lineTerminator    = '[\\\\n\\\\r\\\\u2028\\\\u2029]';\n\tconst notSpace          = space === '\\\\s' ? '\\\\S' : space.replace(/^\\[/, '[^');\n\n\t/*\n\t\tCharacter patterns.\n\t*/\n\tconst anyChar = `(?:.|${lineTerminator})`;\n\n\t/*\n\t\tLetter patterns.\n\n\t\tFIXME:\n\t\t\t1. The existing set, which is a TiddlyWiki holdover, should probably\n\t\t\t   encompass a significantly greater range of BMP code points.\n\t\t\t2. Should we include the surrogate pair code units (\\uD800-\\uDBFF &\n\t\t\t   \\uDC00-\\uDFFF) to handle non-BMP code points?  Further, should we\n\t\t\t   simply be checking for the code units themselves or checking for\n\t\t\t   properly mated pairs?\n\t*/\n\tconst anyLetter       = '[0-9A-Z_a-z\\\\-\\\\u00c0-\\\\u00d6\\\\u00d8-\\\\u00f6\\\\u00f8-\\\\u00ff\\\\u0150\\\\u0170\\\\u0151\\\\u0171]';\n\tconst anyLetterStrict = anyLetter.replace('\\\\-', ''); // anyLetter sans hyphen\n\n\t/*\n\t\tIdentifier patterns.\n\n\t\tNOTE: Since JavaScript's RegExp syntax does not support Unicode character\n\t\tclasses, the correct regular expression to match a valid identifier name,\n\t\twithin the scope of our needs, would be on the order of approximately 5–6\n\t\tor 11–16 KiB, depending on how the pattern was built.  That being the case,\n\t\tfor the moment we restrict valid TwineScript identifiers to US-ASCII.\n\n\t\tFIXME: Fix this to, at least, approximate the correct range.\n\t*/\n\tconst identifierFirstChar = '[$A-Z_a-z]';\n\tconst identifierNextChar  = '[$0-9A-Z_a-z]';\n\tconst identifier          = `${identifierFirstChar}${identifierNextChar}*`;\n\n\t// Variable patterns.\n\tconst variableSigil = '[$_]';\n\tconst variable      = variableSigil + identifier;\n\n\t// Macro name pattern.\n\tconst macroName = '[A-Za-z][\\\\w-]*|[=-]';\n\n\t// Template name pattern.\n\tconst templateName = '[A-Za-z][\\\\w-]*';\n\n\t// CSS ID or class sigil pattern.\n\tconst cssIdOrClassSigil = '[#.]';\n\n\t// CSS image transclusion template pattern.\n\t//\n\t// NOTE: The alignment syntax isn't supported, but removing it might break uses\n\t// of the template in the wild, so we leave it alone for now.\n\tconst cssImage = '\\\\[[<>]?[Ii][Mm][Gg]\\\\[(?:\\\\s|\\\\S)*?\\\\]\\\\]+';\n\n\t// Inline CSS pattern.\n\tconst inlineCss = (() => {\n\t\t/* legacy */\n\t\tconst twStyle   = `(${anyLetter}+)\\\\(([^\\\\)\\\\|\\\\n]+)\\\\):`;\n\t\t/* /legacy */\n\t\tconst cssStyle  = `${spaceNoTerminator}*(${anyLetter}+)${spaceNoTerminator}*:([^;\\\\|\\\\n]+);`;\n\t\tconst idOrClass = `${spaceNoTerminator}*((?:${cssIdOrClassSigil}${anyLetter}+${spaceNoTerminator}*)+);`;\n\n\t\t// [1,2] = style(value):\n\t\t// [3,4] = style:value;\n\t\t// [5]   = #id.className;\n\t\treturn `${twStyle}|${cssStyle}|${idOrClass}`;\n\t})();\n\n\t// URL pattern.\n\tconst url = '(?:file|https?|mailto|ftp|javascript|irc|news|data):[^\\\\s\\'\"]+';\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze({\n\t\tspace,\n\t\tspaceNoTerminator,\n\t\tlineTerminator,\n\t\tnotSpace,\n\t\tanyChar,\n\t\tanyLetter,\n\t\tanyLetterStrict,\n\t\tidentifierFirstChar,\n\t\tidentifierNextChar,\n\t\tidentifier,\n\t\tvariableSigil,\n\t\tvariable,\n\t\tmacroName,\n\t\ttemplateName,\n\t\tcssIdOrClassSigil,\n\t\tcssImage,\n\t\tinlineCss,\n\t\turl\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/extensions.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns */\n\n/*\n\tJavaScript Polyfills.\n\n\tNOTE: The ES5 and ES6 polyfills come from the vendored `es5-shim.js` and `es6-shim.js` libraries.\n*/\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tTrims whitespace from either the start or end of the given string.\n\t*/\n\tconst _trimString = (() => {\n\t\t// Whitespace regular expressions.\n\t\tconst startWSRe = new RegExp(`^${Patterns.space}${Patterns.space}*`);\n\t\tconst endWSRe   = new RegExp(`${Patterns.space}${Patterns.space}*$`);\n\n\t\tfunction trimString(str, where) {\n\t\t\tconst val = String(str);\n\n\t\t\tif (!val) {\n\t\t\t\treturn val;\n\t\t\t}\n\n\t\t\tswitch (where) {\n\t\t\tcase 'start':\n\t\t\t\treturn startWSRe.test(val) ? val.replace(startWSRe, '') : val;\n\n\t\t\tcase 'end':\n\t\t\t\treturn endWSRe.test(val) ? val.replace(endWSRe, '') : val;\n\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`_trimString called with incorrect where parameter value: \"${where}\"`);\n\t\t\t}\n\t\t}\n\n\t\treturn trimString;\n\t})();\n\n\t/*\n\t\tGenerates a pad string based upon the given string and length.\n\t*/\n\tfunction _createPadString(length, padding) {\n\t\tconst targetLength = Number.parseInt(length, 10) || 0;\n\n\t\tif (targetLength < 1) {\n\t\t\treturn '';\n\t\t}\n\n\t\tlet padString = typeof padding === 'undefined' ? '' : String(padding);\n\n\t\tif (padString === '') {\n\t\t\tpadString = ' ';\n\t\t}\n\n\t\twhile (padString.length < targetLength) {\n\t\t\tconst curPadLength    = padString.length;\n\t\t\tconst remainingLength = targetLength - curPadLength;\n\n\t\t\tpadString += curPadLength > remainingLength\n\t\t\t\t? padString.slice(0, remainingLength)\n\t\t\t\t: padString;\n\t\t}\n\n\t\tif (padString.length > targetLength) {\n\t\t\tpadString = padString.slice(0, targetLength);\n\t\t}\n\n\t\treturn padString;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPolyfills.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[ES2019] Returns a new array consisting of the source array with all sub-array elements\n\t\tconcatenated into it recursively up to the given depth.\n\t*/\n\tif (!Array.prototype.flat) {\n\t\tObject.defineProperty(Array.prototype, 'flat', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\t\t\tvalue        : (() => {\n\t\t\t\tfunction flat(/* depth */) {\n\t\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\t\tthrow new TypeError('Array.prototype.flat called on null or undefined');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst depth = arguments.length === 0 ? 1 : Number(arguments[0]) || 0;\n\n\t\t\t\t\tif (depth < 1) {\n\t\t\t\t\t\treturn Array.prototype.slice.call(this);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn Array.prototype.reduce.call(\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\t(acc, cur) => {\n\t\t\t\t\t\t\tif (cur instanceof Array) {\n\t\t\t\t\t\t\t\t// acc.push.apply(acc, flat.call(cur, depth - 1));\n\t\t\t\t\t\t\t\tacc.push(...flat.call(cur, depth - 1));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tacc.push(cur);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn acc;\n\t\t\t\t\t\t},\n\t\t\t\t\t\t[]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn flat;\n\t\t\t})()\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a new array consisting of the result of calling the given mapping function\n\t\ton every element in the source array and then concatenating all sub-array elements into it\n\t\trecursively up to a depth of `1`.  Identical to calling `<Array>.map(fn).flat()`.\n\t*/\n\tif (!Array.prototype.flatMap) {\n\t\tObject.defineProperty(Array.prototype, 'flatMap', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(/* callback [, thisArg] */) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Array.prototype.flatMap called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.map.apply(this, arguments).flat();\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2016] Returns whether the given element was found within the array.\n\t*/\n\tif (!Array.prototype.includes) {\n\t\tObject.defineProperty(Array.prototype, 'includes', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Array.prototype.includes called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tif (arguments.length === 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst length = this.length >>> 0;\n\n\t\t\t\tif (length === 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst needle = arguments[0];\n\t\t\t\tlet i = Number(arguments[1]) || 0;\n\n\t\t\t\tif (i < 0) {\n\t\t\t\t\ti = Math.max(0, length + i);\n\t\t\t\t}\n\n\t\t\t\tfor (/* empty */; i < length; ++i) {\n\t\t\t\t\tconst value = this[i];\n\n\t\t\t\t\tif (value === needle || value !== value && needle !== needle) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a new array consisting of the given object's own enumerable property/value\n\t\tpairs as `[key, value]` arrays.\n\t*/\n\tif (!Object.entries) {\n\t\tObject.defineProperty(Object, 'entries', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (typeof obj !== 'object' || obj === null) {\n\t\t\t\t\tthrow new TypeError('Object.entries object parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\treturn Object.keys(obj).map(key => [key, obj[key]]);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a new generic object consisting of the given list's key/value pairs.\n\t*/\n\tif (!Object.fromEntries) {\n\t\tObject.defineProperty(Object, 'fromEntries', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(iter) {\n\t\t\t\treturn Array.from(iter).reduce(\n\t\t\t\t\t(acc, pair) => {\n\t\t\t\t\t\tif (Object(pair) !== pair) {\n\t\t\t\t\t\t\tthrow new TypeError('Object.fromEntries iterable parameter must yield objects');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (pair[0] in acc) {\n\t\t\t\t\t\t\tObject.defineProperty(acc, pair[0], {\n\t\t\t\t\t\t\t\tconfigurable : true,\n\t\t\t\t\t\t\t\tenumerable   : true,\n\t\t\t\t\t\t\t\twritable     : true,\n\t\t\t\t\t\t\t\tvalue        : pair[1]\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tacc[pair[0]] = pair[1]; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{}\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns all own property descriptors of the given object.\n\t*/\n\tif (!Object.getOwnPropertyDescriptors) {\n\t\tObject.defineProperty(Object, 'getOwnPropertyDescriptors', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (obj == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Object.getOwnPropertyDescriptors object parameter is null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst O = Object(obj);\n\n\t\t\t\treturn Reflect.ownKeys(O).reduce(\n\t\t\t\t\t(acc, key) => {\n\t\t\t\t\t\tconst desc = Object.getOwnPropertyDescriptor(O, key);\n\n\t\t\t\t\t\tif (typeof desc !== 'undefined') {\n\t\t\t\t\t\t\tif (key in acc) {\n\t\t\t\t\t\t\t\tObject.defineProperty(acc, key, {\n\t\t\t\t\t\t\t\t\tconfigurable : true,\n\t\t\t\t\t\t\t\t\tenumerable   : true,\n\t\t\t\t\t\t\t\t\twritable     : true,\n\t\t\t\t\t\t\t\t\tvalue        : desc\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tacc[key] = desc; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{}\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a new array consisting of the given object's own enumerable property values.\n\t*/\n\tif (!Object.values) {\n\t\tObject.defineProperty(Object, 'values', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (typeof obj !== 'object' || obj === null) {\n\t\t\t\t\tthrow new TypeError('Object.values object parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\treturn Object.keys(obj).map(key => obj[key]);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a string based on concatenating the given padding, repeated as necessary,\n\t\tto the start of the string so that the given length is reached.\n\n\t\tNOTE: This pads based upon Unicode code units, rather than code points.\n\t*/\n\tif (!String.prototype.padStart) {\n\t\tObject.defineProperty(String.prototype, 'padStart', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(length, padding) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.padStart called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst baseString   = String(this);\n\t\t\t\tconst baseLength   = baseString.length;\n\t\t\t\tconst targetLength = Number.parseInt(length, 10);\n\n\t\t\t\tif (targetLength <= baseLength) {\n\t\t\t\t\treturn baseString;\n\t\t\t\t}\n\n\t\t\t\treturn _createPadString(targetLength - baseLength, padding) + baseString;\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a string based on concatenating the given padding, repeated as necessary,\n\t\tto the end of the string so that the given length is reached.\n\n\t\tNOTE: This pads based upon Unicode code units, rather than code points.\n\t*/\n\tif (!String.prototype.padEnd) {\n\t\tObject.defineProperty(String.prototype, 'padEnd', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(length, padding) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.padEnd called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst baseString   = String(this);\n\t\t\t\tconst baseLength   = baseString.length;\n\t\t\t\tconst targetLength = Number.parseInt(length, 10);\n\n\t\t\t\tif (targetLength <= baseLength) {\n\t\t\t\t\treturn baseString;\n\t\t\t\t}\n\n\t\t\t\treturn baseString + _createPadString(targetLength - baseLength, padding);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a string with all whitespace removed from the start of the string.\n\t*/\n\tif (!String.prototype.trimStart) {\n\t\tObject.defineProperty(String.prototype, 'trimStart', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimStart called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'start');\n\t\t\t}\n\t\t});\n\t}\n\n\tif (!String.prototype.trimLeft) {\n\t\tObject.defineProperty(String.prototype, 'trimLeft', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimLeft called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'start');\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a string with all whitespace removed from the end of the string.\n\t*/\n\tif (!String.prototype.trimEnd) {\n\t\tObject.defineProperty(String.prototype, 'trimEnd', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimEnd called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'end');\n\t\t\t}\n\t\t});\n\t}\n\n\tif (!String.prototype.trimRight) {\n\t\tObject.defineProperty(String.prototype, 'trimRight', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimRight called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'end');\n\t\t\t}\n\t\t});\n\t}\n})();\n\n\n/*\n\tJavaScript Extensions.\n*/\n(() => {\n\t'use strict';\n\n\tconst _nativeMathRandom = Math.random;\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a pseudo-random whole number (integer) within the given bounds.\n\t*/\n\tfunction _random(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('_random called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = arguments[0];\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = arguments[0];\n\t\t\tmax = arguments[1];\n\t\t\tbreak;\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn Math.floor(_nativeMathRandom() * (max - min + 1)) + min;\n\t}\n\n\t/*\n\t\tReturns a randomly selected index within the given length and bounds.\n\t\tBounds may be negative.\n\t*/\n\tfunction _randomIndex(length, boundsArgs) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (boundsArgs.length) {\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = length - 1;\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tmin = 0;\n\t\t\tmax = Math.trunc(boundsArgs[1]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Math.trunc(boundsArgs[1]);\n\t\t\tmax = Math.trunc(boundsArgs[2]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (Number.isNaN(min)) {\n\t\t\tmin = 0;\n\t\t}\n\t\telse if (!Number.isFinite(min) || min >= length) {\n\t\t\tmin = length - 1;\n\t\t}\n\t\telse if (min < 0) {\n\t\t\tmin = length + min;\n\n\t\t\tif (min < 0) {\n\t\t\t\tmin = 0;\n\t\t\t}\n\t\t}\n\n\t\tif (Number.isNaN(max)) {\n\t\t\tmax = 0;\n\t\t}\n\t\telse if (!Number.isFinite(max) || max >= length) {\n\t\t\tmax = length - 1;\n\t\t}\n\t\telse if (max < 0) {\n\t\t\tmax = length + max;\n\n\t\t\tif (max < 0) {\n\t\t\t\tmax = length - 1;\n\t\t\t}\n\t\t}\n\n\t\treturn _random(min, max);\n\t}\n\n\t/*\n\t\tReturns an object (`{ char, start, end }`) containing the Unicode character at\n\t\tposition `pos`, its starting position, and its ending position—surrogate pairs\n\t\tare properly handled.  If `pos` is out-of-bounds, returns an object containing\n\t\tthe empty string and start/end positions of `-1`.\n\n\t\tThis function is necessary because JavaScript strings are sequences of UTF-16\n\t\tcode units, so surrogate pairs are exposed and thus must be handled.  While the\n\t\tES6/2015 standard does improve the situation somewhat, it does not alleviate\n\t\tthe need for this function.\n\n\t\tNOTE: Will throw exceptions on invalid surrogate pairs.\n\n\t\tIDEA: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt\n\t*/\n\tfunction _getCodePointStartAndEnd(str, pos) {\n\t\tconst code = str.charCodeAt(pos);\n\n\t\t// Given position was out-of-bounds.\n\t\tif (Number.isNaN(code)) {\n\t\t\treturn { char : '', start : -1, end : -1 };\n\t\t}\n\n\t\t// Code unit is not a UTF-16 surrogate.\n\t\tif (code < 0xD800 || code > 0xDFFF) {\n\t\t\treturn {\n\t\t\t\tchar  : str.charAt(pos),\n\t\t\t\tstart : pos,\n\t\t\t\tend   : pos\n\t\t\t};\n\t\t}\n\n\t\t// Code unit is a high surrogate (D800–DBFF).\n\t\tif (code >= 0xD800 && code <= 0xDBFF) {\n\t\t\tconst nextPos = pos + 1;\n\n\t\t\t// End of string.\n\t\t\tif (nextPos >= str.length) {\n\t\t\t\tthrow new Error('high surrogate without trailing low surrogate');\n\t\t\t}\n\n\t\t\tconst nextCode = str.charCodeAt(nextPos);\n\n\t\t\t// Next code unit is not a low surrogate (DC00–DFFF).\n\t\t\tif (nextCode < 0xDC00 || nextCode > 0xDFFF) {\n\t\t\t\tthrow new Error('high surrogate without trailing low surrogate');\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tchar  : str.charAt(pos) + str.charAt(nextPos),\n\t\t\t\tstart : pos,\n\t\t\t\tend   : nextPos\n\t\t\t};\n\t\t}\n\n\t\t// Code unit is a low surrogate (DC00–DFFF) in the first position.\n\t\tif (pos === 0) {\n\t\t\tthrow new Error('low surrogate without leading high surrogate');\n\t\t}\n\n\t\tconst prevPos  = pos - 1;\n\t\tconst prevCode = str.charCodeAt(prevPos);\n\n\t\t// Previous code unit is not a high surrogate (D800–DBFF).\n\t\tif (prevCode < 0xD800 || prevCode > 0xDBFF) {\n\t\t\tthrow new Error('low surrogate without leading high surrogate');\n\t\t}\n\n\t\treturn {\n\t\t\tchar  : str.charAt(prevPos) + str.charAt(pos),\n\t\t\tstart : prevPos,\n\t\t\tend   : pos\n\t\t};\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, General.\n\t*******************************************************************************************************************/\n\t/*\n\t\tRandomly selects an element from the given array, or array-like object, and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array, 'random', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(array /* DEPRECATED: [, [min ,] max] */) {\n\t\t\tif (\n\t\t\t\t   typeof array !== 'object'\n\t\t\t\t|| array === null\n\t\t\t\t|| !Object.prototype.hasOwnProperty.call(array, 'length')\n\t\t\t) {\n\t\t\t\tthrow new TypeError('Array.random array parameter must be an array or array-lke object');\n\t\t\t}\n\n\t\t\tconst length = array.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, Array.prototype.slice.call(arguments, 1));\n\n\t\t\treturn array[index];\n\t\t}\n\t});\n\n\t/*\n\t\tConcatenates one or more unique elements to the end of the base array\n\t\tand returns the result as a new array.  Elements which are arrays will\n\t\tbe merged—i.e. their elements will be concatenated, rather than the\n\t\tarray itself.\n\t*/\n\tObject.defineProperty(Array.prototype, 'concatUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.concatUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst result = Array.from(this);\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tconst items   = Array.prototype.reduce.call(arguments, (prev, cur) => prev.concat(cur), []);\n\t\t\tconst addSize = items.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst push    = Array.prototype.push;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = items[i];\n\n\t\t\t\tif (indexOf.call(result, value) === -1) {\n\t\t\t\t\tpush.call(result, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number of times the given element was found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'count', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex ] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.count called on null or undefined');\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst needle  = arguments[0];\n\t\t\tlet pos   = Number(arguments[1]) || 0;\n\t\t\tlet count = 0;\n\n\t\t\twhile ((pos = indexOf.call(this, needle, pos)) !== -1) {\n\t\t\t\t++count;\n\t\t\t\t++pos;\n\t\t\t}\n\n\t\t\treturn count;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the given elements from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'delete', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.delete called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst needles       = Array.prototype.concat.apply([], arguments);\n\t\t\tconst needlesLength = needles.length;\n\t\t\tconst indices       = [];\n\n\t\t\tfor (let i = 0; i < length; ++i) {\n\t\t\t\tconst value = this[i];\n\n\t\t\t\tfor (let j = 0; j < needlesLength; ++j) {\n\t\t\t\t\tconst needle = needles[j];\n\n\t\t\t\t\tif (value === needle || value !== value && needle !== needle) {\n\t\t\t\t\t\tindices.push(i);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst result = [];\n\n\t\t\t// Copy the elements (in original order).\n\t\t\tfor (let i = 0, iend = indices.length; i < iend; ++i) {\n\t\t\t\tresult[i] = this[indices[i]];\n\t\t\t}\n\n\t\t\tconst splice = Array.prototype.splice;\n\n\t\t\t// Delete the elements (in reverse order).\n\t\t\tfor (let i = indices.length - 1; i >= 0; --i) {\n\t\t\t\tsplice.call(this, indices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the elements at the given indices from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'deleteAt', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* indices */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.deleteAt called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst splice     = Array.prototype.splice;\n\t\t\tconst cpyIndices = [\n\t\t\t\t...(new Set(\n\t\t\t\t\tArray.prototype.concat.apply([], arguments)\n\t\t\t\t\t\t// Map negative indices to their positive counterparts,\n\t\t\t\t\t\t// so the Set can properly filter out duplicates.\n\t\t\t\t\t\t.map(x => x < 0 ? Math.max(0, length + x) : x)\n\t\t\t\t)).values()\n\t\t\t];\n\t\t\tconst delIndices = [...cpyIndices].sort((a, b) => b - a);\n\t\t\tconst result     = [];\n\n\t\t\t// Copy the elements (in originally specified order).\n\t\t\tfor (let i = 0, iend = cpyIndices.length; i < iend; ++i) {\n\t\t\t\tresult[i] = this[cpyIndices[i]];\n\t\t\t}\n\n\t\t\t// Delete the elements (in descending numeric order).\n\t\t\tfor (let i = 0, iend = delIndices.length; i < iend; ++i) {\n\t\t\t\tsplice.call(this, delIndices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the elements that pass the test implemented\n\t\tby the given predicate function from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'deleteWith', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(predicate, thisArg) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.deleteWith called on null or undefined');\n\t\t\t}\n\t\t\tif (typeof predicate !== 'function') {\n\t\t\t\tthrow new Error('Array.prototype.deleteWith predicate parameter must be a function');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst splice  = Array.prototype.splice;\n\t\t\tconst indices = [];\n\t\t\tconst result  = [];\n\n\t\t\t// Copy the elements (in original order).\n\t\t\tfor (let i = 0; i < length; ++i) {\n\t\t\t\tif (predicate.call(thisArg, this[i], i, this)) {\n\t\t\t\t\tresult.push(this[i]);\n\t\t\t\t\tindices.push(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Delete the elements (in reverse order).\n\t\t\tfor (let i = indices.length - 1; i >= 0; --i) {\n\t\t\t\tsplice.call(this, indices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the first element from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'first', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.first called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn this[0];\n\t\t}\n\t});\n\n\t/*\n\t\tReturns whether all of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'includesAll', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.includesAll called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 1) {\n\t\t\t\tif (Array.isArray(arguments[0])) {\n\t\t\t\t\treturn Array.prototype.includesAll.apply(this, arguments[0]);\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = arguments.length; i < iend; ++i) {\n\t\t\t\tif (\n\t\t\t\t\t!Array.prototype.some.call(this, function (val) {\n\t\t\t\t\t\treturn val === this.val || val !== val && this.val !== this.val;\n\t\t\t\t\t}, { val : arguments[i] })\n\t\t\t\t) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns whether any of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'includesAny', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.includesAny called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 1) {\n\t\t\t\tif (Array.isArray(arguments[0])) {\n\t\t\t\t\treturn Array.prototype.includesAny.apply(this, arguments[0]);\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = arguments.length; i < iend; ++i) {\n\t\t\t\tif (\n\t\t\t\t\tArray.prototype.some.call(this, function (val) {\n\t\t\t\t\t\treturn val === this.val || val !== val && this.val !== this.val;\n\t\t\t\t\t}, { val : arguments[i] })\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the last element from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'last', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.last called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn this[length - 1];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly removes an element from the base array and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pluck', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* DEPRECATED: [min ,] max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pluck called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, [...arguments]);\n\n\t\t\treturn Array.prototype.splice.call(this, index, 1)[0];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly removes the given number of unique elements from the base array\n\t\tand returns the removed elements as a new array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pluckMany', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(wantSize) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pluckMany called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tlet want = Math.trunc(wantSize);\n\n\t\t\tif (!Number.isInteger(want)) {\n\t\t\t\tthrow new Error('Array.prototype.pluckMany want parameter must be an integer');\n\t\t\t}\n\n\t\t\tif (want < 1) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif (want > length) {\n\t\t\t\twant = length;\n\t\t\t}\n\n\t\t\tconst splice = Array.prototype.splice;\n\t\t\tconst result = [];\n\t\t\tlet max = length - 1;\n\n\t\t\tdo {\n\t\t\t\tresult.push(splice.call(this, _random(0, max--), 1)[0]);\n\t\t\t} while (result.length < want);\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tAppends one or more unique elements to the end of the base array and\n\t\treturns its new length.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pushUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pushUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst addSize = arguments.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn this.length >>> 0;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst push    = Array.prototype.push;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = arguments[i];\n\n\t\t\t\tif (indexOf.call(this, value) === -1) {\n\t\t\t\t\tpush.call(this, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.length >>> 0;\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly selects an element from the base array and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array.prototype, 'random', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* DEPRECATED: [min ,] max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.random called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, [...arguments]);\n\n\t\t\treturn this[index];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly selects the given number of unique elements from the base array\n\t\tand returns the selected elements as a new array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'randomMany', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(wantSize) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.randomMany called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tlet want = Math.trunc(wantSize);\n\n\t\t\tif (!Number.isInteger(want)) {\n\t\t\t\tthrow new Error('Array.prototype.randomMany want parameter must be an integer');\n\t\t\t}\n\n\t\t\tif (want < 1) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif (want > length) {\n\t\t\t\twant = length;\n\t\t\t}\n\n\t\t\tconst picked = new Map();\n\t\t\tconst result = [];\n\t\t\tconst max    = length - 1;\n\n\t\t\tdo {\n\t\t\t\tlet i;\n\t\t\t\tdo {\n\t\t\t\t\ti = _random(0, max);\n\t\t\t\t} while (picked.has(i));\n\t\t\t\tpicked.set(i, true);\n\t\t\t\tresult.push(this[i]);\n\t\t\t} while (result.length < want);\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly shuffles the array and returns it.\n\t*/\n\tObject.defineProperty(Array.prototype, 'shuffle', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.shuffle called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tfor (let i = length - 1; i > 0; --i) {\n\t\t\t\tconst j = Math.floor(_nativeMathRandom() * (i + 1));\n\n\t\t\t\tif (i === j) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// [this[i], this[j]] = [this[j], this[i]];\n\t\t\t\tconst swap = this[i];\n\t\t\t\tthis[i] = this[j];\n\t\t\t\tthis[j] = swap;\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\t});\n\n\t/*\n\t\tPrepends one or more unique elements to the beginning of the base array\n\t\tand returns its new length.\n\t*/\n\tObject.defineProperty(Array.prototype, 'unshiftUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.unshiftUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst addSize = arguments.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn this.length >>> 0;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst unshift = Array.prototype.unshift;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = arguments[i];\n\n\t\t\t\tif (indexOf.call(this, value) === -1) {\n\t\t\t\t\tunshift.call(this, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.length >>> 0;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a bound function that supplies the given arguments to the base\n\t\tfunction, followed by the arguments are supplied to the bound function,\n\t\twhenever it is called.\n\t*/\n\tObject.defineProperty(Function.prototype, 'partial', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Function.prototype.partial called on null or undefined');\n\t\t\t}\n\n\t\t\tconst slice = Array.prototype.slice;\n\t\t\tconst fn    = this;\n\t\t\tconst bound = slice.call(arguments, 0);\n\n\t\t\treturn function () {\n\t\t\t\tconst applied = [];\n\t\t\t\tlet argc = 0;\n\n\t\t\t\tfor (let i = 0; i < bound.length; ++i) {\n\t\t\t\t\tapplied.push(bound[i] === undefined ? arguments[argc++] : bound[i]);\n\t\t\t\t}\n\n\t\t\t\treturn fn.apply(this, applied.concat(slice.call(arguments, argc)));\n\t\t\t};\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the given numerical clamped to the specified bounds.\n\t*/\n\tObject.defineProperty(Math, 'clamp', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(num, min, max) {\n\t\t\tconst value = Number(num);\n\t\t\treturn Number.isNaN(value) ? NaN : value.clamp(min, max);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a decimal number eased from 0 to 1.\n\n\t\tNOTE: The magnitude of the returned value decreases if num < 0.5 or increases if num > 0.5.\n\t*/\n\tObject.defineProperty(Math, 'easeInOut', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(num) {\n\t\t\treturn 1 - (Math.cos(Number(num) * Math.PI) + 1) / 2;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number clamped to the specified bounds.\n\t*/\n\tObject.defineProperty(Number.prototype, 'clamp', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* min, max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Number.prototype.clamp called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length !== 2) {\n\t\t\t\tthrow new Error('Number.prototype.clamp called with an incorrect number of parameters');\n\t\t\t}\n\n\t\t\tlet min = Number(arguments[0]);\n\t\t\tlet max = Number(arguments[1]);\n\n\t\t\tif (min > max) {\n\t\t\t\t[min, max] = [max, min];\n\t\t\t}\n\n\t\t\treturn Math.min(Math.max(this, min), max);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the given string with all RegExp metacharacters escaped.\n\t*/\n\tif (!RegExp.escape) {\n\t\t(() => {\n\t\t\tconst _regExpMetaCharsRe    = /[\\\\^$*+?.()|[\\]{}]/g;\n\t\t\tconst _hasRegExpMetaCharsRe = new RegExp(_regExpMetaCharsRe.source); // to drop the global flag\n\n\t\t\tObject.defineProperty(RegExp, 'escape', {\n\t\t\t\tconfigurable : true,\n\t\t\t\twritable     : true,\n\n\t\t\t\tvalue(str) {\n\t\t\t\t\tconst val = String(str);\n\t\t\t\t\treturn val && _hasRegExpMetaCharsRe.test(val)\n\t\t\t\t\t\t? val.replace(_regExpMetaCharsRe, '\\\\$&')\n\t\t\t\t\t\t: val;\n\t\t\t\t}\n\t\t\t});\n\t\t})();\n\t}\n\n\t/*\n\t\tReturns a formatted string, after replacing each format item in the given\n\t\tformat string with the text equivalent of the corresponding argument's value.\n\t*/\n\t(() => {\n\t\tconst _formatRegExp    = /{(\\d+)(?:,([+-]?\\d+))?}/g;\n\t\tconst _hasFormatRegExp = new RegExp(_formatRegExp.source); // to drop the global flag\n\n\t\tObject.defineProperty(String, 'format', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(format) {\n\t\t\t\tfunction padString(str, align, pad) {\n\t\t\t\t\tif (!align) {\n\t\t\t\t\t\treturn str;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst plen = Math.abs(align) - str.length;\n\n\t\t\t\t\tif (plen < 1) {\n\t\t\t\t\t\treturn str;\n\t\t\t\t\t}\n\n\t\t\t\t\t// const padding = Array(plen + 1).join(pad);\n\t\t\t\t\tconst padding = String(pad).repeat(plen);\n\t\t\t\t\treturn align < 0 ? str + padding : padding + str;\n\t\t\t\t}\n\n\t\t\t\tif (arguments.length < 2) {\n\t\t\t\t\treturn arguments.length === 0 ? '' : format;\n\t\t\t\t}\n\n\t\t\t\tconst args = arguments.length === 2 && Array.isArray(arguments[1])\n\t\t\t\t\t? [...arguments[1]]\n\t\t\t\t\t: Array.prototype.slice.call(arguments, 1);\n\n\t\t\t\tif (args.length === 0) {\n\t\t\t\t\treturn format;\n\t\t\t\t}\n\n\t\t\t\tif (!_hasFormatRegExp.test(format)) {\n\t\t\t\t\treturn format;\n\t\t\t\t}\n\n\t\t\t\t// Possibly required by some old buggy browsers.\n\t\t\t\t_formatRegExp.lastIndex = 0;\n\n\t\t\t\treturn format.replace(_formatRegExp, (match, index, align) => {\n\t\t\t\t\tlet retval = args[index];\n\n\t\t\t\t\tif (retval == null) { // lazy equality for null\n\t\t\t\t\t\treturn '';\n\t\t\t\t\t}\n\n\t\t\t\t\twhile (typeof retval === 'function') {\n\t\t\t\t\t\tretval = retval();\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (typeof retval) {\n\t\t\t\t\tcase 'string': /* no-op */ break;\n\t\t\t\t\tcase 'object': retval = JSON.stringify(retval); break;\n\t\t\t\t\tdefault:       retval = String(retval); break;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn padString(retval, !align ? 0 : Number.parseInt(align, 10), ' ');\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t})();\n\n\t/*\n\t\tReturns whether the given string was found within the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'contains', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.contains called on null or undefined');\n\t\t\t}\n\n\t\t\treturn String.prototype.indexOf.apply(this, arguments) !== -1;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number of times the given substring was found within the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'count', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex ] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.count called on null or undefined');\n\t\t\t}\n\n\t\t\tconst needle = String(arguments[0] || '');\n\n\t\t\tif (needle === '') {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tconst indexOf = String.prototype.indexOf;\n\t\t\tconst step    = needle.length;\n\t\t\tlet pos     = Number(arguments[1]) || 0;\n\t\t\tlet count   = 0;\n\n\t\t\twhile ((pos = indexOf.call(this, needle, pos)) !== -1) {\n\t\t\t\t++count;\n\t\t\t\tpos += step;\n\t\t\t}\n\n\t\t\treturn count;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the first Unicode code point from the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'first', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.first called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn char;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the last Unicode code point from the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'last', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.last called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the last code point—may be one or two code units—and its end position.\n\t\t\tconst { char } = _getCodePointStartAndEnd(str, str.length - 1);\n\n\t\t\treturn char;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with `delCount` characters replaced with\n\t\t`replacement`, starting at `startAt`.\n\t*/\n\tObject.defineProperty(String.prototype, 'splice', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(startAt, delCount, replacement) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.splice called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tlet start = Number(startAt);\n\n\t\t\tif (!Number.isSafeInteger(start)) {\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t\telse if (start < 0) {\n\t\t\t\tstart += length;\n\n\t\t\t\tif (start < 0) {\n\t\t\t\t\tstart = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (start > length) {\n\t\t\t\tstart = length;\n\t\t\t}\n\n\t\t\tlet count = Number(delCount);\n\n\t\t\tif (!Number.isSafeInteger(count) || count < 0) {\n\t\t\t\tcount = 0;\n\t\t\t}\n\n\t\t\tlet res = this.slice(0, start);\n\n\t\t\tif (typeof replacement !== 'undefined') {\n\t\t\t\tres += replacement;\n\t\t\t}\n\n\t\t\tif (start + count < length) {\n\t\t\t\tres += this.slice(start + count);\n\t\t\t}\n\n\t\t\treturn res;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns an array of strings, split from the string, or an empty array if the\n\t\tstring is empty.\n\t*/\n\tObject.defineProperty(String.prototype, 'splitOrEmpty', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* [ separator [, limit ]] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.splitOrEmpty called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tif (String(this) === '') {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\treturn String.prototype.split.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with the first Unicode code point uppercased,\n\t\taccording to any locale-specific rules.\n\t*/\n\tObject.defineProperty(String.prototype, 'toLocaleUpperFirst', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.toLocaleUpperFirst called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char, end } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn end === -1 ? '' : char.toLocaleUpperCase() + str.slice(end + 1);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with the first Unicode code point uppercased.\n\t*/\n\tObject.defineProperty(String.prototype, 'toUpperFirst', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.toUpperFirst called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char, end } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn end === -1 ? '' : char.toUpperCase() + str.slice(end + 1);\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, JSON.\n\t*******************************************************************************************************************/\n\t/*\n\t\tDefine `toJSON()` methods on each prototype we wish to support.\n\t*/\n\tObject.defineProperty(Date.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:date)', this.toISOString()];\n\t\t}\n\t});\n\tObject.defineProperty(Function.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\t/*\n\t\t\t\tThe enclosing parenthesis here are necessary to force the function expression code\n\t\t\t\tstring, returned by `this.toString()`, to be evaluated as an expression during\n\t\t\t\trevival.  Without them, the function expression, which is likely nameless, will be\n\t\t\t\tevaluated as a function definition—which will throw a syntax error exception, since\n\t\t\t\tfunction definitions must have a name.\n\t\t\t*/\n\t\t\treturn ['(revive:eval)', `(${this.toString()})`];\n\t\t}\n\t});\n\tObject.defineProperty(Map.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:map)', [...this]];\n\t\t}\n\t});\n\tObject.defineProperty(RegExp.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:eval)', this.toString()];\n\t\t}\n\t});\n\tObject.defineProperty(Set.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:set)', [...this]];\n\t\t}\n\t});\n\n\t/*\n\t\tUtility method to allow users to easily wrap their code in the revive wrapper.\n\t*/\n\tObject.defineProperty(JSON, 'reviveWrapper', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(code, data) {\n\t\t\tif (typeof code !== 'string') {\n\t\t\t\tthrow new TypeError('JSON.reviveWrapper code parameter must be a string');\n\t\t\t}\n\n\t\t\treturn ['(revive:eval)', [code, data]];\n\t\t}\n\t});\n\n\t/*\n\t\tBackup the original `JSON.parse()` and replace it with a revive wrapper aware version.\n\t*/\n\tObject.defineProperty(JSON, '_real_parse', {\n\t\tvalue : JSON.parse\n\t});\n\tObject.defineProperty(JSON, 'parse', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(text, reviver) {\n\t\t\treturn JSON._real_parse(text, (key, val) => {\n\t\t\t\tlet value = val;\n\n\t\t\t\t/*\n\t\t\t\t\tAttempt to revive wrapped values.\n\t\t\t\t*/\n\t\t\t\tif (Array.isArray(value) && value.length === 2) {\n\t\t\t\t\tswitch (value[0]) {\n\t\t\t\t\tcase '(revive:set)':\n\t\t\t\t\t\tvalue = new Set(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:map)':\n\t\t\t\t\t\tvalue = new Map(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:date)':\n\t\t\t\t\t\tvalue = new Date(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:eval)':\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t/* eslint-disable no-eval */\n\t\t\t\t\t\t\t// For post-v2.9.0 `JSON.reviveWrapper()`.\n\t\t\t\t\t\t\tif (Array.isArray(value[1])) {\n\t\t\t\t\t\t\t\tconst $ReviveData$ = value[1][1]; // eslint-disable-line no-unused-vars\n\t\t\t\t\t\t\t\tvalue = eval(value[1][0]);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// For regular expressions, functions, and pre-v2.9.0 `JSON.reviveWrapper()`.\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tvalue = eval(value[1]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/* eslint-enable no-eval */\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* legacy */\n\t\t\t\telse if (typeof value === 'string' && value.slice(0, 10) === '@@revive@@') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvalue = eval(value.slice(10)); // eslint-disable-line no-eval\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t}\n\t\t\t\t/* /legacy */\n\n\t\t\t\t/*\n\t\t\t\t\tCall the custom reviver, if specified.\n\t\t\t\t*/\n\t\t\t\tif (typeof reviver === 'function') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvalue = reviver(key, value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t}\n\n\t\t\t\treturn value;\n\t\t\t});\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, Deprecated.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Returns whether the given element was found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'contains', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.contains called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns whether all of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'containsAll', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.containsAll called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includesAll.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns whether any of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'containsAny', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.containsAny called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includesAny.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns a new array consisting of the flattened source array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'flatten', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.flatten called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.flat.call(this, Infinity);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns an array of link titles, parsed from the string.\n\n\t\tNOTE: Unused in SugarCube, only included for compatibility.\n\t*/\n\tObject.defineProperty(String.prototype, 'readBracketedList', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.readBracketedList called on null or undefined');\n\t\t\t}\n\n\t\t\t// RegExp groups: Double-square-bracket quoted | Unquoted.\n\t\t\tconst re    = new RegExp('(?:\\\\[\\\\[((?:\\\\s|\\\\S)*?)\\\\]\\\\])|([^\"\\'\\\\s]\\\\S*)', 'gm');\n\t\t\tconst names = [];\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this)) !== null) {\n\t\t\t\tif (match[1]) { // double-square-bracket quoted\n\t\t\t\t\tnames.push(match[1]);\n\t\t\t\t}\n\t\t\t\telse if (match[2]) { // unquoted\n\t\t\t\t\tnames.push(match[2]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn names;\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/browser.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar Browser = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/* eslint-disable max-len */\n\tconst userAgent = navigator.userAgent.toLowerCase();\n\n\tconst winPhone = userAgent.includes('windows phone');\n\tconst isMobile = Object.freeze({\n\t\tAndroid    : !winPhone && userAgent.includes('android'),\n\t\tBlackBerry : /blackberry|bb10/.test(userAgent),\n\t\tiOS        : !winPhone && /ip(?:hone|ad|od)/.test(userAgent),\n\t\tOpera      : !winPhone && (typeof window.operamini === 'object' || userAgent.includes('opera mini')),\n\t\tWindows    : winPhone || /iemobile|wpdesktop/.test(userAgent),\n\n\t\tany() {\n\t\t\treturn isMobile.Android || isMobile.BlackBerry || isMobile.iOS || isMobile.Opera || isMobile.Windows;\n\t\t}\n\t});\n\n\tconst isGecko = !isMobile.Windows && !/khtml|trident|edge/.test(userAgent) && userAgent.includes('gecko');\n\n\tconst isIE      = !userAgent.includes('opera') && /msie|trident/.test(userAgent);\n\tconst ieVersion = isIE\n\t\t? (() => {\n\t\t\tconst ver = /(?:msie\\s+|rv:)(\\d+\\.\\d)/.exec(userAgent);\n\t\t\treturn ver ? Number(ver[1]) : 0;\n\t\t})()\n\t\t: null;\n\n\t// opera <= 12: \"opera/9.80 (windows nt 6.1; wow64) presto/2.12.388 version/12.16\"\n\t// opera >= 15: \"mozilla/5.0 (windows nt 6.1; wow64) applewebkit/537.36 (khtml, like gecko) chrome/28.0.1500.52 safari/537.36 opr/15.0.1147.130\"\n\tconst isOpera      = userAgent.includes('opera') || userAgent.includes(' opr/');\n\tconst operaVersion = isOpera\n\t\t? (() => {\n\t\t\tconst re  = new RegExp(`${/khtml|chrome/.test(userAgent) ? 'opr' : 'version'}\\\\/(\\\\d+\\\\.\\\\d+)`);\n\t\t\tconst ver = re.exec(userAgent);\n\t\t\treturn ver ? Number(ver[1]) : 0;\n\t\t})()\n\t\t: null;\n\n\tconst isVivaldi = userAgent.includes('vivaldi');\n\t/* eslint-enable max-len */\n\n\t// Module Exports.\n\treturn Object.freeze({\n\t\tuserAgent,\n\t\tisMobile,\n\t\tisGecko,\n\t\tisIE,\n\t\tieVersion,\n\t\tisOpera,\n\t\toperaVersion,\n\t\tisVivaldi\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/has.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser */\n\nvar Has = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tNOTE: The aggressive try/catch feature tests are necessitated by implementation\n\t\tbugs in various browsers.\n\t*/\n\n\t// Is the `HTMLAudioElement` API available?\n\tconst hasAudioElement = (() => {\n\t\ttry {\n\t\t\treturn typeof document.createElement('audio').canPlayType === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `File` API available?\n\tconst hasFile = (() => {\n\t\ttry {\n\t\t\treturn 'Blob' in window &&\n\t\t\t\t'File' in window &&\n\t\t\t\t'FileList' in window &&\n\t\t\t\t'FileReader' in window &&\n\t\t\t\t!Browser.isMobile.any() &&\n\t\t\t\t(!Browser.isOpera || Browser.operaVersion >= 15);\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `geolocation` API available?\n\tconst hasGeolocation = (() => {\n\t\ttry {\n\t\t\treturn 'geolocation' in navigator &&\n\t\t\t\ttypeof navigator.geolocation.getCurrentPosition === 'function' &&\n\t\t\t\ttypeof navigator.geolocation.watchPosition === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `MutationObserver` API available?\n\tconst hasMutationObserver = (() => {\n\t\ttry {\n\t\t\treturn 'MutationObserver' in window &&\n\t\t\t\ttypeof window.MutationObserver === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `performance` API available?\n\tconst hasPerformance = (() => {\n\t\ttry {\n\t\t\treturn 'performance' in window &&\n\t\t\t\ttypeof window.performance.now === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the platform a touch device?\n\tconst hasTouch = (() => {\n\t\ttry {\n\t\t\treturn 'ontouchstart' in window ||\n\t\t\t\t!!window.DocumentTouch &&\n\t\t\t\tdocument instanceof window.DocumentTouch ||\n\t\t\t\t!!navigator.maxTouchPoints ||\n\t\t\t\t!!navigator.msMaxTouchPoints;\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the transition end event available and by what name?\n\tconst hasTransitionEndEvent = (() => {\n\t\ttry {\n\t\t\tconst teMap = new Map([\n\t\t\t\t['transition',       'transitionend'],\n\t\t\t\t['MSTransition',     'msTransitionEnd'],\n\t\t\t\t['WebkitTransition', 'webkitTransitionEnd'],\n\t\t\t\t['MozTransition',    'transitionend']\n\t\t\t]);\n\t\t\tconst teKeys = [...teMap.keys()];\n\t\t\tconst el     = document.createElement('div');\n\n\t\t\tfor (let i = 0; i < teKeys.length; ++i) {\n\t\t\t\tif (el.style[teKeys[i]] !== undefined) {\n\t\t\t\t\treturn teMap.get(teKeys[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Module Exports.\n\treturn Object.freeze({\n\t\taudio              : hasAudioElement,\n\t\tfileAPI            : hasFile,\n\t\tgeolocation        : hasGeolocation,\n\t\tmutationObserver   : hasMutationObserver,\n\t\tperformance        : hasPerformance,\n\t\ttouch              : hasTouch,\n\t\ttransitionEndEvent : hasTransitionEndEvent\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/visibility.js\n\n\tCopyright © 2018–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar Visibility = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tThere are two versions of the Page Visibility API: First Edition and, the current,\n\t\tSecond Edition (i.e. \"Level 2\").  First Edition is mentioned here only because some\n\t\tolder browsers implement it, rather than the current specification.\n\n\t\tSEE:\n\t\t\tSecond Edition : https://www.w3.org/TR/page-visibility/\n\t\t\tFirst Edition  : https://www.w3.org/TR/2013/REC-page-visibility-20130514/\n\n\t\tNOTE: Generally, all supported browsers change the visibility state when either switching tabs\n\t\twithin the browser or minimizing the browser window.  Exceptions are noted below:\n\t\t\t* IE 9 doesn't support either version of the Page Visibility API.\n\t\t\t* Opera 12 (Presto) doesn't change the visibility state when the browser is minimized.\n\t*/\n\n\t// Vendor properties object.\n\tconst vendor = (() => {\n\t\ttry {\n\t\t\treturn Object.freeze([\n\t\t\t\t// Specification.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'hidden',          // boolean; historical in 2nd edition\n\t\t\t\t\tstateProperty  : 'visibilityState', // string, values: 'hidden', 'visible'; 1st edition had more values\n\t\t\t\t\tchangeEvent    : 'visibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `webkit` prefixed: old Blink & WebKit.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'webkitHidden',\n\t\t\t\t\tstateProperty  : 'webkitVisibilityState',\n\t\t\t\t\tchangeEvent    : 'webkitvisibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `moz` prefixed: old Gecko, maybe Seamonkey.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'mozHidden',\n\t\t\t\t\tstateProperty  : 'mozVisibilityState',\n\t\t\t\t\tchangeEvent    : 'mozvisibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `ms` prefixed: IE 10.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'msHidden',\n\t\t\t\t\tstateProperty  : 'msVisibilityState',\n\t\t\t\t\tchangeEvent    : 'msvisibilitychange'\n\t\t\t\t}\n\t\t\t].find(vnd => vnd.hiddenProperty in document));\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn undefined;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tAPI Functions.\n\t*******************************************************************************/\n\n\tfunction getVendor() {\n\t\treturn vendor;\n\t}\n\n\tfunction getVisibility() {\n\t\treturn vendor && document[vendor.stateProperty] || 'visible';\n\t}\n\n\tfunction isEnabled() {\n\t\treturn Boolean(vendor);\n\t}\n\n\tfunction isHidden() {\n\t\t// return Boolean(vendor && document[vendor.stateProperty] === 'hidden');\n\t\treturn Boolean(vendor && document[vendor.hiddenProperty]); // NOTE: Historical, but probably better for 1st edition.\n\t}\n\n\n\t/*******************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Functions.\n\t\tvendor    : { get : getVendor },\n\t\tstate     : { get : getVisibility },\n\t\tisEnabled : { value : isEnabled },\n\t\tisHidden  : { value : isHidden },\n\n\t\t// Properties.\n\t\thiddenProperty : { value : vendor && vendor.hiddenProperty },\n\t\tstateProperty  : { value : vendor && vendor.stateProperty },\n\t\tchangeEvent    : { value : vendor && vendor.changeEvent }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/fullscreen.js\n\n\tCopyright © 2018–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser */\n\nvar Fullscreen = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tSEE:\n\t\t\thttps://fullscreen.spec.whatwg.org\n\t\t\thttps://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API\n\t*/\n\n\t// Vendor properties object.\n\tconst vendor = (() => {\n\t\ttry {\n\t\t\treturn Object.freeze([\n\t\t\t\t// Specification.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'fullscreenEnabled',\n\t\t\t\t\telement     : 'fullscreenElement',\n\t\t\t\t\trequestFn   : 'requestFullscreen',\n\t\t\t\t\texitFn      : 'exitFullscreen',\n\t\t\t\t\tchangeEvent : 'fullscreenchange', // prop: onfullscreenchange\n\t\t\t\t\terrorEvent  : 'fullscreenerror'   // prop: onfullscreenerror\n\t\t\t\t},\n\n\t\t\t\t// `webkit` prefixed: old Blink, WebKit, & Edge.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'webkitFullscreenEnabled',\n\t\t\t\t\telement     : 'webkitFullscreenElement',\n\t\t\t\t\trequestFn   : 'webkitRequestFullscreen',\n\t\t\t\t\texitFn      : 'webkitExitFullscreen',\n\t\t\t\t\tchangeEvent : 'webkitfullscreenchange',\n\t\t\t\t\terrorEvent  : 'webkitfullscreenerror'\n\t\t\t\t},\n\n\t\t\t\t// `moz` prefixed: old Gecko, maybe Seamonkey.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'mozFullScreenEnabled',\n\t\t\t\t\telement     : 'mozFullScreenElement',\n\t\t\t\t\trequestFn   : 'mozRequestFullScreen',\n\t\t\t\t\texitFn      : 'mozCancelFullScreen',\n\t\t\t\t\tchangeEvent : 'mozfullscreenchange',\n\t\t\t\t\terrorEvent  : 'mozfullscreenerror'\n\t\t\t\t},\n\n\t\t\t\t// `ms` prefixed: IE 11.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'msFullscreenEnabled',\n\t\t\t\t\telement     : 'msFullscreenElement',\n\t\t\t\t\trequestFn   : 'msRequestFullscreen',\n\t\t\t\t\texitFn      : 'msExitFullscreen',\n\t\t\t\t\tchangeEvent : 'MSFullscreenChange',\n\t\t\t\t\terrorEvent  : 'MSFullscreenError'\n\t\t\t\t}\n\t\t\t].find(vnd => vnd.isEnabled in document));\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn undefined;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tFeature Detection Functions.\n\t*******************************************************************************/\n\n\t// Return whether the request and exit fullscreen methods return a `Promise`.\n\t//\n\t// NOTE: The initial result is cached for future calls.\n\tconst _returnsPromise = (function () {\n\t\t// Cache of whether the request and exit methods return a `Promise`.\n\t\tlet _hasPromise = null;\n\n\t\tfunction _returnsPromise() {\n\t\t\tif (_hasPromise !== null) {\n\t\t\t\treturn _hasPromise;\n\t\t\t}\n\n\t\t\t_hasPromise = false;\n\n\t\t\tif (vendor) {\n\t\t\t\ttry {\n\t\t\t\t\tconst value = document.exitFullscreen();\n\n\t\t\t\t\t// Silence \"Uncaught (in promise)\" console errors from Blink.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: Swallowing errors is generally bad, but in this case we know there's\n\t\t\t\t\t// going to be an error regardless, since we shouldn't be in fullscreen yet,\n\t\t\t\t\t// and we don't actually care about the error, since we just want the return\n\t\t\t\t\t// value, so we consign it to the bit bucket.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: We don't ensure that the return value is not `undefined` here because\n\t\t\t\t\t// having the attempted call to `<Promise>.catch()` on an `undefined` value throw\n\t\t\t\t\t// is acceptable, since it will be caught and `false` eventually returned.\n\t\t\t\t\tvalue.catch(() => { /* no-op */ });\n\n\t\t\t\t\t_hasPromise = value instanceof Promise;\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t}\n\n\t\t\treturn _hasPromise;\n\t\t}\n\n\t\treturn _returnsPromise;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************/\n\n\tfunction _selectElement(requestedEl) {\n\t\tlet selectedEl = requestedEl || document.documentElement;\n\n\t\t// Document element scrolling workaround for older browsers.\n\t\tif (\n\t\t\t   selectedEl === document.documentElement\n\t\t\t&& (\n\t\t\t\t   vendor.requestFn === 'msRequestFullscreen'   // IE 11\n\t\t\t\t|| Browser.isOpera && Browser.operaVersion < 15 // Opera 12 (Presto)\n\t\t\t)\n\t\t) {\n\t\t\tselectedEl = document.body;\n\t\t}\n\n\t\treturn selectedEl;\n\t}\n\n\n\t/*******************************************************************************\n\t\tAPI Functions.\n\t*******************************************************************************/\n\n\tfunction getVendor() {\n\t\treturn vendor;\n\t}\n\n\tfunction getElement() {\n\t\treturn (vendor || null) && document[vendor.element];\n\t}\n\n\tfunction isEnabled() {\n\t\treturn Boolean(vendor && document[vendor.isEnabled]);\n\t}\n\n\tfunction isFullscreen() {\n\t\treturn Boolean(vendor && document[vendor.element]);\n\t}\n\n\tfunction requestFullscreen(options, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn Promise.reject(new Error('fullscreen not supported'));\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (typeof element[vendor.requestFn] !== 'function') {\n\t\t\treturn Promise.reject(new Error('fullscreen not supported'));\n\t\t}\n\t\tif (isFullscreen()) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tif (_returnsPromise()) {\n\t\t\treturn element[vendor.requestFn](options);\n\t\t}\n\t\telse { // eslint-disable-line no-else-return\n\t\t\tconst namespace = '.Fullscreen_requestFullscreen';\n\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tjQuery(element)\n\t\t\t\t\t.off(namespace)\n\t\t\t\t\t.one(`${vendor.errorEvent}${namespace} ${vendor.changeEvent}${namespace}`, ev => {\n\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\tif (ev.type === vendor.errorEvent) {\n\t\t\t\t\t\t\treject(new Error('unknown fullscreen request error'));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\telement[vendor.requestFn](options);\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction exitFullscreen() {\n\t\tif (!vendor || typeof document[vendor.exitFn] !== 'function') {\n\t\t\treturn Promise.reject(new TypeError('fullscreen not supported'));\n\t\t}\n\t\tif (!isFullscreen()) {\n\t\t\treturn Promise.reject(new TypeError('fullscreen mode not active'));\n\t\t}\n\n\t\tif (_returnsPromise()) {\n\t\t\treturn document[vendor.exitFn]();\n\t\t}\n\t\telse { // eslint-disable-line no-else-return\n\t\t\tconst namespace = '.Fullscreen_exitFullscreen';\n\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tjQuery(document)\n\t\t\t\t\t.off(namespace)\n\t\t\t\t\t.one(`${vendor.errorEvent}${namespace} ${vendor.changeEvent}${namespace}`, ev => {\n\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\tif (ev.type === vendor.errorEvent) {\n\t\t\t\t\t\t\treject(new Error('unknown fullscreen exit error'));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tdocument[vendor.exitFn]();\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction toggleFullscreen(options, requestedEl) {\n\t\treturn isFullscreen() ? exitFullscreen() : requestFullscreen(options, requestedEl);\n\t}\n\n\tfunction onChange(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\t$(element).on(vendor.changeEvent, handlerFn);\n\t}\n\n\tfunction offChange(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (handlerFn) {\n\t\t\t$(element).off(vendor.changeEvent, handlerFn);\n\t\t}\n\t\telse {\n\t\t\t$(element).off(vendor.changeEvent);\n\t\t}\n\t}\n\n\tfunction onError(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\t$(element).on(vendor.errorEvent, handlerFn);\n\t}\n\n\tfunction offError(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (handlerFn) {\n\t\t\t$(element).off(vendor.errorEvent, handlerFn);\n\t\t}\n\t\telse {\n\t\t\t$(element).off(vendor.errorEvent);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tvendor       : { get : getVendor },\n\t\telement      : { get : getElement },\n\t\tisEnabled    : { value : isEnabled },\n\t\tisFullscreen : { value : isFullscreen },\n\t\trequest      : { value : requestFullscreen },\n\t\texit         : { value : exitFullscreen },\n\t\ttoggle       : { value : toggleFullscreen },\n\t\tonChange     : { value : onChange },\n\t\toffChange    : { value : offChange },\n\t\tonError      : { value : onError },\n\t\toffError     : { value : offError }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/helpers.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, L10n, State, Story, Util, Wikifier */\n\nvar { // eslint-disable-line no-var\n\t/* eslint-disable no-unused-vars */\n\tclone,\n\tconvertBreaks,\n\tsafeActiveElement,\n\tsetDisplayTitle,\n\tsetPageElement,\n\tthrowError,\n\ttoStringOrDefault\n\t/* eslint-enable no-unused-vars */\n} = (() => {\n\t'use strict';\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _getTextContent(source) {\n\t\tconst copy = source.cloneNode(true);\n\t\tconst frag = document.createDocumentFragment();\n\t\tlet node;\n\n\t\twhile ((node = copy.firstChild) !== null) {\n\t\t\t// Insert spaces before various elements.\n\t\t\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tswitch (node.nodeName.toUpperCase()) {\n\t\t\t\tcase 'BR':\n\t\t\t\tcase 'DIV':\n\t\t\t\tcase 'P':\n\t\t\t\t\tfrag.appendChild(document.createTextNode(' '));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfrag.appendChild(node);\n\t\t}\n\n\t\treturn frag.textContent;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tHelper Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a deep copy of the given object.\n\n\t\tNOTE:\n\t\t\t1. `clone()` does not clone functions, however, since function definitions\n\t\t\t   are immutable, the only issues are with expando properties and scope.\n\t\t\t   The former really should not be done.  The latter is problematic either\n\t\t\t   way—damned if you do, damned if you don't.\n\t\t\t2. `clone()` does not maintain referential relationships—e.g. multiple\n\t\t\t   references to the same object will, post-cloning, refer to different\n\t\t\t   equivalent objects; i.e. each reference will receive its own clone\n\t\t\t   of the original object.\n\t*/\n\tfunction clone(orig) {\n\t\t/*\n\t\t\tImmediately return the primitives and functions.\n\t\t*/\n\t\tif (typeof orig !== 'object' || orig === null) {\n\t\t\treturn orig;\n\t\t}\n\n\t\t/*\n\t\t\tUnbox instances of the primitive exemplar objects.\n\t\t*/\n\t\tif (orig instanceof String) {\n\t\t\treturn String(orig);\n\t\t}\n\t\tif (orig instanceof Number) {\n\t\t\treturn Number(orig);\n\t\t}\n\t\tif (orig instanceof Boolean) {\n\t\t\treturn Boolean(orig);\n\t\t}\n\n\t\t/*\n\t\t\tHonor native clone methods.\n\t\t*/\n\t\tif (typeof orig.clone === 'function') {\n\t\t\treturn orig.clone(true);\n\t\t}\n\t\tif (orig.nodeType && typeof orig.cloneNode === 'function') {\n\t\t\treturn orig.cloneNode(true);\n\t\t}\n\n\t\t/*\n\t\t\tCreate a copy of the original object.\n\n\t\t\tNOTE: Each non-generic object that we wish to support must be\n\t\t\texplicitly handled below.\n\t\t*/\n\t\tlet copy;\n\n\t\t// Handle instances of the core supported object types.\n\t\tif (orig instanceof Array) {\n\t\t\tcopy = new Array(orig.length);\n\t\t}\n\t\telse if (orig instanceof Date) {\n\t\t\tcopy = new Date(orig.getTime());\n\t\t}\n\t\telse if (orig instanceof Map) {\n\t\t\tcopy = new Map();\n\t\t\torig.forEach((val, key) => copy.set(key, clone(val)));\n\t\t}\n\t\telse if (orig instanceof RegExp) {\n\t\t\tcopy = new RegExp(orig);\n\t\t}\n\t\telse if (orig instanceof Set) {\n\t\t\tcopy = new Set();\n\t\t\torig.forEach(val => copy.add(clone(val)));\n\t\t}\n\n\t\t// Handle instances of unknown or generic objects.\n\t\telse {\n\t\t\t// We try to ensure that the returned copy has the same prototype as\n\t\t\t// the original, but this will probably produce less than satisfactory\n\t\t\t// results on non-generics.\n\t\t\tcopy = Object.create(Object.getPrototypeOf(orig));\n\t\t}\n\n\t\t/*\n\t\t\tDuplicate the original object's own enumerable properties, which will\n\t\t\tinclude expando properties on non-generic objects.\n\n\t\t\tNOTE: This preserves neither symbol properties nor ES5 property attributes.\n\t\t\tNeither does the delta coding or serialization code, however, so it's not\n\t\t\treally an issue at the moment.\n\t\t*/\n\t\tObject.keys(orig).forEach(name => copy[name] = clone(orig[name]));\n\n\t\treturn copy;\n\t}\n\n\t/*\n\t\tConverts <br> elements to <p> elements within the given node tree.\n\t*/\n\tfunction convertBreaks(source) {\n\t\tconst output = document.createDocumentFragment();\n\t\tlet para = document.createElement('p');\n\t\tlet node;\n\n\t\twhile ((node = source.firstChild) !== null) {\n\t\t\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tconst tagName = node.nodeName.toUpperCase();\n\n\t\t\t\tswitch (tagName) {\n\t\t\t\tcase 'BR':\n\t\t\t\t\tif (\n\t\t\t\t\t\t   node.nextSibling !== null\n\t\t\t\t\t\t&& node.nextSibling.nodeType === Node.ELEMENT_NODE\n\t\t\t\t\t\t&& node.nextSibling.nodeName.toUpperCase() === 'BR'\n\t\t\t\t\t) {\n\t\t\t\t\t\tsource.removeChild(node.nextSibling);\n\t\t\t\t\t\tsource.removeChild(node);\n\t\t\t\t\t\toutput.appendChild(para);\n\t\t\t\t\t\tpara = document.createElement('p');\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\telse if (!para.hasChildNodes()) {\n\t\t\t\t\t\tsource.removeChild(node);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'ADDRESS':\n\t\t\t\tcase 'ARTICLE':\n\t\t\t\tcase 'ASIDE':\n\t\t\t\tcase 'BLOCKQUOTE':\n\t\t\t\tcase 'CENTER':\n\t\t\t\tcase 'DIV':\n\t\t\t\tcase 'DL':\n\t\t\t\tcase 'FIGURE':\n\t\t\t\tcase 'FOOTER':\n\t\t\t\tcase 'FORM':\n\t\t\t\tcase 'H1':\n\t\t\t\tcase 'H2':\n\t\t\t\tcase 'H3':\n\t\t\t\tcase 'H4':\n\t\t\t\tcase 'H5':\n\t\t\t\tcase 'H6':\n\t\t\t\tcase 'HEADER':\n\t\t\t\tcase 'HR':\n\t\t\t\tcase 'MAIN':\n\t\t\t\tcase 'NAV':\n\t\t\t\tcase 'OL':\n\t\t\t\tcase 'P':\n\t\t\t\tcase 'PRE':\n\t\t\t\tcase 'SECTION':\n\t\t\t\tcase 'TABLE':\n\t\t\t\tcase 'UL':\n\t\t\t\t\tif (para.hasChildNodes()) {\n\t\t\t\t\t\toutput.appendChild(para);\n\t\t\t\t\t\tpara = document.createElement('p');\n\t\t\t\t\t}\n\n\t\t\t\t\toutput.appendChild(node);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpara.appendChild(node);\n\t\t}\n\n\t\tif (para.hasChildNodes()) {\n\t\t\toutput.appendChild(para);\n\t\t}\n\n\t\tsource.appendChild(output);\n\t}\n\n\t/*\n\t\tReturns `document.activeElement` or `null`.\n\t*/\n\tfunction safeActiveElement() {\n\t\t/*\n\t\t\tIE9 contains a bug where trying to access the active element of an iframe's\n\t\t\tparent document (i.e. `window.parent.document.activeElement`) will throw an\n\t\t\texception, so we must allow for an exception to be thrown.\n\n\t\t\tWe could simply return `undefined` here, but since the API's default behavior\n\t\t\tshould be to return `document.body` or `null` when there is no selection, we\n\t\t\tchoose to return `null` in all non-element cases (i.e. whether it returns\n\t\t\t`null` or throws an exception).  Just a bit of normalization.\n\t\t*/\n\t\ttry {\n\t\t\treturn document.activeElement || null;\n\t\t}\n\t\tcatch (ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/*\n\t\tSets the display title.\n\t*/\n\tfunction setDisplayTitle(title) {\n\t\tif (typeof title !== 'string') {\n\t\t\tthrow new TypeError(`story display title must be a string (received: ${Util.getType(title)})`);\n\t\t}\n\n\t\tconst render = document.createDocumentFragment();\n\t\tnew Wikifier(render, title);\n\n\t\tconst text = _getTextContent(render).trim();\n\n\t\t// if (text === '') {\n\t\t// \tthrow new Error('story display title must not render to an empty string or consist solely of whitespace');\n\t\t// }\n\n\t\tdocument.title = Config.passages.displayTitles && State.passage !== '' && State.passage !== Config.passages.start\n\t\t\t? `${State.passage} | ${text}`\n\t\t\t: text;\n\n\t\tconst storyTitle = document.getElementById('story-title');\n\n\t\tif (storyTitle !== null) {\n\t\t\tjQuery(storyTitle).empty().append(render);\n\t\t}\n\t}\n\n\t/*\n\t\tWikifies a passage into a DOM element corresponding to the passed ID and returns the element.\n\t*/\n\tfunction setPageElement(idOrElement, titles, defaultText) {\n\t\tconst el = typeof idOrElement === 'object'\n\t\t\t? idOrElement\n\t\t\t: document.getElementById(idOrElement);\n\n\t\tif (el == null) { // lazy equality for null\n\t\t\treturn null;\n\t\t}\n\n\t\tconst ids = Array.isArray(titles) ? titles : [titles];\n\n\t\tjQuery(el).empty();\n\n\t\tfor (let i = 0, iend = ids.length; i < iend; ++i) {\n\t\t\tif (Story.has(ids[i])) {\n\t\t\t\tnew Wikifier(el, Story.get(ids[i]).processText().trim());\n\t\t\t\treturn el;\n\t\t\t}\n\t\t}\n\n\t\tif (defaultText != null) { // lazy equality for null\n\t\t\tconst text = String(defaultText).trim();\n\n\t\t\tif (text !== '') {\n\t\t\t\tnew Wikifier(el, text);\n\t\t\t}\n\t\t}\n\n\t\treturn el;\n\t}\n\n\t/*\n\t\tAppends an error view to the passed DOM element.\n\t*/\n\tfunction throwError(place, message, source, stack) {\n\t\tconst $wrapper = jQuery(document.createElement('div'));\n\t\tconst $toggle  = jQuery(document.createElement('button'));\n\t\tconst $source  = jQuery(document.createElement('pre'));\n\t\tconst mesg     = `${L10n.get('errorTitle')}: ${message || 'unknown error'}`;\n\n\t\t$toggle\n\t\t\t.addClass('error-toggle')\n\t\t\t.ariaClick({\n\t\t\t\tlabel : L10n.get('errorToggle')\n\t\t\t}, () => {\n\t\t\t\tif ($toggle.hasClass('enabled')) {\n\t\t\t\t\t$toggle.removeClass('enabled');\n\t\t\t\t\t$source.attr({\n\t\t\t\t\t\t'aria-hidden' : true,\n\t\t\t\t\t\thidden        : 'hidden'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$toggle.addClass('enabled');\n\t\t\t\t\t$source.removeAttr('aria-hidden hidden');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.appendTo($wrapper);\n\t\tjQuery(document.createElement('span'))\n\t\t\t.addClass('error')\n\t\t\t.text(mesg)\n\t\t\t.appendTo($wrapper);\n\t\tjQuery(document.createElement('code'))\n\t\t\t.text(source)\n\t\t\t.appendTo($source);\n\t\t$source\n\t\t\t.addClass('error-source')\n\t\t\t.attr({\n\t\t\t\t'aria-hidden' : true,\n\t\t\t\thidden        : 'hidden'\n\t\t\t})\n\t\t\t.appendTo($wrapper);\n\t\tif (stack) {\n\t\t\tconst lines = stack.split('\\n');\n\t\t\tfor (const ll of lines) {\n\t\t\t\tconst div = document.createElement('div');\n\t\t\t\tdiv.append(ll.replace(/file:.*\\//, '<path>/'));\n\t\t\t\t$source.append(div);\n\t\t\t}\n\t\t}\n\t\t$wrapper\n\t\t\t.addClass('error-view')\n\t\t\t.appendTo(place);\n\n\t\tconsole.warn(`${mesg}\\n\\t${source.replace(/\\n/g, '\\n\\t')}`);\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tReturns the simple string representation of the passed value or, if there is none,\n\t\tthe passed default value.\n\t*/\n\tfunction toStringOrDefault(value, defValue) {\n\t\tconst tSOD = toStringOrDefault;\n\n\t\tswitch (typeof value) {\n\t\tcase 'number':\n\t\t\t// TODO: Perhaps NaN should be printed instead?\n\t\t\tif (Number.isNaN(value)) {\n\t\t\t\treturn defValue;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\tif (value === null) {\n\t\t\t\treturn defValue;\n\t\t\t}\n\t\t\telse if (Array.isArray(value)) {\n\t\t\t\treturn value.map(val => tSOD(val, defValue)).join(', ');\n\t\t\t}\n\t\t\telse if (value instanceof Set) {\n\t\t\t\treturn [...value].map(val => tSOD(val, defValue)).join(', ');\n\t\t\t}\n\t\t\telse if (value instanceof Map) {\n\t\t\t\tconst result = [...value].map(([key, val]) => `${tSOD(key, defValue)} \\u2192 ${tSOD(val, defValue)}`);\n\t\t\t\treturn `{\\u202F${result.join(', ')}\\u202F}`;\n\t\t\t}\n\t\t\telse if (value instanceof Date) {\n\t\t\t\treturn value.toLocaleString();\n\t\t\t}\n\t\t\telse if (typeof value.toString === 'function') {\n\t\t\t\treturn value.toString();\n\t\t\t}\n\t\t\treturn Object.prototype.toString.call(value);\n\n\t\tcase 'function':\n\t\tcase 'undefined':\n\t\t\treturn defValue;\n\t\t}\n\n\t\treturn String(value);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tclone             : { value : clone },\n\t\tconvertBreaks     : { value : convertBreaks },\n\t\tsafeActiveElement : { value : safeActiveElement },\n\t\tsetDisplayTitle   : { value : setDisplayTitle },\n\t\tsetPageElement    : { value : setPageElement },\n\t\tthrowError        : { value : throwError },\n\t\ttoStringOrDefault : { value : toStringOrDefault }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/jquery-plugins.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Wikifier, errorPrologRegExp, safeActiveElement */\n\n/*\n\tWAI-ARIA methods plugin.\n\n\t`<jQuery>.ariaClick([options,] handler)`\n\t    Makes the target element(s) WAI-ARIA compatible clickables.\n\n\t`<jQuery>.ariaDisabled(state)`\n\t    Changes the disabled state of the target WAI-ARIA-compatible clickable element(s).\n\n\t`<jQuery>.ariaIsDisabled()`\n\t    Checks the disabled status of the target WAI-ARIA-compatible clickable element(s).\n*/\n(() => {\n\t'use strict';\n\n\t/*\n\t\tEvent handler & utility functions.\n\n\t\tNOTE: Do not replace the anonymous functions herein with arrow functions.\n\t*/\n\tfunction onKeypressFn(ev) {\n\t\t// 13 is Enter/Return, 32 is Space.\n\t\tif (ev.which === 13 || ev.which === 32) {\n\t\t\tev.preventDefault();\n\n\t\t\t// To allow delegation, attempt to trigger the event on `document.activeElement`,\n\t\t\t// if possible, elsewise on `this`.\n\t\t\tjQuery(safeActiveElement() || this).trigger('click');\n\t\t}\n\t}\n\n\tfunction onClickFnWrapper(fn) {\n\t\treturn function () {\n\t\t\tconst $this = jQuery(this);\n\n\t\t\tconst dataPassage = $this.attr('data-passage');\n\t\t\tconst initialDataPassage = window && window.SugarCube && window.SugarCube.State && window.SugarCube.State.passage;\n\t\t\tconst savedYOffset = window.pageYOffset;\n\n\t\t\t// Toggle \"aria-pressed\" status, if the attribute exists.\n\t\t\tif ($this.is('[aria-pressed]')) {\n\t\t\t\t$this.attr('aria-pressed', $this.attr('aria-pressed') === 'true' ? 'false' : 'true');\n\t\t\t}\n\n\t\t\t// Call the true handler.\n\t\t\tfn.apply(this, arguments);\n\n\t\t\tconst doJump = function(){ window.scrollTo(0, savedYOffset); }\n\t\t\tif ( dataPassage && (window.lastDataPassageLink === dataPassage || initialDataPassage === dataPassage))\n\t\t\t\tdoJump();\n\t\t\twindow.lastDataPassageLink = dataPassage;\n\t\t};\n\t}\n\n\tfunction oneClickFnWrapper(fn) {\n\t\treturn onClickFnWrapper(function () {\n\t\t\t// Remove both event handlers (keypress & click) and the other components.\n\t\t\tjQuery(this)\n\t\t\t\t.off('.aria-clickable')\n\t\t\t\t.removeAttr('tabindex aria-controls aria-pressed')\n\t\t\t\t.not('a,button')\n\t\t\t\t.removeAttr('role')\n\t\t\t\t.end()\n\t\t\t\t.filter('button')\n\t\t\t\t.prop('disabled', true);\n\n\t\t\t// Call the true handler.\n\t\t\tfn.apply(this, arguments);\n\t\t});\n\t}\n\n\tjQuery.fn.extend({\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaClick()` method.\n\t\t*/\n\t\tariaClick(options, handler) {\n\t\t\t// Bail out if there are no target element(s) or parameters.\n\t\t\tif (this.length === 0 || arguments.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tlet opts = options;\n\t\t\tlet fn   = handler;\n\n\t\t\tif (fn == null) { // lazy equality for null\n\t\t\t\tfn   = opts;\n\t\t\t\topts = undefined;\n\t\t\t}\n\n\t\t\topts = jQuery.extend({\n\t\t\t\tnamespace : undefined,\n\t\t\t\tone       : false,\n\t\t\t\tselector  : undefined,\n\t\t\t\tdata      : undefined,\n\t\t\t\tcontrols  : undefined,\n\t\t\t\tpressed   : undefined,\n\t\t\t\tlabel     : undefined\n\t\t\t}, opts);\n\n\t\t\tif (typeof opts.namespace !== 'string') {\n\t\t\t\topts.namespace = '';\n\t\t\t}\n\t\t\telse if (opts.namespace[0] !== '.') {\n\t\t\t\topts.namespace = `.${opts.namespace}`;\n\t\t\t}\n\n\t\t\tif (typeof opts.pressed === 'boolean') {\n\t\t\t\topts.pressed = opts.pressed ? 'true' : 'false';\n\t\t\t}\n\n\t\t\t// Set `type` to `button` to suppress \"submit\" semantics, for <button> elements.\n\t\t\tthis.filter('button').prop('type', 'button');\n\n\t\t\t// Set `role` to `button`, for non-<a>/-<button> elements.\n\t\t\tthis.not('a,button').attr('role', 'button');\n\n\t\t\t// Set `tabindex` to `0` to make them focusable (unnecessary on <button> elements, but it doesn't hurt).\n\t\t\tthis.attr('tabindex', 0);\n\n\t\t\t// Set `aria-controls`.\n\t\t\tif (opts.controls != null) { // lazy equality for null\n\t\t\t\tthis.attr('aria-controls', opts.controls);\n\t\t\t}\n\n\t\t\t// Set `aria-pressed`.\n\t\t\tif (opts.pressed != null) { // lazy equality for null\n\t\t\t\tthis.attr('aria-pressed', opts.pressed);\n\t\t\t}\n\n\t\t\t// Set `aria-label` and `title`.\n\t\t\tif (opts.label != null) { // lazy equality for null\n\t\t\t\tthis.attr({\n\t\t\t\t\t'aria-label' : opts.label,\n\t\t\t\t\ttitle        : opts.label\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Set the keypress handlers, for non-<button> elements.\n\t\t\t// NOTE: For the single-use case, the click handler will also remove this handler.\n\t\t\tthis.not('button').on(\n\t\t\t\t`keypress.aria-clickable${opts.namespace}`,\n\t\t\t\topts.selector,\n\t\t\t\tonKeypressFn\n\t\t\t);\n\n\t\t\t// Set the click handlers.\n\t\t\t// NOTE: To ensure both handlers are properly removed, `one()` must not be used here.\n\t\t\tthis.on(\n\t\t\t\t`click.aria-clickable${opts.namespace}`,\n\t\t\t\topts.selector,\n\t\t\t\topts.data,\n\t\t\t\topts.one ? oneClickFnWrapper(fn) : onClickFnWrapper(fn)\n\t\t\t);\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaDisabled()` method.\n\t\t*/\n\t\tariaDisabled(disable) {\n\t\t\t// Bail out if there are no target element(s) or parameters.\n\t\t\tif (this.length === 0 || arguments.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tNOTE: We use `<jQuery>.each()` callbacks to invoke the `<Element>.setAttribute()`\n\t\t\t\tmethods in the following because the `<jQuery>.attr()` method does not allow you\n\t\t\t\tto set a content attribute without a value, which is recommended for boolean\n\t\t\t\tcontent attributes by the HTML specification.\n\t\t\t*/\n\n\t\t\tconst $nonDisableable = this.not('button,fieldset,input,menuitem,optgroup,option,select,textarea');\n\t\t\tconst $disableable    = this.filter('button,fieldset,input,menuitem,optgroup,option,select,textarea');\n\n\t\t\tif (disable) {\n\t\t\t\t// Add boolean content attribute `disabled` and set non-boolean content attribute\n\t\t\t\t// `aria-disabled` to `'true'`, for non-disableable elements.\n\t\t\t\t$nonDisableable.each(function () {\n\t\t\t\t\tthis.setAttribute('disabled', '');\n\t\t\t\t\tthis.setAttribute('aria-disabled', 'true');\n\t\t\t\t});\n\n\t\t\t\t// Set IDL attribute `disabled` to `true` and set non-boolean content attribute\n\t\t\t\t// `aria-disabled` to `'true'`, for disableable elements.\n\t\t\t\t$disableable.each(function () {\n\t\t\t\t\tthis.disabled = true;\n\t\t\t\t\tthis.setAttribute('aria-disabled', 'true');\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Remove content attributes `disabled` and `aria-disabled`, for non-disableable elements.\n\t\t\t\t$nonDisableable.each(function () {\n\t\t\t\t\tthis.removeAttribute('disabled');\n\t\t\t\t\tthis.removeAttribute('aria-disabled');\n\t\t\t\t});\n\n\t\t\t\t// Set IDL attribute `disabled` to `false` and remove content attribute `aria-disabled`,\n\t\t\t\t// for disableable elements.\n\t\t\t\t$disableable.each(function () {\n\t\t\t\t\tthis.disabled = false;\n\t\t\t\t\tthis.removeAttribute('aria-disabled');\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaIsDisabled()` method.\n\t\t*/\n\t\tariaIsDisabled() {\n\t\t\t// Check content attribute `disabled`.\n\t\t\t//\n\t\t\t// NOTE: We simply check the `disabled` content attribute for all elements\n\t\t\t// since we have to check it for non-disableable elements and it may also\n\t\t\t// be used for disableable elements since their `disabled` IDL attribute\n\t\t\t// is required to reflect the status of their `disabled` content attribute,\n\t\t\t// and vice versa, by the HTML specification.\n\t\t\t// return this.toArray().some(el => el.hasAttribute('disabled'));\n\t\t\treturn this.is('[disabled]');\n\t\t}\n\t});\n})();\n\n/*\n\tWikifier methods plugin.\n\n\t`jQuery.wikiWithOptions(options, sources…)`\n\t    Wikifies the given content source(s), as directed by the given options.\n\n\t`jQuery.wiki(sources…)`\n\t    Wikifies the given content source(s).\n\n\t`<jQuery>.wikiWithOptions(options, sources…)`\n\t    Wikifies the given content source(s) and appends the result to the target\n\t    element(s), as directed by the given options.\n\n\t`<jQuery>.wiki(sources…)`\n\t    Wikifies the given content source(s) and appends the result to the target\n\t    element(s).\n*/\n(() => {\n\t'use strict';\n\n\tjQuery.extend({\n\t\t/*\n\t\t\tExtend jQuery's static methods with a `wikiWithOptions()` method.\n\t\t*/\n\t\twikiWithOptions(options, ...sources) {\n\t\t\t// Bail out, if there are no content sources.\n\t\t\tif (sources.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Wikify the content sources into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tsources.forEach(content => new Wikifier(frag, content, options));\n\n\t\t\t// Gather the text of any error elements within the fragment…\n\t\t\tconst errors = [...frag.querySelectorAll('.error')]\n\t\t\t\t.map(errEl => errEl.textContent.replace(errorPrologRegExp, ''));\n\n\t\t\t// …and throw an exception, if there were any errors.\n\t\t\tif (errors.length > 0) {\n\t\t\t\tthrow new Error(errors.join('; '));\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's static methods with a `wiki()` method.\n\t\t*/\n\t\twiki(...sources) {\n\t\t\tthis.wikiWithOptions(undefined, ...sources);\n\t\t}\n\t});\n\n\tjQuery.fn.extend({\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with a `wikiWithOptions()` method.\n\t\t*/\n\t\twikiWithOptions(options, ...sources) {\n\t\t\t// Bail out if there are no target element(s) or content sources.\n\t\t\tif (this.length === 0 || sources.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t// Wikify the content sources into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tsources.forEach(content => new Wikifier(frag, content, options));\n\n\t\t\t// Append the fragment to the target element(s).\n\t\t\tthis.append(frag);\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with a `wiki()` method.\n\t\t*/\n\t\twiki(...sources) {\n\t\t\treturn this.wikiWithOptions(undefined, ...sources);\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/util.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Has, Scripting */\n\nvar Util = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tType Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the value yielded by `typeof` (for primitives), the `@@toStringTag`\n\t\tinternal property (for objects), and `'null'` for `null`.\n\n\t\tNOTE: In ≤ES5, returns the value of the `[[Class]]` internal slot for objects.\n\t*/\n\tfunction utilGetType(obj) {\n\t\tif (obj === null) { return 'null'; }\n\n\t\tconst baseType = typeof obj;\n\t\treturn baseType === 'object'\n\t\t\t? Object.prototype.toString.call(obj).slice(8, -1)\n\t\t\t: baseType;\n\t}\n\n\t/*\n\t\tReturns whether the passed value is a boolean or one of the strings \"true\"\n\t\tor \"false\".\n\t*/\n\tfunction utilIsBoolean(obj) {\n\t\treturn typeof obj === 'boolean' || typeof obj === 'string' && (obj === 'true' || obj === 'false');\n\t}\n\n\t/*\n\t\tReturns whether the passed value is iterable.\n\t*/\n\tfunction utilIsIterable(obj) {\n\t\treturn obj != null && typeof obj[Symbol.iterator] === 'function'; // lazy equality for null\n\t}\n\n\t/*\n\t\tReturns whether the passed value is a finite number or a numeric string which\n\t\tyields a finite number when parsed.\n\t*/\n\tfunction utilIsNumeric(obj) {\n\t\tlet num;\n\n\t\tswitch (typeof obj) {\n\t\tcase 'number':\n\t\t\tnum = obj;\n\t\t\tbreak;\n\n\t\tcase 'string':\n\t\t\tnum = Number(obj);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !Number.isNaN(num) && Number.isFinite(num);\n\t}\n\n\t/*\n\t\tReturns whether the passed values pass a SameValueZero comparison.\n\n\t\tSEE: http://ecma-international.org/ecma-262/8.0/#sec-samevaluezero\n\t*/\n\tfunction utilSameValueZero(a, b) {\n\t\t/*\n\t\t\tNOTE: This comparison could also be implemented thus:\n\n\t\t\t\t```\n\t\t\t\ta === b ||\n\t\t\t\ttypeof a === 'number' && typeof b === 'number' &&\n\t\t\t\tNumber.isNaN(a) && Number.isNaN(b)\n\t\t\t\t```\n\n\t\t\tThat's needlessly verbose, however, as `NaN` is the only value in\n\t\t\tthe language which is not reflexive.\n\t\t*/\n\t\treturn a === b || a !== a && b !== b;\n\t}\n\n\t/*\n\t\tReturns a pseudo-enumeration created from the given Array, Map, Set, or generic object.\n\t*/\n\tfunction utilToEnum(obj) {\n\t\tconst pEnum = Object.create(null);\n\n\t\tif (obj instanceof Array) {\n\t\t\tobj.forEach((val, i) => pEnum[String(val)] = i);\n\t\t}\n\t\telse if (obj instanceof Set) {\n\t\t\t// NOTE: Use `<Array>.forEach()` here rather than `<Set>.forEach()`\n\t\t\t// as the latter does not provide the indices we require.\n\t\t\tArray.from(obj).forEach((val, i) => pEnum[String(val)] = i);\n\t\t}\n\t\telse if (obj instanceof Map) {\n\t\t\tobj.forEach((val, key) => pEnum[String(key)] = val);\n\t\t}\n\t\telse if (\n\t\t\t   typeof obj === 'object'\n\t\t\t&& obj !== null\n\t\t\t&& Object.getPrototypeOf(obj) === Object.prototype\n\t\t) {\n\t\t\tObject.assign(pEnum, obj);\n\t\t}\n\t\telse {\n\t\t\tthrow new TypeError('Util.toEnum obj parameter must be an Array, Map, Set, or generic object');\n\t\t}\n\n\t\treturn Object.freeze(pEnum);\n\t}\n\n\t/*\n\t\tReturns the value of the `@@toStringTag` property of the given object.\n\n\t\tNOTE: In ≤ES5, returns the value of the `[[Class]]` internal slot.\n\t*/\n\tfunction utilToStringTag(obj) {\n\t\treturn Object.prototype.toString.call(obj).slice(8, -1);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tString Encoding Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a trimmed and encoded slug of the passed string that should be safe\n\t\tfor use as a DOM ID or class name.\n\n\t\tNOTE: The range of illegal characters consists of: C0 controls, space, exclamation,\n\t\tdouble quote, number, dollar, percent, ampersand, single quote, left paren, right\n\t\tparen, asterisk, plus, comma, hyphen, period, forward slash, colon, semi-colon,\n\t\tless-than, equals, greater-than, question, at, left bracket, backslash, right\n\t\tbracket, caret, backquote/grave, left brace, pipe/vertical-bar, right brace, tilde,\n\t\tdelete, C1 controls.\n\t*/\n\tconst _illegalSlugCharsRe = /[\\x00-\\x20!-/:-@[-^`{-\\x9f]+/g; // eslint-disable-line no-control-regex\n\t/* legacy */\n\tconst _isInvalidSlugRe = /^-*$/; // Matches the empty string or one comprised solely of hyphens.\n\t/* /legacy */\n\n\tfunction utilSlugify(str) {\n\t\tconst base = String(str).trim();\n\n\t\t/* legacy */\n\t\tconst _legacy = base\n\t\t\t.replace(/[^\\w\\s\\u2013\\u2014-]+/g, '')\n\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-')\n\t\t\t.toLocaleLowerCase();\n\n\t\tif (!_isInvalidSlugRe.test(_legacy)) {\n\t\t\treturn _legacy;\n\t\t}\n\t\t/* /legacy */\n\n\t\treturn base\n\t\t\t.replace(_illegalSlugCharsRe, '')\n\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-');\n\n\t\t// For v3.\n\t\t// return base.replace(_illegalSlugCharsRe, '-');\n\t}\n\n\t/*\n\t\tReturns an entity encoded version of the passed string.\n\n\t\tNOTE: Only escapes the five primary special characters and the backquote.\n\t*/\n\tconst _htmlCharsRe    = /[&<>\"'`]/g;\n\tconst _hasHtmlCharsRe = new RegExp(_htmlCharsRe.source); // to drop the global flag\n\tconst _htmlCharsMap   = Object.freeze({\n\t\t'&' : '&amp;',\n\t\t'<' : '&lt;',\n\t\t'>' : '&gt;',\n\t\t'\"' : '&quot;',\n\t\t\"'\" : '&#39;',\n\t\t'`' : '&#96;'\n\t});\n\n\tfunction utilEscape(str) {\n\t\tif (str == null) { // lazy equality for null\n\t\t\treturn '';\n\t\t}\n\n\t\tconst val = String(str);\n\t\treturn val && _hasHtmlCharsRe.test(val)\n\t\t\t? val.replace(_htmlCharsRe, ch => _htmlCharsMap[ch])\n\t\t\t: val;\n\t}\n\n\t/*\n\t\tReturns a decoded version of the passed entity encoded string.\n\n\t\tNOTE: The extended replacement set here, in contrast to `utilEscape()`,\n\t\tis required due to observed stupidity from various sources.\n\t*/\n\tconst _escapedHtmlRe    = /&(?:amp|#38|#x26|lt|#60|#x3c|gt|#62|#x3e|quot|#34|#x22|apos|#39|#x27|#96|#x60);/gi;\n\tconst _hasEscapedHtmlRe = new RegExp(_escapedHtmlRe.source, 'i'); // to drop the global flag\n\tconst _escapedHtmlMap   = Object.freeze({\n\t\t'&amp;'  : '&', // ampersand (HTML character entity, XML predefined entity)\n\t\t'&#38;'  : '&', // ampersand (decimal numeric character reference)\n\t\t'&#x26;' : '&', // ampersand (hexadecimal numeric character reference)\n\t\t'&lt;'   : '<', // less-than (HTML character entity, XML predefined entity)\n\t\t'&#60;'  : '<', // less-than (decimal numeric character reference)\n\t\t'&#x3c;' : '<', // less-than (hexadecimal numeric character reference)\n\t\t'&gt;'   : '>', // greater-than (HTML character entity, XML predefined entity)\n\t\t'&#62;'  : '>', // greater-than (decimal numeric character reference)\n\t\t'&#x3e;' : '>', // greater-than (hexadecimal numeric character reference)\n\t\t'&quot;' : '\"', // double quote (HTML character entity, XML predefined entity)\n\t\t'&#34;'  : '\"', // double quote (decimal numeric character reference)\n\t\t'&#x22;' : '\"', // double quote (hexadecimal numeric character reference)\n\t\t'&apos;' : \"'\", // apostrophe (XML predefined entity)\n\t\t'&#39;'  : \"'\", // apostrophe (decimal numeric character reference)\n\t\t'&#x27;' : \"'\", // apostrophe (hexadecimal numeric character reference)\n\t\t'&#96;'  : '`', // backquote (decimal numeric character reference)\n\t\t'&#x60;' : '`'  // backquote (hexadecimal numeric character reference)\n\t});\n\n\tfunction utilUnescape(str) {\n\t\tif (str == null) { // lazy equality for null\n\t\t\treturn '';\n\t\t}\n\n\t\tconst val = String(str);\n\t\treturn val && _hasEscapedHtmlRe.test(val)\n\t\t\t? val.replace(_escapedHtmlRe, entity => _escapedHtmlMap[entity.toLowerCase()])\n\t\t\t: val;\n\t}\n\n\t/*\n\t\tReturns an object (`{ char, start, end }`) containing the Unicode character at\n\t\tposition `pos`, its starting position, and its ending position—surrogate pairs\n\t\tare properly handled.  If `pos` is out-of-bounds, returns an object containing\n\t\tthe empty string and start/end positions of `-1`.\n\n\t\tThis function is necessary because JavaScript strings are sequences of UTF-16\n\t\tcode units, so surrogate pairs are exposed and thus must be handled.  While the\n\t\tES6/2015 standard does improve the situation somewhat, it does not alleviate\n\t\tthe need for this function.\n\n\t\tNOTE: Returns the individual code units of invalid surrogate pairs as-is.\n\n\t\tIDEA: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt\n\t*/\n\tfunction utilCharAndPosAt(text, position) {\n\t\tconst str  = String(text);\n\t\tconst pos  = Math.trunc(position);\n\t\tconst code = str.charCodeAt(pos);\n\n\t\t// Given position was out-of-bounds.\n\t\tif (Number.isNaN(code)) {\n\t\t\treturn { char : '', start : -1, end : -1 };\n\t\t}\n\n\t\tconst retval = {\n\t\t\tchar  : str.charAt(pos),\n\t\t\tstart : pos,\n\t\t\tend   : pos\n\t\t};\n\n\t\t// Code unit is not a UTF-16 surrogate.\n\t\tif (code < 0xD800 || code > 0xDFFF) {\n\t\t\treturn retval;\n\t\t}\n\n\t\t// Code unit is a high surrogate (D800–DBFF).\n\t\tif (code >= 0xD800 && code <= 0xDBFF) {\n\t\t\tconst nextPos = pos + 1;\n\n\t\t\t// End of string.\n\t\t\tif (nextPos >= str.length) {\n\t\t\t\treturn retval;\n\t\t\t}\n\n\t\t\tconst nextCode = str.charCodeAt(nextPos);\n\n\t\t\t// Next code unit is not a low surrogate (DC00–DFFF).\n\t\t\tif (nextCode < 0xDC00 || nextCode > 0xDFFF) {\n\t\t\t\treturn retval;\n\t\t\t}\n\n\t\t\tretval.char = retval.char + str.charAt(nextPos);\n\t\t\tretval.end = nextPos;\n\t\t\treturn retval;\n\t\t}\n\n\t\t// Code unit is a low surrogate (DC00–DFFF) in the first position.\n\t\tif (pos === 0) {\n\t\t\treturn retval;\n\t\t}\n\n\t\tconst prevPos  = pos - 1;\n\t\tconst prevCode = str.charCodeAt(prevPos);\n\n\t\t// Previous code unit is not a high surrogate (D800–DBFF).\n\t\tif (prevCode < 0xD800 || prevCode > 0xDBFF) {\n\t\t\treturn retval;\n\t\t}\n\n\t\tretval.char = str.charAt(prevPos) + retval.char;\n\t\tretval.start = prevPos;\n\t\treturn retval;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTime Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the number of milliseconds elapsed since a reference epoch.\n\n\t\tNOTE: Use the Performance API, if available, elsewise use Date as a\n\t\tfailover.  The Performance API is preferred for its monotonic clock—\n\t\tmeaning, it's not subject to the vagaries of timezone changes and leap\n\t\tperiods, as is Date.\n\t*/\n\tconst _nowSource = Has.performance ? performance : Date;\n\n\tfunction utilNow() {\n\t\treturn _nowSource.now();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tConversion Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the number of miliseconds represented by the passed CSS time string.\n\t*/\n\tconst _cssTimeRe = /^([+-]?(?:\\d*\\.)?\\d+)([Mm]?[Ss])$/;\n\n\tfunction utilFromCssTime(cssTime) {\n\t\tconst match = _cssTimeRe.exec(String(cssTime));\n\n\t\tif (match === null) {\n\t\t\tthrow new SyntaxError(`invalid time value syntax: \"${cssTime}\"`);\n\t\t}\n\n\t\tlet msec = Number(match[1]);\n\n\t\tif (match[2].length === 1) {\n\t\t\tmsec *= 1000;\n\t\t}\n\n\t\tif (Number.isNaN(msec) || !Number.isFinite(msec)) {\n\t\t\tthrow new RangeError(`invalid time value: \"${cssTime}\"`);\n\t\t}\n\n\t\treturn msec;\n\t}\n\n\t/*\n\t\tReturns the CSS time string represented by the passed number of milliseconds.\n\t*/\n\tfunction utilToCssTime(msec) {\n\t\tif (typeof msec !== 'number' || Number.isNaN(msec) || !Number.isFinite(msec)) {\n\t\t\tlet what;\n\n\t\t\tswitch (typeof msec) {\n\t\t\tcase 'string':\n\t\t\t\twhat = `\"${msec}\"`;\n\t\t\t\tbreak;\n\n\t\t\tcase 'number':\n\t\t\t\twhat = String(msec);\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\twhat = utilToStringTag(msec);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tthrow new Error(`invalid milliseconds: ${what}`);\n\t\t}\n\n\t\treturn `${msec}ms`;\n\t}\n\n\t/*\n\t\tReturns the DOM property name represented by the passed CSS property name.\n\t*/\n\tfunction utilFromCssProperty(cssName) {\n\t\tif (!cssName.includes('-')) {\n\t\t\tswitch (cssName) {\n\t\t\tcase 'bgcolor': return 'backgroundColor';\n\t\t\tcase 'float':   return 'cssFloat';\n\t\t\tdefault:        return cssName;\n\t\t\t}\n\t\t}\n\n\t\t// Strip the leading hyphen from the `-ms-` vendor prefix, so it stays lowercased.\n\t\tconst normalized = cssName.slice(0, 4) === '-ms-' ? cssName.slice(1) : cssName;\n\n\t\treturn normalized\n\t\t\t.split('-')\n\t\t\t.map((part, i) => i === 0 ? part : part.toUpperFirst())\n\t\t\t.join('');\n\t}\n\n\t/*\n\t\tReturns an object containing the component properties parsed from the passed URL.\n\t*/\n\tfunction utilParseUrl(url) {\n\t\tconst el       = document.createElement('a');\n\t\tconst queryObj = Object.create(null);\n\n\t\t// Let the `<a>` element parse the URL.\n\t\tel.href = url;\n\n\t\t// Populate the `queryObj` object with the query string attributes.\n\t\tif (el.search) {\n\t\t\tel.search\n\t\t\t\t.replace(/^\\?/, '')\n\t\t\t\t.splitOrEmpty(/(?:&(?:amp;)?|;)/)\n\t\t\t\t.forEach(query => {\n\t\t\t\t\tconst [key, value] = query.split('=');\n\t\t\t\t\tqueryObj[key] = value;\n\t\t\t\t});\n\t\t}\n\n\t\t/*\n\t\t\tCaveats by browser:\n\t\t\t\tEdge and Internet Explorer (≥8) do not support authentication\n\t\t\t\tinformation within a URL at all and will throw a security exception\n\t\t\t\ton *any* property access if it's included.\n\n\t\t\t\tInternet Explorer does not include the leading forward slash on\n\t\t\t\t`pathname` when required.\n\n\t\t\t\tOpera (Presto) strips the authentication information from `href`\n\t\t\t\tand does not supply `username` or `password`.\n\n\t\t\t\tSafari (ca. v5.1.x) does not supply `username` or `password` and\n\t\t\t\tpeforms URI decoding on `pathname`.\n\t\t*/\n\n\t\t// Patch for IE not including the leading slash on `pathname` when required.\n\t\tconst pathname = el.host && el.pathname[0] !== '/' ? `/${el.pathname}` : el.pathname;\n\n\t\treturn {\n\t\t\t// The full URL that was originally parsed.\n\t\t\thref : el.href,\n\n\t\t\t// The request protocol, lowercased.\n\t\t\tprotocol : el.protocol,\n\n\t\t\t// // The full authentication information.\n\t\t\t// auth : el.username || el.password // eslint-disable-line no-nested-ternary\n\t\t\t// \t? `${el.username}:${el.password}`\n\t\t\t// \t: typeof el.username === 'string' ? '' : undefined,\n\t\t\t//\n\t\t\t// // The username portion of the auth info.\n\t\t\t// username : el.username,\n\t\t\t//\n\t\t\t// // The password portion of the auth info.\n\t\t\t// password : el.password,\n\n\t\t\t// The full host information, including port number, lowercased.\n\t\t\thost : el.host,\n\n\t\t\t// The hostname portion of the host info, lowercased.\n\t\t\thostname : el.hostname,\n\n\t\t\t// The port number portion of the host info.\n\t\t\tport : el.port,\n\n\t\t\t// The full path information, including query info.\n\t\t\tpath : `${pathname}${el.search}`,\n\n\t\t\t// The pathname portion of the path info.\n\t\t\tpathname,\n\n\t\t\t// The query string portion of the path info, including the leading question mark.\n\t\t\tquery  : el.search,\n\t\t\tsearch : el.search,\n\n\t\t\t// The attributes portion of the query string, parsed into an object.\n\t\t\tqueries  : queryObj,\n\t\t\tsearches : queryObj,\n\n\t\t\t// The fragment string, including the leading hash/pound sign.\n\t\t\thash : el.hash\n\t\t};\n\t}\n\n\t/*\n\t\tReturns a new exception based on the given exception.\n\n\t\tNOTE: Mostly useful for making a standard JavaScript exception type copy\n\t\tof a host exception type—e.g. `DOMException` → `Error`.\n\t*/\n\tfunction utilNewExceptionFrom(original, exceptionType, override) {\n\t\tif (typeof original !== 'object' || original === null) {\n\t\t\tthrow new Error('Util.newExceptionFrom original parameter must be an object');\n\t\t}\n\t\tif (typeof exceptionType !== 'function') {\n\t\t\tthrow new Error('Util.newExceptionFrom exceptionType parameter must be an error type constructor');\n\t\t}\n\n\t\tconst ex = new exceptionType(original.message); // eslint-disable-line new-cap\n\n\t\tif (typeof original.name !== 'undefined') {\n\t\t\tex.name = original.name;\n\t\t}\n\t\tif (typeof original.code !== 'undefined') {\n\t\t\tex.code = original.code;\n\t\t}\n\t\tif (typeof original.columnNumber !== 'undefined') {\n\t\t\tex.columnNumber = original.columnNumber;\n\t\t}\n\t\tif (typeof original.description !== 'undefined') {\n\t\t\tex.description = original.description;\n\t\t}\n\t\tif (typeof original.fileName !== 'undefined') {\n\t\t\tex.fileName = original.fileName;\n\t\t}\n\t\tif (typeof original.lineNumber !== 'undefined') {\n\t\t\tex.lineNumber = original.lineNumber;\n\t\t}\n\t\tif (typeof original.number !== 'undefined') {\n\t\t\tex.number = original.number;\n\t\t}\n\t\tif (typeof original.stack !== 'undefined') {\n\t\t\tex.stack = original.stack;\n\t\t}\n\n\t\tconst overrideType = typeof override;\n\n\t\tif (overrideType !== 'undefined') {\n\t\t\tif (overrideType === 'object' && override !== null) {\n\t\t\t\tObject.assign(ex, override);\n\t\t\t}\n\t\t\telse if (overrideType === 'string') {\n\t\t\t\tex.message = override;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('Util.newExceptionFrom override parameter must be an object or string');\n\t\t\t}\n\t\t}\n\n\t\treturn ex;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tType Functions.\n\t\t*/\n\t\tgetType       : { value : utilGetType },\n\t\tisBoolean     : { value : utilIsBoolean },\n\t\tisIterable    : { value : utilIsIterable },\n\t\tisNumeric     : { value : utilIsNumeric },\n\t\tsameValueZero : { value : utilSameValueZero },\n\t\ttoEnum        : { value : utilToEnum },\n\t\ttoStringTag   : { value : utilToStringTag },\n\n\t\t/*\n\t\t\tString Encoding Functions.\n\t\t*/\n\t\tslugify      : { value : utilSlugify },\n\t\tescape       : { value : utilEscape },\n\t\tunescape     : { value : utilUnescape },\n\t\tcharAndPosAt : { value : utilCharAndPosAt },\n\n\t\t/*\n\t\t\tConversion Functions.\n\t\t*/\n\t\tfromCssTime      : { value : utilFromCssTime },\n\t\ttoCssTime        : { value : utilToCssTime },\n\t\tfromCssProperty  : { value : utilFromCssProperty },\n\t\tparseUrl         : { value : utilParseUrl },\n\t\tnewExceptionFrom : { value : utilNewExceptionFrom },\n\n\t\t/*\n\t\t\tTime Functions.\n\t\t*/\n\t\tnow : { value : utilNow },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\trandom         : { value : Math.random },\n\t\tentityEncode   : { value : utilEscape },\n\t\tentityDecode   : { value : utilUnescape },\n\t\tevalExpression : { value : (...args) => Scripting.evalJavaScript(...args) }, // SEE: `markup/scripting.js`.\n\t\tevalStatements : { value : (...args) => Scripting.evalJavaScript(...args) }  // SEE: `markup/scripting.js`.\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/simplestore.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar SimpleStore = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// In-order list of database adapters.\n\tconst _adapters = [];\n\n\t// The initialized adapter.\n\tlet _initialized = null;\n\n\n\t/*******************************************************************************************************************\n\t\tSimpleStore Functions.\n\t*******************************************************************************************************************/\n\tfunction storeCreate(storageId, persistent) {\n\t\tif (_initialized) {\n\t\t\treturn _initialized.create(storageId, persistent);\n\t\t}\n\n\t\t// Return the first adapter which successfully initializes, elsewise throw an exception.\n\t\tfor (let i = 0; i < _adapters.length; ++i) {\n\t\t\tif (_adapters[i].init(storageId, persistent)) {\n\t\t\t\t_initialized = _adapters[i];\n\t\t\t\treturn _initialized.create(storageId, persistent);\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error('no valid storage adapters found');\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tAdapters List.\n\n\t\t\tTODO: This should probably have a getter, rather than being exported directly.\n\t\t*/\n\t\tadapters : { value : _adapters },\n\n\t\t/*\n\t\t\tCore Functions.\n\t\t*/\n\t\tcreate : { value : storeCreate }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/FCHost.Storage.js\n\n\tCopyright © 2013–2019 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_FCHostStorageAdapter Class.\n        Note that FCHost is only intended for a single document, so we ignore both prefixing and storageID\n\t*******************************************************************************************************************/\n\tclass _FCHostStorageAdapter {\n\t\tconstructor(persistent) {\n\t\t\tlet engine = null;\n\t\t\tlet name   = null;\n\n\t\t\tif (persistent) {\n\t\t\t\tengine = window.FCHostPersistent;\n\t\t\t\tname   = 'FCHostPersistent';\n\t\t\t}\n\t\t\telse {\n\t\t\t    engine = window.FCHostSession;\n\t\t\t\tname   = 'FCHostSession';\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_engine : {\n\t\t\t\t\tvalue : engine\n\t\t\t\t},\n                \n\t\t\t\tname : {\n\t\t\t\t\tvalue : name\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\treturn this._engine.size();\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\treturn this._engine.size();\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\treturn this._engine.keys();\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn this._engine.has(key);\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = this._engine.get(key);\n\n\t\t\treturn value == null ? null : _FCHostStorageAdapter._deserialize(value); // lazy equality for null\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.set(key, _FCHostStorageAdapter._serialize(value));\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.remove(key);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tthis._engine.clear();\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn JSON.stringify(obj);\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse(str);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit() {\n\t\t// FCHost feature test.\n\t\tfunction hasFCHostStorage() {\n\t\t\ttry {\n\t\t\t    if (typeof window.FCHostPersistent !== 'undefined')\n\t\t\t        return true;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn false;\n\t\t}\n\n\t\t_ok = hasFCHostStorage();\n\t\t\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _FCHostStorageAdapter(persistent);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/webstorage.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_WebStorageAdapter Class.\n\t*******************************************************************************************************************/\n\tclass _WebStorageAdapter {\n\t\tconstructor(storageId, persistent) {\n\t\t\tconst prefix = `${storageId}.`;\n\t\t\tlet engine = null;\n\t\t\tlet name   = null;\n\n\t\t\tif (persistent) {\n\t\t\t\tengine = window.localStorage;\n\t\t\t\tname   = 'localStorage';\n\t\t\t}\n\t\t\telse {\n\t\t\t\tengine = window.sessionStorage;\n\t\t\t\tname   = 'sessionStorage';\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_engine : {\n\t\t\t\t\tvalue : engine\n\t\t\t\t},\n\n\t\t\t\t_prefix : {\n\t\t\t\t\tvalue : prefix\n\t\t\t\t},\n\n\t\t\t\t_prefixRe : {\n\t\t\t\t\tvalue : new RegExp(`^${RegExp.escape(prefix)}`)\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : name\n\t\t\t\t},\n\n\t\t\t\tid : {\n\t\t\t\t\tvalue : storageId\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\t/*\n\t\t\t\tNOTE: DO NOT do something like `return this._engine.length;` here,\n\t\t\t\tas that will return the length of the entire store, rather than\n\t\t\t\tjust our prefixed keys.\n\t\t\t*/\n\t\t\treturn this.keys().length;\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\t/*\n\t\t\t\tNOTE: DO NOT do something like `return this._engine.length;` here,\n\t\t\t\tas that will return the length of the entire store, rather than\n\t\t\t\tjust our prefixed keys.\n\t\t\t*/\n\t\t\treturn this.keys().length;\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\tconst keys = [];\n\n\t\t\tfor (let i = 0; i < this._engine.length; ++i) {\n\t\t\t\tconst key = this._engine.key(i);\n\n\t\t\t\tif (this._prefixRe.test(key)) {\n\t\t\t\t\tkeys.push(key.replace(this._prefixRe, ''));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn keys;\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// // FIXME: This method should probably check for the key, rather than comparing its value.\n\t\t\t// return this._engine.getItem(this._prefix + key) != null; // lazy equality for null\n\n\t\t\treturn this._engine.hasOwnProperty(this._prefix + key);\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = this._engine.getItem(this._prefix + key);\n\n\t\t\treturn value == null ? null : _WebStorageAdapter._deserialize(value); // lazy equality for null\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tthis._engine.setItem(this._prefix + key, _WebStorageAdapter._serialize(value));\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t/*\n\t\t\t\t\tIf the exception is a quota exceeded error, massage it into something\n\t\t\t\t\ta bit nicer for the player.\n\n\t\t\t\t\tNOTE: Ideally, we could simply do something like checking `ex.code`, but\n\t\t\t\t\tit's a non-standard property and not supported in all browsers.  Thus,\n\t\t\t\t\twe have to resort to pattern matching the name and message—the latter being\n\t\t\t\t\trequired by Opera (Presto).  I hate the parties responsible for this snafu\n\t\t\t\t\tso much.\n\t\t\t\t*/\n\t\t\t\tif (/quota.?(?:exceeded|reached)/i.test(ex.name + ex.message)) {\n\t\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `${this.name} quota exceeded`);\n\t\t\t\t}\n\n\t\t\t\tthrow ex;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.removeItem(this._prefix + key);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tconst keys = this.keys();\n\n\t\t\tfor (let i = 0, iend = keys.length; i < iend; ++i) {\n\t\t\t\tif (DEBUG) { console.log('\\tdeleting key:', keys[i]); }\n\n\t\t\t\tthis.delete(keys[i]);\n\t\t\t}\n\n\t\t\t// return this.keys().forEach(key => {\n\t\t\t// \tif (DEBUG) { console.log('\\tdeleting key:', key); }\n\t\t\t//\n\t\t\t// \tthis.delete(key);\n\t\t\t// });\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn JSON.stringify(obj);\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse((!str || str[0] == \"{\") ? str : LZString.decompressFromUTF16(str));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit() {\n\t\t// Web Storage feature test.\n\t\tfunction hasWebStorage(storeId) {\n\t\t\ttry {\n\t\t\t\tconst store = window[storeId];\n\t\t\t\tconst tid   = `_sc_${String(Date.now())}`;\n\t\t\t\tstore.setItem(tid, tid);\n\t\t\t\tconst result = store.getItem(tid) === tid;\n\t\t\t\tstore.removeItem(tid);\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn false;\n\t\t}\n\n\t\t/*\n\t\t\tJust to be safe, we feature test for both `localStorage` and `sessionStorage`,\n\t\t\tas you never know what browser implementation bugs you're going to run into.\n\t\t*/\n\t\t_ok = hasWebStorage('localStorage') && hasWebStorage('sessionStorage');\n\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _WebStorageAdapter(storageId, persistent);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/cookie.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Expiry constants.\n\tconst _MAX_EXPIRY = 'Tue, 19 Jan 2038 03:14:07 GMT'; // (new Date((Math.pow(2, 31) - 1) * 1000)).toUTCString()\n\tconst _MIN_EXPIRY = 'Thu, 01 Jan 1970 00:00:00 GMT'; // (new Date(0)).toUTCString()\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_CookieAdapter Class.\n\t*******************************************************************************************************************/\n\tclass _CookieAdapter {\n\t\tconstructor(storageId, persistent) {\n\t\t\tconst prefix = `${storageId}${persistent ? '!' : '*'}.`;\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_prefix : {\n\t\t\t\t\tvalue : prefix\n\t\t\t\t},\n\n\t\t\t\t_prefixRe : {\n\t\t\t\t\tvalue : new RegExp(`^${RegExp.escape(prefix)}`)\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : 'cookie'\n\t\t\t\t},\n\n\t\t\t\tid : {\n\t\t\t\t\tvalue : storageId\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\treturn this.keys().length;\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\treturn this.keys().length;\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\tif (document.cookie === '') {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst cookies = document.cookie.split(/;\\s*/);\n\t\t\tconst keys    = [];\n\n\t\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\t\tif (this._prefixRe.test(key)) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\t\tnot a serialized empty string, so we should omit such pairs.\n\t\t\t\t\t*/\n\t\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\t\tif (value !== '') {\n\t\t\t\t\t\tkeys.push(key.replace(this._prefixRe, ''));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn keys;\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn _CookieAdapter._getCookie(this._prefix + key) !== null;\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = _CookieAdapter._getCookie(this._prefix + key);\n\n\t\t\treturn value === null ? null : _CookieAdapter._deserialize(value);\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\tthis._prefix + key,\n\t\t\t\t\t_CookieAdapter._serialize(value),\n\n\t\t\t\t\t// An undefined expiry denotes a session cookie.\n\t\t\t\t\tthis.persistent ? _MAX_EXPIRY : undefined\n\t\t\t\t);\n\n\t\t\t\tif (!this.has(key)) {\n\t\t\t\t\tthrow new Error('unknown validation error during set');\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t// Massage the cookie exception into something a bit nicer for the player.\n\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `cookie error: ${ex.message}`);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\t/*\n\t\t\t\tAttempting to delete a cookie implies setting it, so we test for its existence\n\t\t\t\tbeforehand, to avoid creating it in the event that it does not already exist.\n\t\t\t*/\n\t\t\tif (typeof key !== 'string' || !key || !this.has(key)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\tthis._prefix + key,\n\n\t\t\t\t\t// Use `undefined` as the value.\n\t\t\t\t\tundefined,\n\n\t\t\t\t\t// Use the epoch as the expiry.\n\t\t\t\t\t_MIN_EXPIRY\n\t\t\t\t);\n\n\t\t\t\tif (this.has(key)) {\n\t\t\t\t\tthrow new Error('unknown validation error during delete');\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t// Massage the cookie exception into something a bit nicer for the player.\n\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `cookie error: ${ex.message}`);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tconst keys = this.keys();\n\n\t\t\tfor (let i = 0, iend = keys.length; i < iend; ++i) {\n\t\t\t\tif (DEBUG) { console.log('\\tdeleting key:', keys[i]); }\n\n\t\t\t\tthis.delete(keys[i]);\n\t\t\t}\n\n\t\t\t// this.keys().forEach(key => {\n\t\t\t// \tif (DEBUG) { console.log('\\tdeleting key:', key); }\n\t\t\t//\n\t\t\t// \tthis.delete(key);\n\t\t\t// });\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _getCookie(prefixedKey) {\n\t\t\tif (!prefixedKey || document.cookie === '') {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst cookies = document.cookie.split(/;\\s*/);\n\n\t\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\t\tif (prefixedKey === key) {\n\t\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\t\tnot a serialized empty string, so we should yield `null` for such pairs.\n\t\t\t\t\t*/\n\t\t\t\t\treturn value || null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tstatic _setCookie(prefixedKey, value, expiry) {\n\t\t\tif (!prefixedKey) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet payload = `${encodeURIComponent(prefixedKey)}=`;\n\n\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\tpayload += encodeURIComponent(value);\n\t\t\t}\n\n\t\t\tif (expiry != null) { // lazy equality for null\n\t\t\t\tpayload += `; expires=${expiry}`;\n\t\t\t}\n\n\t\t\tpayload += '; path=/';\n\t\t\tdocument.cookie = payload;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn LZString.compressToBase64(JSON.stringify(obj));\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse(LZString.decompressFromBase64(str));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit(\n\t\t// Only used for stores updates.\n\t\tstorageId\n\t) {\n\t\t// Cookie feature test.\n\t\ttry {\n\t\t\tconst tid = `_sc_${String(Date.now())}`;\n\n\t\t\t// We only test a session cookie as that should suffice.\n\t\t\t_CookieAdapter._setCookie(tid, _CookieAdapter._serialize(tid), undefined);\n\t\t\t_ok = _CookieAdapter._deserialize(_CookieAdapter._getCookie(tid)) === tid;\n\t\t\t_CookieAdapter._setCookie(tid, undefined, _MIN_EXPIRY);\n\t\t}\n\t\tcatch (ex) {\n\t\t\t_ok = false;\n\t\t}\n\n\t\t/* legacy */\n\t\t// Attempt to update the cookie stores, if necessary.  This should happen only during initialization.\n\t\tif (_ok) {\n\t\t\t_updateCookieStores(storageId);\n\t\t}\n\t\t/* /legacy */\n\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _CookieAdapter(storageId, persistent);\n\t}\n\n\t/* legacy */\n\t// Updates old non-segmented cookie stores into segmented stores.\n\tfunction _updateCookieStores(storageId) {\n\t\tif (document.cookie === '') {\n\t\t\treturn;\n\t\t}\n\n\t\tconst oldPrefix     = `${storageId}.`;\n\t\tconst oldPrefixRe   = new RegExp(`^${RegExp.escape(oldPrefix)}`);\n\t\tconst persistPrefix = `${storageId}!.`;\n\t\tconst sessionPrefix = `${storageId}*.`;\n\t\tconst sessionTestRe = /\\.(?:state|rcWarn)$/;\n\t\tconst cookies       = document.cookie.split(/;\\s*/);\n\n\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\tif (oldPrefixRe.test(key)) {\n\t\t\t\t/*\n\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\tnot a serialized empty string, so we should skip processing such pairs.\n\t\t\t\t*/\n\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\tif (value !== '') {\n\t\t\t\t\tconst persist = !sessionTestRe.test(key);\n\n\t\t\t\t\t// Delete the old k/v pair.\n\t\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t_MIN_EXPIRY\n\t\t\t\t\t);\n\n\t\t\t\t\t// Set the new k/v pair.\n\t\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\t\tkey.replace(oldPrefixRe, () => persist ? persistPrefix : sessionPrefix),\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tpersist ? _MAX_EXPIRY : undefined\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t/* /legacy */\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/debugview.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tTODO: Make this use jQuery throughout.\n*/\nvar DebugView = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tDebugView Class.\n\t*******************************************************************************************************************/\n\tclass DebugView {\n\t\tconstructor(parent, type, name, title) {\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tparent : {\n\t\t\t\t\tvalue : parent\n\t\t\t\t},\n\n\t\t\t\tview : {\n\t\t\t\t\tvalue : document.createElement('span')\n\t\t\t\t},\n\n\t\t\t\tbreak : {\n\t\t\t\t\tvalue : document.createElement('wbr')\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Set up the wrapper (`<span>`) element.\n\t\t\tjQuery(this.view)\n\t\t\t\t.attr({\n\t\t\t\t\ttitle,\n\t\t\t\t\t'aria-label' : title,\n\t\t\t\t\t'data-type'  : type != null ? type : '', // lazy equality for null\n\t\t\t\t\t'data-name'  : name != null ? name : ''  // lazy equality for null\n\t\t\t\t})\n\t\t\t\t.addClass('debug');\n\n\t\t\t// Set up the word break (`<wbr>`) element.\n\t\t\tjQuery(this.break).addClass('debug hidden');\n\n\t\t\t// Add the wrapper (`<span>`) and word break (`<wbr>`) elements to the `parent` element.\n\t\t\tthis.parent.appendChild(this.view);\n\t\t\tthis.parent.appendChild(this.break);\n\t\t}\n\n\t\tget output() {\n\t\t\treturn this.view;\n\t\t}\n\n\t\tget type() {\n\t\t\treturn this.view.getAttribute('data-type');\n\t\t}\n\t\tset type(type) {\n\t\t\tthis.view.setAttribute('data-type', type != null ? type : ''); // lazy equality for null\n\t\t}\n\n\t\tget name() {\n\t\t\treturn this.view.getAttribute('data-name');\n\t\t}\n\t\tset name(name) {\n\t\t\tthis.view.setAttribute('data-name', name != null ? name : ''); // lazy equality for null\n\t\t}\n\n\t\tget title() {\n\t\t\treturn this.view.title;\n\t\t}\n\t\tset title(title) {\n\t\t\tthis.view.title = title;\n\t\t}\n\n\t\tappend(el) {\n\t\t\tjQuery(this.view).append(el);\n\t\t\treturn this;\n\t\t}\n\n\t\tmodes(options) {\n\t\t\tif (options == null) { // lazy equality for null\n\t\t\t\tconst current = {};\n\n\t\t\t\tthis.view.className.splitOrEmpty(/\\s+/).forEach(name => {\n\t\t\t\t\tif (name !== 'debug') {\n\t\t\t\t\t\tcurrent[name] = true;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\treturn current;\n\t\t\t}\n\t\t\telse if (typeof options === 'object') {\n\t\t\t\tObject.keys(options).forEach(function (name) {\n\t\t\t\t\tthis[options[name] ? 'addClass' : 'removeClass'](name);\n\t\t\t\t}, jQuery(this.view));\n\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tthrow new Error('DebugView.prototype.modes options parameter must be an object or null/undefined');\n\t\t}\n\n\t\tremove() {\n\t\t\tconst $view = jQuery(this.view);\n\n\t\t\tif (this.view.hasChildNodes()) {\n\t\t\t\t$view.contents().appendTo(this.parent);\n\t\t\t}\n\n\t\t\t$view.remove();\n\t\t\tjQuery(this.break).remove();\n\t\t}\n\n\t\tstatic isEnabled() {\n\t\t\treturn jQuery(document.documentElement).attr('data-debug-view') === 'enabled';\n\t\t}\n\n\t\tstatic enable() {\n\t\t\tjQuery(document.documentElement).attr('data-debug-view', 'enabled');\n\t\t\tjQuery.event.trigger(':debugviewupdate');\n\t\t}\n\n\t\tstatic disable() {\n\t\t\tjQuery(document.documentElement).removeAttr('data-debug-view');\n\t\t\tjQuery.event.trigger(':debugviewupdate');\n\t\t}\n\n\t\tstatic toggle() {\n\t\t\tif (jQuery(document.documentElement).attr('data-debug-view') === 'enabled') {\n\t\t\t\tDebugView.disable();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tDebugView.enable();\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn DebugView;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/prngwrapper.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar PRNGWrapper = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tPRNGWrapper Class.\n\t*******************************************************************************************************************/\n\tclass PRNGWrapper {\n\t\tconstructor(seed, useEntropy) {\n\t\t\t/* eslint-disable new-cap */\n\t\t\tObject.defineProperties(this, new Math.seedrandom(seed, useEntropy, (prng, seed) => ({\n\t\t\t\t_prng : {\n\t\t\t\t\tvalue : prng\n\t\t\t\t},\n\n\t\t\t\tseed : {\n\t\t\t\t\t/*\n\t\t\t\t\t\tTODO: Make this non-writable.\n\t\t\t\t\t*/\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : seed\n\t\t\t\t},\n\n\t\t\t\tpull : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\trandom : {\n\t\t\t\t\tvalue() {\n\t\t\t\t\t\t++this.pull;\n\t\t\t\t\t\treturn this._prng();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})));\n\t\t\t/* eslint-enable new-cap */\n\t\t}\n\n\t\tstatic marshal(prng) {\n\t\t\tif (!prng || !prng.hasOwnProperty('seed') || !prng.hasOwnProperty('pull')) {\n\t\t\t\tthrow new Error('PRNG is missing required data');\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tseed : prng.seed,\n\t\t\t\tpull : prng.pull\n\t\t\t};\n\t\t}\n\n\t\tstatic unmarshal(prngObj) {\n\t\t\tif (!prngObj || !prngObj.hasOwnProperty('seed') || !prngObj.hasOwnProperty('pull')) {\n\t\t\t\tthrow new Error('PRNG object is missing required data');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tCreate a new PRNG using the original seed and pull values from it until it\n\t\t\t\thas reached the original pull count.\n\t\t\t*/\n\t\t\tconst prng = new PRNGWrapper(prngObj.seed, false);\n\n\t\t\tfor (let i = prngObj.pull; i > 0; --i) {\n\t\t\t\tprng.random();\n\t\t\t}\n\n\t\t\treturn prng;\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn PRNGWrapper;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/stylewrapper.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns, Story, Wikifier */\n\nvar StyleWrapper = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tconst _imageMarkupRe    = new RegExp(Patterns.cssImage, 'g');\n\tconst _hasImageMarkupRe = new RegExp(Patterns.cssImage);\n\n\n\t/*******************************************************************************************************************\n\t\tStyleWrapper Class.\n\t*******************************************************************************************************************/\n\tclass StyleWrapper {\n\t\tconstructor(style) {\n\t\t\tif (style == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('StyleWrapper style parameter must be an HTMLStyleElement object');\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tstyle : {\n\t\t\t\t\tvalue : style\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tisEmpty() {\n\t\t\t// This should work in all supported browsers.\n\t\t\treturn this.style.cssRules.length === 0;\n\t\t}\n\n\t\tset(rawCss) {\n\t\t\tthis.clear();\n\t\t\tthis.add(rawCss);\n\t\t}\n\n\t\tadd(rawCss) {\n\t\t\tlet css = rawCss;\n\n\t\t\t// Check for wiki image transclusion.\n\t\t\tif (_hasImageMarkupRe.test(css)) {\n\t\t\t\t/*\n\t\t\t\t\tThe JavaScript specifications, since at least ES3, say that `<String>.replace()`\n\t\t\t\t\tshould reset a global-flagged regular expression's `lastIndex` property to `0`\n\t\t\t\t\tupon invocation.  Buggy browser versions exist, however, which do not reset\n\t\t\t\t\t`lastIndex`, so we should do so manually to support those browsers.\n\n\t\t\t\t\tNOTE: I do not think this is actually necessary, since `_imageMarkupRe` is\n\t\t\t\t\tscoped to this module—meaning users should not be able to access it.  That\n\t\t\t\t\tbeing the case, and since we search to exhaustion which should also cause\n\t\t\t\t\t`lastIndex` to be reset, there should never be an instance where we invoke\n\t\t\t\t\t`css.replace()` and `_imageMarkupRe.lastIndex` is not already `0`.  Still,\n\t\t\t\t\tconsidering the other bug, better safe than sorry.\n\t\t\t\t*/\n\t\t\t\t_imageMarkupRe.lastIndex = 0;\n\n\t\t\t\tcss = css.replace(_imageMarkupRe, wikiImage => {\n\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\tsource     : wikiImage,\n\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t});\n\n\t\t\t\t\tif (markup.hasOwnProperty('error') || markup.pos < wikiImage.length) {\n\t\t\t\t\t\treturn wikiImage;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet source = markup.source;\n\n\t\t\t\t\t// Handle image passage transclusion.\n\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\tsource = passage.text.trim();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tThe source may be URI- or Base64-encoded, so we cannot use `encodeURIComponent()`\n\t\t\t\t\t\there.  Instead, we simply encode any double quotes, since the URI will be\n\t\t\t\t\t\tdelimited by them.\n\t\t\t\t\t*/\n\t\t\t\t\treturn `url(\"${source.replace(/\"/g, '%22')}\")`;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// For IE ≤ 10.\n\t\t\tif (this.style.styleSheet) {\n\t\t\t\tthis.style.styleSheet.cssText += css;\n\t\t\t}\n\n\t\t\t// For all other browsers (incl. IE ≥ 11).\n\t\t\telse {\n\t\t\t\tthis.style.appendChild(document.createTextNode(css));\n\t\t\t}\n\t\t}\n\n\t\tclear() {\n\t\t\t// For IE ≤10.\n\t\t\tif (this.style.styleSheet) {\n\t\t\t\tthis.style.styleSheet.cssText = '';\n\t\t\t}\n\n\t\t\t// For all other browsers (incl. IE ≥11).\n\t\t\telse {\n\t\t\t\tjQuery(this.style).empty();\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn StyleWrapper;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/diff.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util, clone */\n\nvar Diff = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tDiff Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tDiff operations object (pseudo-enumeration).\n\t*/\n\tconst Op = Util.toEnum({\n\t\tDelete      : 0,\n\t\tSpliceArray : 1,\n\t\tCopy        : 2,\n\t\tCopyDate    : 3\n\t});\n\n\t/*\n\t\tReturns a difference object generated from comparing the the orig and dest objects.\n\t*/\n\tfunction diff(orig, dest) /* diff object */ {\n\t\tconst objToString = Object.prototype.toString;\n\t\tconst origIsArray = orig instanceof Array;\n\t\tconst keys        = []\n\t\t\t.concat(Object.keys(orig), Object.keys(dest))\n\t\t\t.sort()\n\t\t\t.filter((val, i, arr) => i === 0 || arr[i - 1] !== val);\n\t\tconst diffed      = {};\n\t\tlet aOpRef;\n\n\t\tconst keyIsAOpRef = key => key === aOpRef;\n\n\t\t/* eslint-disable max-depth */\n\t\tfor (let i = 0, klen = keys.length; i < klen; ++i) {\n\t\t\tconst key   = keys[i];\n\t\t\tconst origP = orig[key];\n\t\t\tconst destP = dest[key];\n\n\t\t\tif (orig.hasOwnProperty(key)) {\n\t\t\t\t// Key exists in both.\n\t\t\t\tif (dest.hasOwnProperty(key)) {\n\t\t\t\t\t// Values are exactly the same, so do nothing.\n\t\t\t\t\tif (origP === destP) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Values are of the same basic type.\n\t\t\t\t\tif (typeof origP === typeof destP) { // eslint-disable-line valid-typeof\n\t\t\t\t\t\t// Values are functions.\n\t\t\t\t\t\tif (typeof origP === 'function') {\n\t\t\t\t\t\t\t/* diffed[key] = [Op.Copy, destP]; */\n\t\t\t\t\t\t\tif (origP.toString() !== destP.toString()) {\n\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, destP];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Values are primitives.\n\t\t\t\t\t\telse if (typeof origP !== 'object' || origP === null) {\n\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, destP];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Values are objects.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst origPType = objToString.call(origP);\n\t\t\t\t\t\t\tconst destPType = objToString.call(destP);\n\n\t\t\t\t\t\t\t// Values are objects of the same reported type.\n\t\t\t\t\t\t\tif (origPType === destPType) {\n\t\t\t\t\t\t\t\t// Various special cases to handle supported non-generic objects.\n\t\t\t\t\t\t\t\tif (origP instanceof Date) {\n\t\t\t\t\t\t\t\t\tif (Number(origP) !== Number(destP)) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof Map) {\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof RegExp) {\n\t\t\t\t\t\t\t\t\tif (origP.toString() !== destP.toString()) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof Set) {\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Unknown non-generic objects (custom or unsupported natives).\n\t\t\t\t\t\t\t\telse if (origPType !== '[object Object]') {\n\t\t\t\t\t\t\t\t\t// We cannot know how to process these objects,\n\t\t\t\t\t\t\t\t\t// so we simply accept them as-is.\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Generic objects.\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tconst recurse = diff(origP, destP);\n\n\t\t\t\t\t\t\t\t\tif (recurse !== null) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = recurse;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Values are objects of different reported types.\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Values are of different types.\n\t\t\t\t\telse {\n\t\t\t\t\t\tdiffed[key] = [\n\t\t\t\t\t\t\tOp.Copy,\n\t\t\t\t\t\t\ttypeof destP !== 'object' || destP === null ? destP : clone(destP)\n\t\t\t\t\t\t];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Key only exists in orig.\n\t\t\t\telse {\n\t\t\t\t\tif (origIsArray && Util.isNumeric(key)) {\n\t\t\t\t\t\tconst nKey = Number(key);\n\n\t\t\t\t\t\tif (!aOpRef) {\n\t\t\t\t\t\t\taOpRef = '';\n\n\t\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\t\taOpRef += '~';\n\t\t\t\t\t\t\t} while (keys.some(keyIsAOpRef));\n\n\t\t\t\t\t\t\tdiffed[aOpRef] = [Op.SpliceArray, nKey, nKey];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (nKey < diffed[aOpRef][1]) {\n\t\t\t\t\t\t\tdiffed[aOpRef][1] = nKey;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (nKey > diffed[aOpRef][2]) {\n\t\t\t\t\t\t\tdiffed[aOpRef][2] = nKey;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdiffed[key] = Op.Delete;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Key only exists in dest.\n\t\t\telse {\n\t\t\t\tdiffed[key] = [\n\t\t\t\t\tOp.Copy,\n\t\t\t\t\ttypeof destP !== 'object' || destP === null ? destP : clone(destP)\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\t\t/* eslint-enable max-depth */\n\n\t\treturn Object.keys(diffed).length > 0 ? diffed : null;\n\t}\n\n\t/*\n\t\tReturns the object resulting from updating the orig object with the diffed object.\n\t*/\n\tfunction patch(orig, diffed) /* patched object */ {\n\t\tconst keys    = Object.keys(diffed || {});\n\t\tconst patched = clone(orig);\n\n\t\tfor (let i = 0, klen = keys.length; i < klen; ++i) {\n\t\t\tconst key     = keys[i];\n\t\t\tconst diffedP = diffed[key];\n\n\t\t\tif (diffedP === Op.Delete) {\n\t\t\t\tdelete patched[key];\n\t\t\t}\n\t\t\telse if (diffedP instanceof Array) {\n\t\t\t\tswitch (diffedP[0]) {\n\t\t\t\tcase Op.SpliceArray:\n\t\t\t\t\tpatched.splice(diffedP[1], 1 + (diffedP[2] - diffedP[1]));\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase Op.Copy:\n\t\t\t\t\tpatched[key] = clone(diffedP[1]);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase Op.CopyDate:\n\t\t\t\t\tpatched[key] = new Date(diffedP[1]);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tpatched[key] = patch(patched[key], diffedP);\n\t\t\t}\n\t\t}\n\n\t\treturn patched;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tOp    : { value : Op },\n\t\tdiff  : { value : diff },\n\t\tpatch : { value : patch }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tl10n/l10n.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global l10nStrings, strings */\n\nvar L10n = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Replacement pattern regular expressions.\n\tconst _patternRe    = /\\{\\w+\\}/g;\n\tconst _hasPatternRe = new RegExp(_patternRe.source); // to drop the global flag\n\n\n\t/*******************************************************************************************************************\n\t\tLocalization Functions.\n\t*******************************************************************************************************************/\n\tfunction l10nInit() {\n\t\t/* legacy */\n\t\t_mapStringsToL10nStrings();\n\t\t/* /legacy */\n\t}\n\n\t/*******************************************************************************************************************\n\t\tLocalized String Functions.\n\t*******************************************************************************************************************/\n\tfunction l10nGet(ids, overrides) {\n\t\tif (!ids) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst id = (idList => {\n\t\t\tlet selectedId;\n\t\t\tidList.some(id => {\n\t\t\t\tif (l10nStrings.hasOwnProperty(id)) {\n\t\t\t\t\tselectedId = id;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\treturn selectedId;\n\t\t})(Array.isArray(ids) ? ids : [ids]);\n\n\t\tif (!id) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst maxIterations = 50;\n\t\tlet processed = l10nStrings[id];\n\t\tlet iteration = 0;\n\n\t\twhile (_hasPatternRe.test(processed)) {\n\t\t\tif (++iteration > maxIterations) {\n\t\t\t\tthrow new Error('L10n.get exceeded maximum replacement iterations, probable infinite loop');\n\t\t\t}\n\n\t\t\t// Possibly required by some old buggy browsers.\n\t\t\t_patternRe.lastIndex = 0;\n\n\t\t\tprocessed = processed.replace(_patternRe, pat => {\n\t\t\t\tconst subId = pat.slice(1, -1);\n\n\t\t\t\tif (overrides && overrides.hasOwnProperty(subId)) {\n\t\t\t\t\treturn overrides[subId];\n\t\t\t\t}\n\t\t\t\telse if (l10nStrings.hasOwnProperty(subId)) {\n\t\t\t\t\treturn l10nStrings[subId];\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treturn processed;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tLegacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tAttempt to map legacy `strings` object properties to the `l10nStrings` object.\n\t*/\n\tfunction _mapStringsToL10nStrings() {\n\t\tif (strings && Object.keys(strings).length > 0) {\n\t\t\tObject.keys(l10nStrings).forEach(id => {\n\t\t\t\ttry {\n\t\t\t\t\tlet value;\n\n\t\t\t\t\tswitch (id) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tGeneral.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'identity': value = strings.identity; break;\n\t\t\t\t\tcase 'aborting': value = strings.aborting; break;\n\t\t\t\t\tcase 'cancel':   value = strings.cancel; break;\n\t\t\t\t\tcase 'close':    value = strings.close; break;\n\t\t\t\t\tcase 'ok':       value = strings.ok; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tErrors.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'errorTitle':              value = strings.errors.title; break;\n\t\t\t\t\tcase 'errorNonexistentPassage': value = strings.errors.nonexistentPassage; break;\n\t\t\t\t\tcase 'errorSaveMissingData':    value = strings.errors.saveMissingData; break;\n\t\t\t\t\tcase 'errorSaveIdMismatch':     value = strings.errors.saveIdMismatch; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tWarnings.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'warningDegraded': value = strings.warnings.degraded; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tDebug View.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'debugViewTitle':  value = strings.debugView.title; break;\n\t\t\t\t\tcase 'debugViewToggle': value = strings.debugView.toggle; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tUI bar.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'uiBarToggle':   value = strings.uiBar.toggle; break;\n\t\t\t\t\tcase 'uiBarBackward': value = strings.uiBar.backward; break;\n\t\t\t\t\tcase 'uiBarForward':  value = strings.uiBar.forward; break;\n\t\t\t\t\tcase 'uiBarJumpto':   value = strings.uiBar.jumpto; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tJump To.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'jumptoTitle':       value = strings.jumpto.title; break;\n\t\t\t\t\tcase 'jumptoTurn':        value = strings.jumpto.turn; break;\n\t\t\t\t\tcase 'jumptoUnavailable': value = strings.jumpto.unavailable; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tSaves.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'savesTitle':       value = strings.saves.title; break;\n\t\t\t\t\tcase 'savesDisallowed':  value = strings.saves.disallowed; break;\n\t\t\t\t\tcase 'savesIncapable':   value = strings.saves.incapable; break;\n\t\t\t\t\tcase 'savesLabelAuto':   value = strings.saves.labelAuto; break;\n\t\t\t\t\tcase 'savesLabelDelete': value = strings.saves.labelDelete; break;\n\t\t\t\t\tcase 'savesLabelExport': value = strings.saves.labelExport; break;\n\t\t\t\t\tcase 'savesLabelImport': value = strings.saves.labelImport; break;\n\t\t\t\t\tcase 'savesLabelLoad':   value = strings.saves.labelLoad; break;\n\t\t\t\t\tcase 'savesLabelClear':  value = strings.saves.labelClear; break;\n\t\t\t\t\tcase 'savesLabelSave':   value = strings.saves.labelSave; break;\n\t\t\t\t\tcase 'savesLabelSlot':   value = strings.saves.labelSlot; break;\n\t\t\t\t\tcase 'savesUnavailable': value = strings.saves.unavailable; break;\n\t\t\t\t\tcase 'savesUnknownDate': value = strings.saves.unknownDate; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tSettings.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'settingsTitle': value = strings.settings.title; break;\n\t\t\t\t\tcase 'settingsOff':   value = strings.settings.off; break;\n\t\t\t\t\tcase 'settingsOn':    value = strings.settings.on; break;\n\t\t\t\t\tcase 'settingsReset': value = strings.settings.reset; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tRestart.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'restartTitle':  value = strings.restart.title; break;\n\t\t\t\t\tcase 'restartPrompt': value = strings.restart.prompt; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tShare.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'shareTitle': value = strings.share.title; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAlert.\n\t\t\t\t\t*/\n\t\t\t\t\t/* none */\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAutoload.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'autoloadTitle':  value = strings.autoload.title; break;\n\t\t\t\t\tcase 'autoloadCancel': value = strings.autoload.cancel; break;\n\t\t\t\t\tcase 'autoloadOk':     value = strings.autoload.ok; break;\n\t\t\t\t\tcase 'autoloadPrompt': value = strings.autoload.prompt; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tMacros.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'macroBackText':   value = strings.macros.back.text; break;\n\t\t\t\t\tcase 'macroReturnText': value = strings.macros.return.text; break;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (value) {\n\t\t\t\t\t\tl10nStrings[id] = value.replace(/%\\w+%/g, pat => `{${pat.slice(1, -1)}}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t});\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tLocalization Functions.\n\t\t*/\n\t\tinit : { value : l10nInit },\n\n\t\t/*\n\t\t\tLocalized String Functions.\n\t\t*/\n\t\tget : { value : l10nGet }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tl10n/legacy.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\t[DEPRECATED] The `strings` object is deprecated and should no longer be used.\n\tAll new or updated translations should be based upon the `l10nStrings` object\n\t(see: `l10n/strings.js`).\n\n\tLegacy/existing uses of the `strings` object will be mapped to the `l10nStrings`\n\tobject after user script evaluation.\n*/\nvar strings = { // eslint-disable-line no-unused-vars, no-var\n\terrors    : {},\n\twarnings  : {},\n\tdebugView : {},\n\tuiBar     : {},\n\tjumpto    : {},\n\tsaves     : {},\n\tsettings  : {},\n\trestart   : {},\n\tshare     : {},\n\tautoload  : {},\n\tmacros    : {\n\t\tback   : {},\n\t\treturn : {}\n\t}\n};\n\n/***********************************************************************************************************************\n\n\tl10n/strings.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* eslint-disable max-len, prefer-template */\n\n/*\n\tATTENTION TRANSLATORS\n\n\tPlease use the `locale/l10n-template.js` file, from the root of the repository,\n\tas the template for your translation rather than this file.\n\n\tSEE: https://github.com/tmedwards/sugarcube-2/tree/develop/locale\n*/\nvar l10nStrings = { // eslint-disable-line no-unused-vars, no-var\n\t/*\n\t\tGeneral.\n\t*/\n\tidentity : 'game',\n\taborting : 'Aborting',\n\tcancel   : 'Cancel',\n\tclose    : 'Close',\n\tok       : 'OK',\n\n\t/*\n\t\tErrors.\n\t*/\n\terrorTitle              : 'Error',\n\terrorToggle             : 'Toggle the error view',\n\terrorNonexistentPassage : 'the passage \"{passage}\" does not exist', // NOTE: `passage` is supplied locally\n\terrorSaveMissingData    : 'save is missing required data. Either the loaded file is not a save or the save has become corrupted',\n\terrorSaveIdMismatch     : 'save is from the wrong {identity}',\n\n\t/*\n\t\tWarnings.\n\t*/\n\t_warningIntroLacking  : 'Your browser either lacks or has disabled',\n\t_warningOutroDegraded : ', so this {identity} is running in a degraded mode. You may be able to continue, however, some parts may not work properly.',\n\twarningNoWebStorage   : '{_warningIntroLacking} the Web Storage API{_warningOutroDegraded}',\n\twarningDegraded       : '{_warningIntroLacking} some of the capabilities required by this {identity}{_warningOutroDegraded}',\n\n\t/*\n\t\tDebug bar.\n\t*/\n\tdebugBarToggle      : 'Toggle the debug bar',\n\tdebugBarNoWatches   : '\\u2014 no watches set \\u2014',\n\tdebugBarAddWatch    : 'Add watch',\n\tdebugBarDeleteWatch : 'Delete watch',\n\tdebugBarWatchAll    : 'Watch all',\n\tdebugBarWatchNone   : 'Delete all',\n\tdebugBarLabelAdd    : 'Add',\n\tdebugBarLabelWatch  : 'Watch',\n\tdebugBarLabelTurn   : 'Turn', // (noun) chance to act (in a game), moment, period\n\tdebugBarLabelViews  : 'Views',\n\tdebugBarViewsToggle : 'Toggle the debug views',\n\tdebugBarWatchToggle : 'Toggle the watch panel',\n\n\t/*\n\t\tUI bar.\n\t*/\n\tuiBarToggle   : 'Toggle the UI bar',\n\tuiBarBackward : 'Go backward within the {identity} history',\n\tuiBarForward  : 'Go forward within the {identity} history',\n\tuiBarJumpto   : 'Jump to a specific point within the {identity} history',\n\n\t/*\n\t\tJump To.\n\t*/\n\tjumptoTitle       : 'Jump To',\n\tjumptoTurn        : 'Turn', // (noun) chance to act (in a game), moment, period\n\tjumptoUnavailable : 'No jump points currently available\\u2026',\n\n\t/*\n\t\tSaves.\n\t*/\n\tsavesTitle       : 'Saves',\n\tsavesDisallowed  : 'Saving has been disallowed on this passage.',\n\tsavesIncapable   : '{_warningIntroLacking} the capabilities required to support saves, so saves have been disabled for this session.',\n\tsavesLabelAuto   : 'Autosave',\n\tsavesLabelDelete : 'Delete',\n\tsavesLabelExport : 'Save to Disk\\u2026',\n\tsavesLabelImport : 'Load from Disk\\u2026',\n\tsavesLabelLoad   : 'Load',\n\tsavesLabelClear  : 'Delete All',\n\tsavesLabelSave   : 'Save',\n\tsavesLabelSlot   : 'Slot',\n\tsavesUnavailable : 'No save slots found\\u2026',\n\tsavesUnknownDate : 'unknown',\n\n\t/*\n\t\tSettings.\n\t*/\n\tsettingsTitle : 'Settings',\n\tsettingsOff   : 'Off',\n\tsettingsOn    : 'On',\n\tsettingsReset : 'Reset to Defaults',\n\n\t/*\n\t\tRestart.\n\t*/\n\trestartTitle  : 'Restart',\n\trestartPrompt : 'Are you sure that you want to restart? Unsaved progress will be lost.',\n\n\t/*\n\t\tShare.\n\t*/\n\tshareTitle : 'Share',\n\n\t/*\n\t\tAlert.\n\t*/\n\t/* none */\n\n\t/*\n\t\tAutoload.\n\t*/\n\tautoloadTitle  : 'Autoload',\n\tautoloadCancel : 'Go to start',\n\tautoloadOk     : 'Load autosave',\n\tautoloadPrompt : 'An autosave exists. Load it now or go to the start?',\n\n\t/*\n\t\tMacros.\n\t*/\n\tmacroBackText   : 'Back',  // (verb) rewind, revert\n\tmacroReturnText : 'Return' // (verb) go/send back\n};\n\n/***********************************************************************************************************************\n\n\tconfig.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util */\n\nvar Config = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// General settings.\n\tlet _debug                 = false;\n\tlet _addVisitedLinkClass   = false;\n\tlet _cleanupWikifierOutput = false;\n\tlet _loadDelay             = 0;\n\n\t// Audio settings.\n\tlet _audioPauseOnFadeToZero = true;\n\tlet _audioPreloadMetadata   = true;\n\n\t// State history settings.\n\tlet _historyControls  = true;\n\tlet _historyMaxStates = 100;\n\n\t// Macros settings.\n\tlet _macrosIfAssignmentError = true;\n\tlet _macrosMaxLoopIterations = 1000;\n\n\t// Navigation settings.\n\tlet _navigationOverride;\n\n\t// Passages settings.\n\tlet _passagesDescriptions;\n\tlet _passagesDisplayTitles = false;\n\tlet _passagesNobr          = false;\n\tlet _passagesStart; // set by `Story.load()`\n\tlet _passagesOnProcess;\n\tlet _passagesTransitionOut;\n\n\t// Saves settings.\n\tlet _savesAutoload;\n\tlet _savesAutosave;\n\tlet _savesId        = 'untitled-story';\n\tlet _savesIsAllowed;\n\tlet _savesOnLoad;\n\tlet _savesOnSave;\n\tlet _savesSlots     = 8;\n\tlet _savesVersion;\n\n\t// UI settings.\n\tlet _uiStowBarInitially    = 800;\n\tlet _uiUpdateStoryElements = true;\n\n\n\t/*******************************************************************************\n\t\tError Constants.\n\t*******************************************************************************/\n\n\tconst _errHistoryModeDeprecated     = 'Config.history.mode has been deprecated and is no longer used by SugarCube, please remove it from your code';\n\tconst _errHistoryTrackingDeprecated = 'Config.history.tracking has been deprecated, use Config.history.maxStates instead';\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze({\n\t\t/*\n\t\t\tGeneral settings.\n\t\t*/\n\t\tget debug() { return _debug; },\n\t\tset debug(value) { _debug = Boolean(value); },\n\n\t\tget addVisitedLinkClass() { return _addVisitedLinkClass; },\n\t\tset addVisitedLinkClass(value) { _addVisitedLinkClass = Boolean(value); },\n\n\t\tget cleanupWikifierOutput() { return _cleanupWikifierOutput; },\n\t\tset cleanupWikifierOutput(value) { _cleanupWikifierOutput = Boolean(value); },\n\n\t\tget loadDelay() { return _loadDelay; },\n\t\tset loadDelay(value) {\n\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\tthrow new RangeError('Config.loadDelay must be a non-negative integer');\n\t\t\t}\n\n\t\t\t_loadDelay = value;\n\t\t},\n\n\t\t/*\n\t\t\tAudio settings.\n\t\t*/\n\t\taudio : Object.freeze({\n\t\t\tget pauseOnFadeToZero() { return _audioPauseOnFadeToZero; },\n\t\t\tset pauseOnFadeToZero(value) { _audioPauseOnFadeToZero = Boolean(value); },\n\n\t\t\tget preloadMetadata() { return _audioPreloadMetadata; },\n\t\t\tset preloadMetadata(value) { _audioPreloadMetadata = Boolean(value); }\n\t\t}),\n\n\t\t/*\n\t\t\tState history settings.\n\t\t*/\n\t\thistory : Object.freeze({\n\t\t\t// TODO: (v3) This should be under UI settings → `Config.ui.historyControls`.\n\t\t\tget controls() { return _historyControls; },\n\t\t\tset controls(value) {\n\t\t\t\tconst controls = Boolean(value);\n\n\t\t\t\tif (_historyMaxStates === 1 && controls) {\n\t\t\t\t\tthrow new Error('Config.history.controls must be false when Config.history.maxStates is 1');\n\t\t\t\t}\n\n\t\t\t\t_historyControls = controls;\n\t\t\t},\n\n\t\t\tget maxStates() { return _historyMaxStates; },\n\t\t\tset maxStates(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new RangeError('Config.history.maxStates must be a non-negative integer');\n\t\t\t\t}\n\n\t\t\t\t_historyMaxStates = value;\n\n\t\t\t\t// Force `Config.history.controls` to `false`, when limited to `1` moment.\n\t\t\t\tif (_historyControls && value === 1) {\n\t\t\t\t\t_historyControls = false;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// legacy\n\t\t\t// Die if deprecated state history settings are accessed.\n\t\t\tget mode()  { throw new Error(_errHistoryModeDeprecated); },\n\t\t\tset mode(_) { throw new Error(_errHistoryModeDeprecated); },\n\t\t\tget tracking()  { throw new Error(_errHistoryTrackingDeprecated); },\n\t\t\tset tracking(_) { throw new Error(_errHistoryTrackingDeprecated); }\n\t\t\t// /legacy\n\t\t}),\n\n\t\t/*\n\t\t\tMacros settings.\n\t\t*/\n\t\tmacros : Object.freeze({\n\t\t\tget ifAssignmentError() { return _macrosIfAssignmentError; },\n\t\t\tset ifAssignmentError(value) { _macrosIfAssignmentError = Boolean(value); },\n\n\t\t\tget maxLoopIterations() { return _macrosMaxLoopIterations; },\n\t\t\tset maxLoopIterations(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new RangeError('Config.macros.maxLoopIterations must be a non-negative integer');\n\t\t\t\t}\n\n\t\t\t\t_macrosMaxLoopIterations = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tNavigation settings.\n\t\t*/\n\t\tnavigation : Object.freeze({\n\t\t\tget override() { return _navigationOverride; },\n\t\t\tset override(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.navigation.override must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_navigationOverride = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tPassages settings.\n\t\t*/\n\t\tpassages : Object.freeze({\n\t\t\tget descriptions() { return _passagesDescriptions; },\n\t\t\tset descriptions(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'boolean' && valueType !== 'Object' && valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.descriptions must be a boolean, object, function, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesDescriptions = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.updateTitle`.\n\t\t\tget displayTitles() { return _passagesDisplayTitles; },\n\t\t\tset displayTitles(value) { _passagesDisplayTitles = Boolean(value); },\n\n\t\t\tget nobr() { return _passagesNobr; },\n\t\t\tset nobr(value) { _passagesNobr = Boolean(value); },\n\n\t\t\tget onProcess() { return _passagesOnProcess; },\n\t\t\tset onProcess(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.onProcess must be a function or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesOnProcess = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.(start|startingPassage)`.\n\t\t\tget start() { return _passagesStart; },\n\t\t\tset start(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'string') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.start must be a string or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesStart = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.transitionOut`.\n\t\t\tget transitionOut() { return _passagesTransitionOut; },\n\t\t\tset transitionOut(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t   valueType !== 'string'\n\t\t\t\t\t\t&& (valueType !== 'number' || !Number.isSafeInteger(value) || value < 0)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.transitionOut must be a string, non-negative integer, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesTransitionOut = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tSaves settings.\n\t\t*/\n\t\tsaves : Object.freeze({\n\t\t\tget autoload() { return _savesAutoload; },\n\t\t\tset autoload(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'boolean' && valueType !== 'string' && valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.saves.autoload must be a boolean, string, function, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_savesAutoload = value;\n\t\t\t},\n\n\t\t\tget autosave() { return _savesAutosave; },\n\t\t\tset autosave(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\t// legacy\n\t\t\t\t\t// Convert a string value to an Array of string.\n\t\t\t\t\tif (valueType === 'string') {\n\t\t\t\t\t\t_savesAutosave = [value];\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// /legacy\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t   valueType !== 'boolean'\n\t\t\t\t\t\t&& (valueType !== 'Array' || !value.every(item => typeof item === 'string'))\n\t\t\t\t\t\t&& valueType !== 'function'\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new TypeError(`Config.saves.autosave must be a boolean, Array of strings, function, or null/undefined (received: ${valueType}${valueType === 'Array' ? ' of mixed' : ''})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_savesAutosave = value;\n\t\t\t},\n\n\t\t\tget id() { return _savesId; },\n\t\t\tset id(value) {\n\t\t\t\tif (typeof value !== 'string' || value === '') {\n\t\t\t\t\tthrow new TypeError(`Config.saves.id must be a non-empty string (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesId = value;\n\t\t\t},\n\n\t\t\tget isAllowed() { return _savesIsAllowed; },\n\t\t\tset isAllowed(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.isAllowed must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesIsAllowed = value;\n\t\t\t},\n\n\t\t\tget onLoad() { return _savesOnLoad; },\n\t\t\tset onLoad(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.onLoad must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesOnLoad = value;\n\t\t\t},\n\n\t\t\tget onSave() { return _savesOnSave; },\n\t\t\tset onSave(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.onSave must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesOnSave = value;\n\t\t\t},\n\n\t\t\tget slots() { return _savesSlots; },\n\t\t\tset slots(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new TypeError(`Config.saves.slots must be a non-negative integer (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesSlots = value;\n\t\t\t},\n\n\t\t\tget version() { return _savesVersion; },\n\t\t\tset version(value) { _savesVersion = value; }\n\t\t}),\n\n\t\t/*\n\t\t\tUI settings.\n\t\t*/\n\t\tui : Object.freeze({\n\t\t\tget stowBarInitially() { return _uiStowBarInitially; },\n\t\t\tset stowBarInitially(value) {\n\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\tif (\n\t\t\t\t\t   valueType !== 'boolean'\n\t\t\t\t\t&& (valueType !== 'number' || !Number.isSafeInteger(value) || value < 0)\n\t\t\t\t) {\n\t\t\t\t\tthrow new TypeError(`Config.ui.stowBarInitially must be a boolean or non-negative integer (received: ${valueType})`);\n\t\t\t\t}\n\n\t\t\t\t_uiStowBarInitially = value;\n\t\t\t},\n\n\t\t\tget updateStoryElements() { return _uiUpdateStoryElements; },\n\t\t\tset updateStoryElements(value) { _uiUpdateStoryElements = Boolean(value); }\n\t\t})\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tsimpleaudio.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser, Config, Has, LoadScreen, Story, Util, Visibility, clone */\n\nvar SimpleAudio = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tEvents that count as user activation—i.e. \"user gestures\", \"activation behavior\".\n\n\t\tNOTE (ca. Dec, 2018): This not an exhaustive list and varies significantly by browser.\n\t\tProposals for a specification/standard are still very much in flux at this point.\n\n\t\tTODO (ca. Dec, 2018): Revisit this topic.\n\n\t\tSEE: (too many to list)\n\t\t\thttps://github.com/whatwg/html/issues/3849\n\t\t\thttps://github.com/whatwg/html/issues/1903\n\t\t\thttps://html.spec.whatwg.org/#activation\n\t\t\thttps://docs.google.com/spreadsheets/d/1DGXjhQ6D3yZXIePOMo0dsd2agz0t5W7rYH1NwJ-QGJo/edit#gid=0\n\t*/\n\tconst _gestureEventNames = Object.freeze(['click', 'contextmenu', 'dblclick', 'keyup', 'mouseup', 'pointerup', 'touchend']);\n\n\t// Special group IDs.\n\tconst _specialIds = Object.freeze([':not', ':all', ':looped', ':muted', ':paused', ':playing']);\n\n\t// Format specifier regular expression.\n\tconst _formatSpecRe = /^([\\w-]+)\\s*\\|\\s*(\\S.*)$/; // e.g. 'mp3|https://audiohost.tld/id'\n\n\t// ID verification regular expressions.\n\tconst _badIdRe = /[:\\s]/;\n\n\t// Tracks collection.\n\tconst _tracks = new Map();\n\n\t// Groups collection.\n\tconst _groups = new Map();\n\n\t// Playlists collection.\n\tconst _lists = new Map();\n\n\t// Subscriber collection.\n\tconst _subscribers = new Map();\n\n\t// Master playback rate.\n\tlet _masterRate = 1;\n\n\t// Master playback volume.\n\tlet _masterVolume = 1;\n\n\t// Master mute state.\n\tlet _masterMute = false;\n\n\t// Master mute on tab/window visibility state.\n\tlet _masterMuteOnHidden = false;\n\n\n\t/*******************************************************************************************************************\n\t\tFeature Detection Functions.\n\t*******************************************************************************************************************/\n\t// Return whether the `<HTMLAudioElement>.play()` method returns a `Promise`.\n\t//\n\t// NOTE: The initial result is cached for future calls.\n\tconst _playReturnsPromise = (function () {\n\t\t// Cache of whether `<HTMLAudioElement>.play()` returns a `Promise`.\n\t\tlet _hasPromise = null;\n\n\t\tfunction _playReturnsPromise() {\n\t\t\tif (_hasPromise !== null) {\n\t\t\t\treturn _hasPromise;\n\t\t\t}\n\n\t\t\t_hasPromise = false;\n\n\t\t\tif (Has.audio) {\n\t\t\t\ttry {\n\t\t\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t\t\t// NOTE (ca. Jan 01, 2020): Firefox will still log an \"Autoplay is only allowed\n\t\t\t\t\t// when […] media is muted.\" message to the console when attempting the test\n\t\t\t\t\t// below, even though the audio has been muted.  Stay classy, Firefox.\n\t\t\t\t\t//\n\t\t\t\t\t// QUESTION (ca. Jan 01, 2020): Keep this?  It's only here to appease Firefox,\n\t\t\t\t\t// but doesn't seem to work as Firefox seems to ignore mute in violation of the\n\t\t\t\t\t// `HTMLAudioElement` specification—willfully or simply a bug, I can't say.\n\t\t\t\t\taudio.muted = true;\n\n\t\t\t\t\tconst value = audio.play();\n\n\t\t\t\t\t// Silence \"Uncaught (in promise)\" console errors from Blink.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: Swallowing errors is generally bad, but in this case we know there's\n\t\t\t\t\t// going to be an error regardless, since there's no source, and we don't actually\n\t\t\t\t\t// care about the error, since we just want the return value, so we consign it\n\t\t\t\t\t// to the bit bucket.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: We don't ensure that the return value is not `undefined` here because\n\t\t\t\t\t// having the attempted call to `<Promise>.catch()` on an `undefined` value throw\n\t\t\t\t\t// is acceptable, since it will be caught and `false` eventually returned.\n\t\t\t\t\tvalue.catch(() => { /* no-op */ });\n\n\t\t\t\t\t_hasPromise = value instanceof Promise;\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t}\n\n\t\t\treturn _hasPromise;\n\t\t}\n\n\t\treturn _playReturnsPromise;\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tAudioTrack Class.\n\t*******************************************************************************************************************/\n\tclass AudioTrack {\n\t\tconstructor(obj) {\n\t\t\t// Process the given array of sources or AudioTrack object.\n\t\t\tif (obj instanceof Array) {\n\t\t\t\tthis._create(obj);\n\t\t\t}\n\t\t\telse if (obj instanceof AudioTrack) {\n\t\t\t\tthis._copy(obj);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('sources parameter must be either an array, of URIs or source objects, or an AudioTrack instance');\n\t\t\t}\n\t\t}\n\n\t\t_create(sourceList) {\n\t\t\tconst dataUriRe   = /^data:\\s*audio\\/([^;,]+)\\s*[;,]/i;\n\t\t\tconst extRe       = /\\.([^./\\\\]+)$/;\n\t\t\tconst getType     = AudioTrack.getType;\n\t\t\tconst usedSources = [];\n\t\t\t/*\n\t\t\t\tHTMLAudioElement: DOM factory method vs. constructor\n\n\t\t\t\tUse of the DOM factory method, `document.createElement('audio')`, should be\n\t\t\t\tpreferred over use of the constructor, `new Audio()`.  The reason being that\n\t\t\t\tobjects created by the latter are, erroneously, treated differently, often\n\t\t\t\tunfavorably, by certain browser engines—e.g. within some versions of the iOS\n\t\t\t\tbrowser core.\n\n\t\t\t\tNotably, the only difference between the two, per the specification, is that\n\t\t\t\tobjects created via the constructor should have their `preload` property\n\t\t\t\tautomatically set to 'auto'.  Thus, there's no technical reason to prefer\n\t\t\t\tusage of the constructor, even discounting buggy browser implementations.\n\t\t\t*/\n\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t// Initially set the `preload` attribute to `'none'`.\n\t\t\taudio.preload = 'none';\n\n\t\t\t// Process the array of sources, adding any valid sources to the `usedSources`\n\t\t\t// array and to the audio element as source elements.\n\t\t\tsourceList.forEach(src => {\n\t\t\t\tlet srcObj = null;\n\n\t\t\t\tswitch (typeof src) {\n\t\t\t\tcase 'string':\n\t\t\t\t\t{\n\t\t\t\t\t\tlet match;\n\n\t\t\t\t\t\tif (src.slice(0, 5) === 'data:') {\n\t\t\t\t\t\t\tmatch = dataUriRe.exec(src);\n\n\t\t\t\t\t\t\tif (match === null) {\n\t\t\t\t\t\t\t\tthrow new Error('source data URI missing media type');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tmatch = extRe.exec(Util.parseUrl(src).pathname);\n\n\t\t\t\t\t\t\tif (match === null) {\n\t\t\t\t\t\t\t\tthrow new Error('source URL missing file extension');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst type = getType(match[1]);\n\n\t\t\t\t\t\tif (type !== null) {\n\t\t\t\t\t\t\tsrcObj = { src, type };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\t{\n\t\t\t\t\t\tif (src === null) {\n\t\t\t\t\t\t\tthrow new Error('source object cannot be null');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (!src.hasOwnProperty('src')) {\n\t\t\t\t\t\t\tthrow new Error('source object missing required \"src\" property');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (!src.hasOwnProperty('format')) {\n\t\t\t\t\t\t\tthrow new Error('source object missing required \"format\" property');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst type = getType(src.format);\n\n\t\t\t\t\t\tif (type !== null) {\n\t\t\t\t\t\t\tsrcObj = { src : src.src, type };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`invalid source value (type: ${typeof src})`);\n\t\t\t\t}\n\n\t\t\t\tif (srcObj !== null) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tOpera (Blink; ca. Jul 2017) fails to play audio from some sources\n\t\t\t\t\t\twith MIME-types containing a `codecs` parameter, despite the fact\n\t\t\t\t\t\tthat `canPlayType()` blessed the full MIME-type including `codecs`.\n\n\t\t\t\t\t\tBizarrely, this only affects some MIME-types—e.g. MP3s are affected,\n\t\t\t\t\t\twhile WAVEs are not.\n\t\t\t\t\t\t\tFails: 'audio/mpeg; codecs=\"mp3\"'\n\t\t\t\t\t\t\tPlays: 'audio/mpeg'\n\t\t\t\t\t\t\tPlays: 'audio/wav; codecs=\"1\"'\n\n\t\t\t\t\t\tTo workaround this we remove all parameters from the MIME-type in\n\t\t\t\t\t\tOpera.\n\t\t\t\t\t*/\n\t\t\t\t\tif (Browser.isOpera) {\n\t\t\t\t\t\tsrcObj.type =  srcObj.type.replace(/;.*$/, '');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst source = document.createElement('source');\n\t\t\t\t\tsource.src  = srcObj.src;\n\t\t\t\t\tsource.type = srcObj.type;\n\t\t\t\t\taudio.appendChild(source);\n\t\t\t\t\tusedSources.push(srcObj);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (audio.hasChildNodes()) {\n\t\t\t\t// Set the `preload` attribute to `'metadata'`, unless preloading has been disabled.\n\t\t\t\tif (Config.audio.preloadMetadata) {\n\t\t\t\t\taudio.preload = 'metadata';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._finalize(audio, usedSources, clone(sourceList));\n\t\t}\n\n\t\t_copy(obj) {\n\t\t\tthis._finalize(\n\t\t\t\tobj.audio.cloneNode(true), // deep clone of the audio element & its children\n\t\t\t\tclone(obj.sources),\n\t\t\t\tclone(obj.originals)\n\t\t\t);\n\t\t}\n\n\t\t_finalize(audio, sources, originals) {\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\taudio : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : audio\n\t\t\t\t},\n\n\t\t\t\tsources : {\n\t\t\t\t\tvalue : Object.freeze(sources)\n\t\t\t\t},\n\n\t\t\t\toriginals : {\n\t\t\t\t\tvalue : Object.freeze(originals)\n\t\t\t\t},\n\n\t\t\t\t_error : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_faderId : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_mute : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_rate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_volume : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Set up event handlers on the audio and source elements.\n\t\t\tjQuery(this.audio)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving a `loadstart` event on the audio element, set `_error` to\n\t\t\t\t\t`false`.\n\t\t\t\t*/\n\t\t\t\t.on('loadstart.AudioTrack', () => this._error = false)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving an `error` event on the audio element, set `_error` to\n\t\t\t\t\t`true`.\n\n\t\t\t\t\tCaveats by browser:\n\t\t\t\t\t\tEdge violates the specification by triggering `error` events from source\n\t\t\t\t\t\telements on their parent media element, rather than the source element.\n\t\t\t\t\t\tTo enable error handling in all browsers, we set the error handler on the\n\t\t\t\t\t\taudio element and have the final source element forward its `error` event.\n\n\t\t\t\t\t\tIE does not trigger, at least some, `error` events from source elements at\n\t\t\t\t\t\tall, not on the source element or its parent media element.  AFAIK, nothing\n\t\t\t\t\t\tcan be done about this lossage.\n\t\t\t\t*/\n\t\t\t\t.on('error.AudioTrack', () => this._error = true)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving an `error` event on the final source element (if any), trigger\n\t\t\t\t\tan `error` event on the audio element—that being necessary because the source\n\t\t\t\t\t`error` event does not bubble.\n\t\t\t\t*/\n\t\t\t\t.find('source:last-of-type')\n\t\t\t\t.on('error.AudioTrack', () => this._trigger('error'));\n\n\t\t\t// Subscribe to command messages.\n\t\t\tsubscribe(this, mesg => {\n\t\t\t\tif (!this.audio) {\n\t\t\t\t\tunsubscribe(this);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch (mesg) {\n\t\t\t\tcase 'loadwithscreen':\n\t\t\t\t\tif (this.hasSource()) {\n\t\t\t\t\t\tconst lockId = LoadScreen.lock();\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t// NOTE: Do not use an arrow function here.\n\t\t\t\t\t\t\t.one(\n\t\t\t\t\t\t\t\t'canplaythrough.AudioTrack_loadwithscreen error.AudioTrack_loadwithscreen',\n\t\t\t\t\t\t\t\tfunction () {\n\t\t\t\t\t\t\t\t\tjQuery(this).off('.AudioTrack_loadwithscreen');\n\t\t\t\t\t\t\t\t\tLoadScreen.unlock(lockId);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.load();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'load':   this.load();               break;\n\t\t\t\tcase 'mute':   this._updateAudioMute();   break;\n\t\t\t\tcase 'rate':   this._updateAudioRate();   break;\n\t\t\t\tcase 'stop':   this.stop();               break;\n\t\t\t\tcase 'volume': this._updateAudioVolume(); break;\n\t\t\t\tcase 'unload': this.unload();             break;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Synchronize with the current master audio settings.\n\t\t\tthis._updateAudioMute();\n\t\t\tthis._updateAudioRate();\n\t\t\tthis._updateAudioVolume();\n\t\t}\n\n\t\t_trigger(eventName) {\n\t\t\t// Do not use `trigger()` here as we do not want these events to bubble.\n\t\t\tjQuery(this.audio).triggerHandler(eventName);\n\t\t}\n\n\t\t_destroy() {\n\t\t\t/*\n\t\t\t\tStrictly speaking, self-destruction is not necessary as this object will,\n\t\t\t\teventually, be garbage collected.  That said, since the audio element contains\n\t\t\t\tdata buffers for the selected audio source, which may be quite large, manually\n\t\t\t\tpurging them as soon as we know that they're no longer needed is not a bad idea.\n\t\t\t*/\n\t\t\tunsubscribe(this);\n\n\t\t\tif (!this.audio) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tjQuery(this.audio).off();\n\t\t\tthis.unload();\n\t\t\tthis._error = true;\n\n\t\t\t// Delete the audio element property.\n\t\t\tdelete this.audio;\n\t\t}\n\n\t\tclone() {\n\t\t\treturn new AudioTrack(this);\n\t\t}\n\n\t\tload() {\n\t\t\tthis.fadeStop();\n\t\t\tthis.audio.pause();\n\n\t\t\tif (!this.audio.hasChildNodes()) {\n\t\t\t\tif (this.sources.length === 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.sources.forEach(srcObj => {\n\t\t\t\t\tconst source = document.createElement('source');\n\t\t\t\t\tsource.src  = srcObj.src;\n\t\t\t\t\tsource.type = srcObj.type;\n\t\t\t\t\tthis.audio.appendChild(source);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (this.audio.preload !== 'auto') {\n\t\t\t\tthis.audio.preload = 'auto';\n\t\t\t}\n\n\t\t\tif (!this.isLoading()) {\n\t\t\t\tthis.audio.load();\n\t\t\t}\n\t\t}\n\n\t\tunload() {\n\t\t\tthis.fadeStop();\n\t\t\tthis.stop();\n\n\t\t\tconst audio = this.audio;\n\t\t\taudio.preload = 'none';\n\n\t\t\t// Remove all source elements.\n\t\t\twhile (audio.hasChildNodes()) {\n\t\t\t\taudio.removeChild(audio.firstChild);\n\t\t\t}\n\n\t\t\t// Force the audio element to drop any existing data buffers.\n\t\t\taudio.load();\n\t\t}\n\n\t\tplay() {\n\t\t\tif (!this.hasSource()) {\n\t\t\t\treturn Promise.reject(new Error('none of the candidate sources were acceptable'));\n\t\t\t}\n\n\t\t\tif (this.isUnloaded()) {\n\t\t\t\treturn Promise.reject(new Error('no sources are loaded'));\n\t\t\t}\n\n\t\t\tif (this.isFailed()) {\n\t\t\t\treturn Promise.reject(new Error('failed to load any of the sources'));\n\t\t\t}\n\n\t\t\tif (this.audio.preload !== 'auto') {\n\t\t\t\tthis.audio.preload = 'auto';\n\t\t\t}\n\n\t\t\tconst namespace = '.AudioTrack_play';\n\n\t\t\treturn _playReturnsPromise()\n\t\t\t\t? this.audio.play()\n\t\t\t\t: new Promise((resolve, reject) => {\n\t\t\t\t\tif (this.isPlaying()) {\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tjQuery(this.audio)\n\t\t\t\t\t\t\t.off(namespace)\n\t\t\t\t\t\t\t.one(`error${namespace} playing${namespace} timeupdate${namespace}`, ev => {\n\t\t\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\t\t\tif (ev.type === 'error') {\n\t\t\t\t\t\t\t\t\treject(new Error('unknown audio play error'));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.audio.play();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tthis.play().catch(() => {\n\t\t\t\tconst gestures = _gestureEventNames.map(name => `${name}.AudioTrack_playWhenAllowed`).join(' ');\n\t\t\t\tjQuery(document).one(gestures, () => {\n\t\t\t\t\tjQuery(document).off('.AudioTrack_playWhenAllowed');\n\t\t\t\t\tthis.audio.play();\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tpause() {\n\t\t\tthis.audio.pause();\n\t\t}\n\n\t\tstop() {\n\t\t\tthis.audio.pause();\n\t\t\tthis.time(0);\n\t\t\tthis._trigger(':stopped');\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (typeof duration !== 'number') {\n\t\t\t\tthrow new TypeError('duration parameter must be a number');\n\t\t\t}\n\t\t\tif (typeof toVol !== 'number') {\n\t\t\t\tthrow new TypeError('toVolume parameter must be a number');\n\t\t\t}\n\t\t\tif (fromVol != null && typeof fromVol !== 'number') { // lazy equality for null\n\t\t\t\tthrow new TypeError('fromVolume parameter must be a number');\n\t\t\t}\n\n\t\t\tif (!this.hasSource()) {\n\t\t\t\treturn Promise.reject(new Error('none of the candidate sources were acceptable'));\n\t\t\t}\n\n\t\t\tif (this.isUnloaded()) {\n\t\t\t\treturn Promise.reject(new Error('no sources are loaded'));\n\t\t\t}\n\n\t\t\tif (this.isFailed()) {\n\t\t\t\treturn Promise.reject(new Error('failed to load any of the sources'));\n\t\t\t}\n\n\t\t\tthis.fadeStop();\n\n\t\t\tconst from = Math.clamp(fromVol == null ? this.volume() : fromVol, 0, 1); // lazy equality for null\n\t\t\tconst to   = Math.clamp(toVol, 0, 1);\n\n\t\t\tif (from === to) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.volume(from);\n\n\t\t\t/*\n\t\t\t\tWe listen for the `timeupdate` event here, rather than `playing`, because\n\t\t\t\tvarious browsers (notably, mobile browsers) are poor at firing media events\n\t\t\t\tin a timely fashion, so we use `timeupdate` to ensure that we don't start\n\t\t\t\tthe fade until the track is actually progressing.\n\t\t\t*/\n\t\t\tjQuery(this.audio)\n\t\t\t\t.off('timeupdate.AudioTrack_fade')\n\t\t\t\t.one('timeupdate.AudioTrack_fade', () => {\n\t\t\t\t\tlet min;\n\t\t\t\t\tlet max;\n\n\t\t\t\t\t// Fade in.\n\t\t\t\t\tif (from < to) {\n\t\t\t\t\t\tmin = from;\n\t\t\t\t\t\tmax = to;\n\t\t\t\t\t}\n\t\t\t\t\t// Fade out.\n\t\t\t\t\telse {\n\t\t\t\t\t\tmin = to;\n\t\t\t\t\t\tmax = from;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst time     = Math.max(duration, 1);\n\t\t\t\t\tconst interval = 25; // in milliseconds\n\t\t\t\t\tconst delta    = (to - from) / (time / (interval / 1000));\n\n\t\t\t\t\tthis._trigger(':fading');\n\t\t\t\t\tthis._faderId = setInterval(() => {\n\t\t\t\t\t\tif (!this.isPlaying()) {\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tWhile it may seem like a good idea to also set the track volume\n\t\t\t\t\t\t\t\tto the `to` value here, we should not do so.  We cannot know why\n\t\t\t\t\t\t\t\tthe track is no longer playing, nor if the volume has been modified\n\t\t\t\t\t\t\t\tin the interim, so doing so now may clobber an end-user set volume.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tthis.fadeStop();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthis.volume(Math.clamp(this.volume() + delta, min, max));\n\n\t\t\t\t\t\tif (Config.audio.pauseOnFadeToZero && this.volume() === 0) {\n\t\t\t\t\t\t\tthis.pause();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.volume() === to) {\n\t\t\t\t\t\t\tthis.fadeStop();\n\t\t\t\t\t\t\tthis._trigger(':faded');\n\t\t\t\t\t\t}\n\t\t\t\t\t}, interval);\n\t\t\t\t});\n\n\t\t\treturn this.play();\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\treturn this.fade(duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\treturn this.fade(duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tif (this._faderId !== null) {\n\t\t\t\tclearInterval(this._faderId);\n\t\t\t\tthis._faderId = null;\n\t\t\t}\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\treturn this.audio.loop;\n\t\t\t}\n\n\t\t\tthis.audio.loop = !!loop;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\treturn this._mute;\n\t\t\t}\n\n\t\t\tthis._mute = !!mute;\n\t\t\tthis._updateAudioMute();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioMute() {\n\t\t\tthis.audio.muted = this._mute || _masterMute;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\treturn this._rate;\n\t\t\t}\n\n\t\t\tif (typeof rate !== 'number') {\n\t\t\t\tthrow new TypeError('rate parameter must be a number');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tClamp the playback rate to sane values—some browsers also do this to varying degrees.\n\n\t\t\t\tNOTE (ca. Aug 2016): The specification allows negative values for reverse playback,\n\t\t\t\thowever, most browsers either completely ignore negative values or clamp them to\n\t\t\t\tsome positive value.  In some (notably, IE & Edge), setting a negative playback\n\t\t\t\trate breaks the associated controls, if displayed.\n\t\t\t*/\n\t\t\t/*\n\t\t\tthis._rate = rate < 0\n\t\t\t\t? Math.clamp(rate, -0.2, -5) // clamp to 5× slower & faster, backward\n\t\t\t\t: Math.clamp(rate, 0.2, 5);  // clamp to 5× slower & faster, forward\n\t\t\t*/\n\t\t\tthis._rate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\t\t\tthis._updateAudioRate();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioRate() {\n\t\t\t/*\n\t\t\tconst rate = this._rate * _masterRate;\n\t\t\tthis.audio.playbackRate = rate < 0\n\t\t\t\t? Math.clamp(rate, -0.2, -5) // clamp to 5× slower & faster, backward\n\t\t\t\t: Math.clamp(rate, 0.2, 5);  // clamp to 5× slower & faster, forward\n\t\t\t*/\n\t\t\tthis.audio.playbackRate = Math.clamp(this._rate * _masterRate, 0.2, 5); // clamp to 5× slower & faster\n\t\t}\n\n\t\ttime(time) {\n\t\t\tif (time == null) { // lazy equality for null\n\t\t\t\treturn this.audio.currentTime;\n\t\t\t}\n\n\t\t\tif (typeof time !== 'number') {\n\t\t\t\tthrow new TypeError('time parameter must be a number');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tNOTE (historic): If we try to modify the audio clip's `.currentTime` property\n\t\t\t\tbefore its metadata has been loaded, it will throw an `InvalidStateError`\n\t\t\t\t(since it doesn't know its duration, allowing `.currentTime` to be set would\n\t\t\t\tbe undefined behavior), so in case an exception is thrown we provide a fallback\n\t\t\t\tusing the `loadedmetadata` event.\n\n\t\t\t\tNOTE (ca. 2016): This workaround should no longer be necessary in most browsers.\n\t\t\t\tThat said, it will still be required for some time to service legacy browsers.\n\n\t\t\t\tNOTE (ca. Dec 09, 2018): Firefox will still log an `InvalidStateError` to the\n\t\t\t\tconsole when attempting to modify the clip's `.currentTime` property before its\n\t\t\t\tmetadata has been loaded, even though it handles the situation properly—by waiting\n\t\t\t\tfor the metadata, as all browsers do now.  To prevent this spurious logging, we\n\t\t\t\tmust now manually check for the existence of the metadata and always failover to\n\t\t\t\tan event regardless of if the browser needs it or not—because I don't want to\n\t\t\t\tintroduce a browser check here.  Stay classy, Firefox.\n\t\t\t*/\n\t\t\tif (this.hasMetadata()) {\n\t\t\t\tthis.audio.currentTime = time;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery(this.audio)\n\t\t\t\t\t.off('loadedmetadata.AudioTrack_time')\n\t\t\t\t\t.one('loadedmetadata.AudioTrack_time', () => this.audio.currentTime = time);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\treturn this._volume;\n\t\t\t}\n\n\t\t\tif (typeof volume !== 'number') {\n\t\t\t\tthrow new TypeError('volume parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._volume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\t\t\tthis._updateAudioVolume();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioVolume() {\n\t\t\tthis.audio.volume = Math.clamp(this._volume * _masterVolume, 0, 1);\n\t\t}\n\n\t\tduration() {\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.audio.duration;\n\t\t}\n\n\t\tremaining() {\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.audio.duration - this.audio.currentTime;\n\t\t}\n\n\t\tisFailed() {\n\t\t\treturn this._error;\n\t\t}\n\n\t\tisLoading() {\n\t\t\treturn this.audio.networkState === HTMLMediaElement.NETWORK_LOADING;\n\t\t}\n\n\t\tisUnloaded() {\n\t\t\treturn !this.audio.hasChildNodes();\n\t\t}\n\n\t\tisUnavailable() {\n\t\t\treturn !this.hasSource() || this.isUnloaded() || this.isFailed();\n\t\t}\n\n\t\tisPlaying() {\n\t\t\t// NOTE: The `this.hasSomeData()` check is probably no longer necessary.\n\t\t\treturn !this.audio.paused && this.hasSomeData();\n\t\t}\n\n\t\tisPaused() {\n\t\t\t/*\n\t\t\t\tIf the selected audio resource is a stream, `currentTime` may return a non-zero\n\t\t\t\tvalue even at the earliest available position within the stream as the browser\n\t\t\t\tmay have dropped the earliest chunks of buffered data or the stream may have a\n\t\t\t\ttimeline which does not start at zero.\n\n\t\t\t\tIn an attempt to guard against these possiblities, as best as we can, we test\n\t\t\t\t`duration` against `Infinity` first, which should yield true for actual streams.\n\t\t\t*/\n\t\t\treturn this.audio.paused\n\t\t\t\t&& (this.audio.duration === Infinity || this.audio.currentTime > 0)\n\t\t\t\t&& !this.audio.ended;\n\t\t}\n\n\t\tisStopped() {\n\t\t\treturn this.audio.paused && this.audio.currentTime === 0;\n\t\t}\n\n\t\tisEnded() {\n\t\t\treturn this.audio.ended;\n\t\t}\n\n\t\tisFading() {\n\t\t\treturn this._faderId !== null;\n\t\t}\n\n\t\tisSeeking() {\n\t\t\treturn this.audio.seeking;\n\t\t}\n\n\t\thasSource() {\n\t\t\treturn this.sources.length > 0;\n\t\t}\n\n\t\thasNoData() {\n\t\t\treturn this.audio.readyState === HTMLMediaElement.HAVE_NOTHING;\n\t\t}\n\n\t\thasMetadata() {\n\t\t\treturn this.audio.readyState >= HTMLMediaElement.HAVE_METADATA;\n\t\t}\n\n\t\thasSomeData() {\n\t\t\treturn this.audio.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA;\n\t\t}\n\n\t\thasData() {\n\t\t\treturn this.audio.readyState === HTMLMediaElement.HAVE_ENOUGH_DATA;\n\t\t}\n\n\t\ton(...args) {\n\t\t\tjQuery.fn.on.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\tone(...args) {\n\t\t\tjQuery.fn.one.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\toff(...args) {\n\t\t\tjQuery.fn.off.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\t/*\n\t\t\tVerifies that the browser supports the given MIME-type and then retuns either\n\t\t\tthe MIME-type, if it is supported, or `null`, if it is not.\n\t\t*/\n\t\tstatic _verifyType(type) {\n\t\t\tif (!type || !Has.audio) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst cache = AudioTrack._types;\n\n\t\t\tif (!cache.hasOwnProperty(type)) {\n\t\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t\t// Some early implementations return 'no' instead of the empty string.\n\t\t\t\tcache[type] = audio.canPlayType(type).replace(/^no$/i, '') !== '';\n\t\t\t}\n\n\t\t\treturn cache[type] ? type : null;\n\t\t}\n\n\t\t/*\n\t\t\tRetuns the MIME-type associated with the given format-ID, if it is supported,\n\t\t\telsewise `null`.\n\t\t*/\n\t\tstatic getType(format) {\n\t\t\tif (!format || !Has.audio) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst known = AudioTrack.formats;\n\t\t\tconst id    = format.toLowerCase();\n\t\t\tconst type  = known.hasOwnProperty(id) ? known[id] : `audio/${id}`;\n\n\t\t\treturn AudioTrack._verifyType(type);\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the browser potentially supports a format.\n\t\t*/\n\t\tstatic canPlayFormat(format) {\n\t\t\treturn AudioTrack.getType(format) !== null;\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the browser potentially supports a MIME-type.\n\t\t*/\n\t\tstatic canPlayType(type) {\n\t\t\treturn AudioTrack._verifyType(type) !== null;\n\t\t}\n\t}\n\n\t// Attach the static data members.\n\tObject.defineProperties(AudioTrack, {\n\t\t/*\n\t\t\tFormat-ID to MIME-type mappings for common audio types.\n\n\t\t\tIn most cases, the codecs property should not be included with the MIME-type,\n\t\t\tas we have no way of knowing which codec was used—and the browser will figure\n\t\t\tit out.  Conversely, in cases where the relationship relationship between a\n\t\t\tformat-ID and a specific codec is strong, we should include the codecs property.\n\n\t\t\tNOTE: Caveats by browser/engine:\n\t\t\t\tOpera ≤12 (Presto) will return a false-negative if the codecs value is quoted\n\t\t\t\twith single quotes, requiring the use of either double quotes or no quotes.\n\n\t\t\t\tBlink-based browsers (e.g. Chrome, Opera ≥15) will return a false-negative\n\t\t\t\tfor WAVE audio if the preferred MIME-type of 'audio/wave' is specified,\n\t\t\t\trequiring the use of 'audio/wav' instead.\n\t\t*/\n\t\tformats : {\n\t\t\tvalue : { // Leave this object extensible for users.\n\t\t\t\t// AAC — MPEG-2 AAC audio; specific profiles vary, but commonly \"AAC-LC\".\n\t\t\t\taac : 'audio/aac',\n\n\t\t\t\t// CAF — Codecs vary.\n\t\t\t\tcaf     : 'audio/x-caf',\n\t\t\t\t'x-caf' : 'audio/x-caf',\n\n\t\t\t\t// MP3 — MPEG-1/-2 Layer-III audio.\n\t\t\t\tmp3  : 'audio/mpeg; codecs=\"mp3\"',\n\t\t\t\tmpeg : 'audio/mpeg; codecs=\"mp3\"',\n\n\t\t\t\t// MP4 — Codecs vary, but commonly \"mp4a.40.2\" (a.k.a. \"AAC-LC\").\n\t\t\t\tm4a     : 'audio/mp4',\n\t\t\t\tmp4     : 'audio/mp4',\n\t\t\t\t'x-m4a' : 'audio/mp4',\n\t\t\t\t'x-mp4' : 'audio/mp4',\n\n\t\t\t\t// OGG — Codecs vary, but commonly \"vorbis\" and, recently, \"opus\".\n\t\t\t\toga : 'audio/ogg',\n\t\t\t\togg : 'audio/ogg',\n\n\t\t\t\t// OPUS — Opus audio in an Ogg container.\n\t\t\t\topus : 'audio/ogg; codecs=\"opus\"',\n\n\t\t\t\t// WAVE — Codecs vary, but commonly \"1\" (1 is the FourCC for PCM/LPCM).\n\t\t\t\twav  : 'audio/wav',\n\t\t\t\twave : 'audio/wav',\n\n\t\t\t\t// WEBM — Codecs vary, but commonly \"vorbis\" and, recently, \"opus\".\n\t\t\t\tweba : 'audio/webm',\n\t\t\t\twebm : 'audio/webm'\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t\tCache of supported MIME-types.\n\t\t*/\n\t\t_types : {\n\t\t\tvalue : {}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAudioList Class.\n\t*******************************************************************************************************************/\n\tclass AudioList {\n\t\tconstructor(obj) {\n\t\t\t// Process the given array of track objects or AudioList object.\n\t\t\tif (obj instanceof Array) {\n\t\t\t\tthis._create(obj);\n\t\t\t}\n\t\t\telse if (obj instanceof AudioList) {\n\t\t\t\tthis._copy(obj);\n\t\t\t\t// this._create(obj.tracks);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('tracks parameter must be either an array, of track objects, or an AudioTrack instance');\n\t\t\t}\n\t\t}\n\n\t\t_create(trackList) {\n\t\t\t// Map the array of tracks to playlist track objects.\n\t\t\tthis._finalize(trackList.map(trackObj => {\n\t\t\t\tif (typeof trackObj !== 'object') { // lazy equality for null\n\t\t\t\t\tthrow new Error('tracks parameter array members must be objects');\n\t\t\t\t}\n\n\t\t\t\tlet own;\n\t\t\t\tlet rate;\n\t\t\t\tlet track;\n\t\t\t\tlet volume;\n\n\t\t\t\tif (trackObj instanceof AudioTrack) {\n\t\t\t\t\town    = true;\n\t\t\t\t\trate   = trackObj.rate();\n\t\t\t\t\ttrack  = trackObj.clone();\n\t\t\t\t\tvolume = trackObj.volume();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (!trackObj.hasOwnProperty('track')) {\n\t\t\t\t\t\tthrow new Error('track object missing required \"track\" property');\n\t\t\t\t\t}\n\t\t\t\t\telse if (!(trackObj.track instanceof AudioTrack)) {\n\t\t\t\t\t\tthrow new Error('track object\\'s \"track\" property must be an AudioTrack object');\n\t\t\t\t\t}\n\t\t\t\t\t// else if (!trackObj.hasOwnProperty('volume')) {\n\t\t\t\t\t// \tthrow new Error('track object missing required \"volume\" property');\n\t\t\t\t\t// }\n\n\t\t\t\t\town    = trackObj.hasOwnProperty('own') && trackObj.own;\n\t\t\t\t\trate   = trackObj.hasOwnProperty('rate') ? trackObj.rate : trackObj.track.rate();\n\t\t\t\t\ttrack  = trackObj.track;\n\t\t\t\t\tvolume = trackObj.hasOwnProperty('volume') ? trackObj.volume : trackObj.track.volume();\n\t\t\t\t}\n\n\t\t\t\ttrack.stop();\n\t\t\t\ttrack.loop(false);\n\t\t\t\ttrack.mute(false);\n\t\t\t\ttrack.rate(rate);\n\t\t\t\ttrack.volume(volume);\n\t\t\t\ttrack.on('ended.AudioList', () => this._onEnd());\n\n\t\t\t\treturn { own, track, volume, rate };\n\t\t\t}));\n\t\t}\n\n\t\t_copy(obj) {\n\t\t\tthis._finalize(clone(obj.tracks));\n\t\t}\n\n\t\t_finalize(tracks) {\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\ttracks : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : Object.freeze(tracks)\n\t\t\t\t},\n\n\t\t\t\tqueue : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : []\n\t\t\t\t},\n\n\t\t\t\tcurrent : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_rate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_volume : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_mute : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_loop : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_shuffle : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t_destroy() {\n\t\t\t/*\n\t\t\t\tStrictly speaking, self-destruction is not necessary as this object will,\n\t\t\t\teventually, be garbage collected.\n\t\t\t*/\n\t\t\t// Stop playback.\n\t\t\tthis.stop();\n\n\t\t\t// Destroy all owned tracks.\n\t\t\tthis.tracks\n\t\t\t\t.filter(trackObj => trackObj.own)\n\t\t\t\t.forEach(trackObj => trackObj.track._destroy());\n\n\t\t\t// Delete the reference-type properties.\n\t\t\tdelete this.tracks;\n\t\t\tdelete this.queue;\n\t\t}\n\n\t\tload() {\n\t\t\tthis.tracks.forEach(trackObj => trackObj.track.load());\n\t\t}\n\n\t\tunload() {\n\t\t\tthis.stop();\n\t\t\tthis.tracks.forEach(trackObj => trackObj.track.unload());\n\t\t}\n\n\t\tplay() {\n\t\t\tif (this.current === null || this.current.track.isUnavailable() || this.current.track.isEnded()) {\n\t\t\t\tif (this.queue.length === 0) {\n\t\t\t\t\tthis._fillQueue();\n\t\t\t\t}\n\n\t\t\t\tif (!this._next()) {\n\t\t\t\t\treturn Promise.reject(new Error('no tracks were available'));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.current.track.play();\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tthis.play().catch(() => {\n\t\t\t\tconst gestures = _gestureEventNames.map(name => `${name}.AudioList_playWhenAllowed`).join(' ');\n\t\t\t\tjQuery(document).one(gestures, () => {\n\t\t\t\t\tjQuery(document).off('.AudioList_playWhenAllowed');\n\t\t\t\t\tthis.play();\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tpause() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.pause();\n\t\t\t}\n\t\t}\n\n\t\tstop() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.stop();\n\t\t\t\tthis.current = null;\n\t\t\t}\n\n\t\t\tthis._drainQueue();\n\t\t}\n\n\t\tskip() {\n\t\t\tif (this._next()) {\n\t\t\t\tthis.current.track.play();\n\t\t\t}\n\t\t\telse if (this._loop) {\n\t\t\t\tthis.play();\n\t\t\t}\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (typeof duration !== 'number') {\n\t\t\t\tthrow new TypeError('duration parameter must be a number');\n\t\t\t}\n\t\t\tif (typeof toVol !== 'number') {\n\t\t\t\tthrow new TypeError('toVolume parameter must be a number');\n\t\t\t}\n\t\t\tif (fromVol != null && typeof fromVol !== 'number') { // lazy equality for null\n\t\t\t\tthrow new TypeError('fromVolume parameter must be a number');\n\t\t\t}\n\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\tthis._fillQueue();\n\t\t\t}\n\n\t\t\tif (this.current === null || this.current.track.isUnavailable() || this.current.track.isEnded()) {\n\t\t\t\tif (!this._next()) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst adjToVol = Math.clamp(toVol, 0, 1) * this.current.volume;\n\t\t\tlet adjFromVol;\n\n\t\t\tif (fromVol != null) { // lazy equality for null\n\t\t\t\tadjFromVol = Math.clamp(fromVol, 0, 1) * this.current.volume;\n\t\t\t}\n\n\t\t\tthis._volume = toVol; // NOTE: Kludgey, but necessary.\n\n\t\t\treturn this.current.track.fade(duration, adjToVol, adjFromVol);\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\treturn this.fade(duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\treturn this.fade(duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.fadeStop();\n\t\t\t}\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\treturn this._loop;\n\t\t\t}\n\n\t\t\tthis._loop = !!loop;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\treturn this._mute;\n\t\t\t}\n\n\t\t\tthis._mute = !!mute;\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.mute(this._mute);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\treturn this._rate;\n\t\t\t}\n\n\t\t\tif (typeof rate !== 'number') {\n\t\t\t\tthrow new TypeError('rate parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._rate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.rate(this._rate * this.current.rate);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tshuffle(shuffle) {\n\t\t\tif (shuffle == null) { // lazy equality for null\n\t\t\t\treturn this._shuffle;\n\t\t\t}\n\n\t\t\tthis._shuffle = !!shuffle;\n\n\t\t\tif (this.queue.length > 0) {\n\t\t\t\tthis._fillQueue();\n\n\t\t\t\t// Try not to immediately replay the last track when not shuffling.\n\t\t\t\tif (!this._shuffle && this.current !== null && this.queue.length > 1) {\n\t\t\t\t\tconst firstIdx = this.queue.findIndex(trackObj => trackObj === this.current);\n\n\t\t\t\t\tif (firstIdx !== -1) {\n\t\t\t\t\t\tthis.queue.push(...this.queue.splice(0, firstIdx + 1));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\treturn this._volume;\n\t\t\t}\n\n\t\t\tif (typeof volume !== 'number') {\n\t\t\t\tthrow new TypeError('volume parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._volume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.volume(this._volume * this.current.volume);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tduration() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('duration takes no parameters');\n\t\t\t}\n\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.tracks\n\t\t\t\t.map(trackObj => trackObj.track.duration())\n\t\t\t\t.reduce((prev, cur) => prev + cur, 0);\n\t\t}\n\n\t\tremaining() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('remaining takes no parameters');\n\t\t\t}\n\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\tlet remainingTime = this.queue\n\t\t\t\t.map(trackObj => trackObj.track.duration())\n\t\t\t\t.reduce((prev, cur) => prev + cur, 0);\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tremainingTime += this.current.track.remaining();\n\t\t\t}\n\n\t\t\treturn remainingTime;\n\t\t}\n\n\t\ttime() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('time takes no parameters');\n\t\t\t}\n\n\t\t\treturn this.duration() - this.remaining();\n\t\t}\n\n\t\tisPlaying() {\n\t\t\treturn this.current !== null && this.current.track.isPlaying();\n\t\t}\n\n\t\tisPaused() {\n\t\t\treturn this.current === null || this.current.track.isPaused();\n\t\t}\n\n\t\tisStopped() {\n\t\t\treturn this.queue.length === 0 && this.current === null;\n\t\t}\n\n\t\tisEnded() {\n\t\t\treturn this.queue.length === 0 && (this.current === null || this.current.track.isEnded());\n\t\t}\n\n\t\tisFading() {\n\t\t\treturn this.current !== null && this.current.track.isFading();\n\t\t}\n\n\t\t_next() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.stop();\n\t\t\t\tthis.current = null;\n\t\t\t}\n\n\t\t\tlet nextTrack;\n\n\t\t\twhile ((nextTrack = this.queue.shift())) {\n\t\t\t\tif (!nextTrack.track.isUnavailable()) {\n\t\t\t\t\tthis.current = nextTrack;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.current === null) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis.current.track.mute(this._mute);\n\t\t\tthis.current.track.rate(this._rate * this.current.rate);\n\t\t\tthis.current.track.volume(this._volume * this.current.volume);\n\n\t\t\t// Attempt to protect against the `loop` state being reenabled\n\t\t\t// outside of the playlist.  Mostly for unowned tracks.\n\t\t\t//\n\t\t\t// TODO: Should we reapply the `ended` event handler too?\n\t\t\tthis.current.track.loop(false);\n\n\t\t\treturn true;\n\t\t}\n\n\t\t_onEnd() {\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\tif (!this._loop) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._fillQueue();\n\t\t\t}\n\n\t\t\tif (!this._next()) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.current.track.play();\n\t\t}\n\n\t\t_drainQueue() {\n\t\t\tthis.queue.splice(0);\n\t\t}\n\n\t\t_fillQueue() {\n\t\t\tthis._drainQueue();\n\t\t\tthis.queue.push(...this.tracks.filter(trackObj => !trackObj.track.isUnavailable()));\n\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (this._shuffle) {\n\t\t\t\tthis.queue.shuffle();\n\n\t\t\t\t// Try not to immediately replay the last track when shuffling.\n\t\t\t\tif (this.queue.length > 1 && this.queue[0] === this.current) {\n\t\t\t\t\tthis.queue.push(this.queue.shift());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAudioRunner Class.\n\t*******************************************************************************************************************/\n\tclass AudioRunner {\n\t\tconstructor(list) {\n\t\t\tif (!(list instanceof Set || list instanceof AudioRunner)) {\n\t\t\t\tthrow new TypeError('list parameter must be a Set or a AudioRunner instance');\n\t\t\t}\n\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\ttrackIds : {\n\t\t\t\t\tvalue : new Set(list instanceof AudioRunner ? list.trackIds : list)\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tload() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.load);\n\t\t}\n\n\t\tunload() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.unload);\n\t\t}\n\n\t\tplay() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.play);\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.playWhenAllowed);\n\t\t}\n\n\t\tpause() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.pause);\n\t\t}\n\n\t\tstop() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.stop);\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (duration == null || toVol == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fade requires parameters');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fade, duration, toVol, fromVol);\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\tif (duration == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fadeIn requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeIn, duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\tif (duration == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fadeOut requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeOut, duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeStop);\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\tthrow new Error('loop requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.loop, loop);\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\tthrow new Error('mute requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.mute, mute);\n\t\t\treturn this;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\tthrow new Error('rate requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.rate, rate);\n\t\t\treturn this;\n\t\t}\n\n\t\ttime(time) {\n\t\t\tif (time == null) { // lazy equality for null\n\t\t\t\tthrow new Error('time requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.time, time);\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\tthrow new Error('volume requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.volume, volume);\n\t\t\treturn this;\n\t\t}\n\n\t\ton(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.on, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\tone(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.one, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\toff(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.off, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\tstatic _run(ids, fn, ...args) {\n\t\t\tids.forEach(id => {\n\t\t\t\tconst track = _tracks.get(id);\n\n\t\t\t\tif (track) {\n\t\t\t\t\tfn.apply(track, args);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTrack Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.tracks.add(trackId, sources…);\n\n\t\tE.g.\n\t\t\tSimpleAudio.tracks.add(\n\t\t\t\t'over_the_top',\n\t\t\t\t'https://audiohost.tld/id/over_the_top.mp3',\n\t\t\t\t'https://audiohost.tld/id/over_the_top.ogg'\n\t\t\t);\n\t*/\n\tfunction trackAdd(/* trackId , sources… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('track ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('sources'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `track ID \"${id}\"`;\n\n\t\tif (_badIdRe.test(id)) {\n\t\t\tthrow new Error(`invalid ${what}: track IDs must not contain colons or whitespace`);\n\t\t}\n\n\t\tconst sources = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet track;\n\n\t\ttry {\n\t\t\ttrack = _newTrack(sources);\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during track initialization: ${ex.message}`);\n\t\t}\n\n\t\t// If in Test Mode and no supported sources were specified, throw an error.\n\t\tif (Config.debug && !track.hasSource()) {\n\t\t\tthrow new Error(`${what}: no supported audio sources found`);\n\t\t}\n\n\t\t// If a track by the given ID already exists, destroy it.\n\t\tif (_tracks.has(id)) {\n\t\t\t_tracks.get(id)._destroy();\n\t\t}\n\n\t\t// Add the track to the cache.\n\t\t_tracks.set(id, track);\n\t}\n\n\tfunction trackDelete(id) {\n\t\tif (_tracks.has(id)) {\n\t\t\t_tracks.get(id)._destroy();\n\t\t}\n\n\t\t// TODO: Should this also remove references to the track from groups and playlists?\n\n\t\treturn _tracks.delete(id);\n\t}\n\n\tfunction trackClear() {\n\t\t_tracks.forEach(track => track._destroy());\n\t\t_tracks.clear();\n\t}\n\n\tfunction trackHas(id) {\n\t\treturn _tracks.has(id);\n\t}\n\n\tfunction trackGet(id) {\n\t\treturn _tracks.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tGroup Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.groups.add(groupId, trackIds…);\n\n\t\tE.g.\n\t\t\tSimpleAudio.groups.add(':ui', 'beep', 'boop', 'boing');\n\t*/\n\tfunction groupAdd(/* groupId , trackIds… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('group ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('track IDs'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `group ID \"${id}\"`;\n\n\t\tif (id[0] !== ':' || _badIdRe.test(id.slice(1))) {\n\t\t\tthrow new Error(`invalid ${what}: group IDs must start with a colon and must not contain colons or whitespace`);\n\t\t}\n\n\t\tif (_specialIds.includes(id)) {\n\t\t\tthrow new Error(`cannot clobber special ${what}`);\n\t\t}\n\n\t\tconst trackIds = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet group;\n\n\t\ttry {\n\t\t\tgroup = new Set(trackIds.map(trackId => {\n\t\t\t\tif (!_tracks.has(trackId)) {\n\t\t\t\t\tthrow new Error(`track \"${trackId}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\treturn trackId;\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during group initialization: ${ex.message}`);\n\t\t}\n\n\t\t// Add the group to the cache.\n\t\t_groups.set(id, Object.freeze(Array.from(group)));\n\t}\n\n\tfunction groupDelete(id) {\n\t\treturn _groups.delete(id);\n\t}\n\n\tfunction groupClear() {\n\t\t_groups.clear();\n\t}\n\n\tfunction groupHas(id) {\n\t\treturn _groups.has(id);\n\t}\n\n\tfunction groupGet(id) {\n\t\treturn _groups.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPlaylist Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.lists.add(listId, sources…);\n\t\t\tWhere `sources` may be either a track ID or descriptor (object).\n\t\t\tTrack descriptors are either { id, [own], [rate], [volume] } or { sources, [rate], [volume] }.\n\n\t\tNOTE: Rate properties are currently unsupported due to poor browser support.\n\n\t\tE.g.\n\t\t\tSimpleAudio.lists.add(\n\t\t\t\t'bgm',\n\t\t\t\t'over_the_top',\n\t\t\t\t{\n\t\t\t\t\tid     : 'heavens_a_lie',\n\t\t\t\t\tvolume : 0.5,\n\t\t\t\t\town    : true\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tsources : [\n\t\t\t\t\t\t'https://audiohost.tld/id/swamped.mp3',\n\t\t\t\t\t\t'https://audiohost.tld/id/swamped.ogg'\n\t\t\t\t\t],\n\t\t\t\t\tvolume  : 0.75\n\t\t\t\t}\n\t\t\t);\n\t*/\n\tfunction listAdd(/* listId , sources… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('list ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('track IDs'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `list ID \"${id}\"`;\n\n\t\tif (_badIdRe.test(id)) {\n\t\t\treturn this.error(`invalid ${what}: list IDs must not contain colons or whitespace`);\n\t\t}\n\n\t\tconst descriptors = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet list;\n\n\t\ttry {\n\t\t\tlist = new AudioList(descriptors.map(desc => {\n\t\t\t\tif (desc === null) {\n\t\t\t\t\tthrow new Error('track descriptor must be a string or object (type: null)');\n\t\t\t\t}\n\n\t\t\t\tswitch (typeof desc) {\n\t\t\t\tcase 'string':\n\t\t\t\t\t// Simply a track ID, so convert it into an object.\n\t\t\t\t\tdesc = { id : desc }; // eslint-disable-line no-param-reassign\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\tif (!desc.hasOwnProperty('id') && !desc.hasOwnProperty('sources')) {\n\t\t\t\t\t\tthrow new Error('track descriptor must contain one of either an \"id\" or a \"sources\" property');\n\t\t\t\t\t}\n\t\t\t\t\telse if (desc.hasOwnProperty('id') && desc.hasOwnProperty('sources')) {\n\t\t\t\t\t\tthrow new Error('track descriptor must contain either an \"id\" or a \"sources\" property, not both');\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`track descriptor must be a string or object (type: ${typeof desc})`);\n\t\t\t\t}\n\n\t\t\t\tlet own;\n\t\t\t\t// let rate;\n\t\t\t\tlet track;\n\t\t\t\tlet volume;\n\n\t\t\t\tif (desc.hasOwnProperty('id')) {\n\t\t\t\t\tif (typeof desc.id !== 'string') {\n\t\t\t\t\t\tthrow new Error('\"id\" property must be a string');\n\t\t\t\t\t}\n\t\t\t\t\tif (!_tracks.has(desc.id)) {\n\t\t\t\t\t\tthrow new Error(`track \"${desc.id}\" does not exist`);\n\t\t\t\t\t}\n\n\t\t\t\t\ttrack = _tracks.get(desc.id);\n\t\t\t\t}\n\t\t\t\telse if (desc.hasOwnProperty('sources')) {\n\t\t\t\t\tif (!Array.isArray(desc.sources) || desc.sources.length === 0) {\n\t\t\t\t\t\tthrow new Error('\"sources\" property must be a non-empty array');\n\t\t\t\t\t}\n\t\t\t\t\tif (desc.hasOwnProperty('own')) {\n\t\t\t\t\t\tthrow new Error('\"own\" property is not allowed with the \"sources\" property');\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\ttrack = _newTrack(desc.sources);\n\t\t\t\t\t\town = true;\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`error during track initialization: ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// If in Test Mode and no supported sources were specified, return an error.\n\t\t\t\t\tif (Config.debug && !track.hasSource()) {\n\t\t\t\t\t\tthrow new Error('no supported audio sources found');\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (desc.hasOwnProperty('own')) {\n\t\t\t\t\tif (typeof desc.own !== 'boolean') {\n\t\t\t\t\t\tthrow new Error('\"own\" property must be a boolean');\n\t\t\t\t\t}\n\n\t\t\t\t\town = desc.own;\n\n\t\t\t\t\tif (own) {\n\t\t\t\t\t\ttrack = track.clone();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if (desc.hasOwnProperty('rate')) {\n\t\t\t\t// \tif (\n\t\t\t\t// \t\t   typeof desc.rate !== 'number'\n\t\t\t\t// \t\t|| Number.isNaN(desc.rate)\n\t\t\t\t// \t\t|| !Number.isFinite(desc.rate)\n\t\t\t\t// \t) {\n\t\t\t\t// \t\tthrow new Error('\"rate\" property must be a finite number');\n\t\t\t\t// \t}\n\t\t\t\t//\n\t\t\t\t// \trate = desc.rate;\n\t\t\t\t// }\n\n\t\t\t\tif (desc.hasOwnProperty('volume')) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t   typeof desc.volume !== 'number'\n\t\t\t\t\t\t|| Number.isNaN(desc.volume)\n\t\t\t\t\t\t|| !Number.isFinite(desc.volume)\n\t\t\t\t\t\t|| desc.volume < 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new Error('\"volume\" property must be a non-negative finite number');\n\t\t\t\t\t}\n\n\t\t\t\t\tvolume = desc.volume;\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\town    : own != null ? own : false, // lazy equality for null,\n\t\t\t\t\t// rate   : rate != null ? rate : track.rate(), // lazy equality for null,\n\t\t\t\t\ttrack,\n\t\t\t\t\tvolume : volume != null ? volume : track.volume() // lazy equality for null\n\t\t\t\t};\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during playlist initialization: ${ex.message}`);\n\t\t}\n\n\t\t// If a playlist by the given ID already exists, destroy it.\n\t\tif (_lists.has(id)) {\n\t\t\t_lists.get(id)._destroy();\n\t\t}\n\n\t\t// Add the playlist to the cache.\n\t\t_lists.set(id, list);\n\t}\n\n\tfunction listDelete(id) {\n\t\tif (_lists.has(id)) {\n\t\t\t_lists.get(id)._destroy();\n\t\t}\n\n\t\treturn _lists.delete(id);\n\t}\n\n\tfunction listClear() {\n\t\t_lists.forEach(list => list._destroy());\n\t\t_lists.clear();\n\t}\n\n\tfunction listHas(id) {\n\t\treturn _lists.has(id);\n\t}\n\n\tfunction listGet(id) {\n\t\treturn _lists.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tRunner Functions.\n\t*******************************************************************************************************************/\n\tconst _runnerParseSelector = (() => {\n\t\tconst notWsRe = /\\S/g;\n\t\tconst parenRe = /[()]/g;\n\n\t\tfunction processNegation(str, startPos) {\n\t\t\tlet match;\n\n\t\t\tnotWsRe.lastIndex = startPos;\n\t\t\tmatch = notWsRe.exec(str);\n\n\t\t\tif (match === null || match[0] !== '(') {\n\t\t\t\tthrow new Error('invalid \":not()\" syntax: missing parentheticals');\n\t\t\t}\n\n\t\t\tparenRe.lastIndex = notWsRe.lastIndex;\n\t\t\tconst start  = notWsRe.lastIndex;\n\t\t\tconst result = { str : '', nextMatch : -1 };\n\t\t\tlet depth = 1;\n\n\t\t\twhile ((match = parenRe.exec(str)) !== null) {\n\t\t\t\tif (match[0] === '(') {\n\t\t\t\t\t++depth;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t--depth;\n\t\t\t\t}\n\n\t\t\t\tif (depth < 1) {\n\t\t\t\t\tresult.nextMatch = parenRe.lastIndex;\n\t\t\t\t\tresult.str = str.slice(start, result.nextMatch - 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tfunction parseSelector(idArg) {\n\t\t\tconst ids  = [];\n\t\t\tconst idRe = /:?[^\\s:()]+/g;\n\t\t\tlet match;\n\n\t\t\twhile ((match = idRe.exec(idArg)) !== null) {\n\t\t\t\tconst id = match[0];\n\n\t\t\t\t// Group negation.\n\t\t\t\tif (id === ':not') {\n\t\t\t\t\tif (ids.length === 0) {\n\t\t\t\t\t\tthrow new Error('invalid negation: no group ID preceded \":not()\"');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst parent = ids[ids.length - 1];\n\n\t\t\t\t\tif (parent.id[0] !== ':') {\n\t\t\t\t\t\tthrow new Error(`invalid negation of track \"${parent.id}\": only groups may be negated with \":not()\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst negation = processNegation(idArg, idRe.lastIndex);\n\n\t\t\t\t\tif (negation.nextMatch === -1) {\n\t\t\t\t\t\tthrow new Error('unknown error parsing \":not()\"');\n\t\t\t\t\t}\n\n\t\t\t\t\tidRe.lastIndex = negation.nextMatch;\n\t\t\t\t\tparent.not = parseSelector(negation.str);\n\t\t\t\t}\n\n\t\t\t\t// Group or track ID.\n\t\t\t\telse {\n\t\t\t\t\tids.push({ id });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn ids;\n\t\t}\n\n\t\treturn parseSelector;\n\t})();\n\n\t/*\n\t\tSimpleAudio.select(selector).…;\n\n\t\tE.g.\n\t\t\tSimpleAudio.select(':ui').…\n\t\t\tSimpleAudio.select(':ui:not(boop)').…\n\t\t\tSimpleAudio.select('boop beep').…\n\t\t\tSimpleAudio.select(':ui :sfx').…\n\t\t\tSimpleAudio.select(':ui:not(boop) :sfx overthetop').…\n\t*/\n\tfunction runnerGet(/* selector */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('no track selector specified');\n\t\t}\n\n\t\tconst selector = String(arguments[0]).trim();\n\t\tconst trackIds = new Set();\n\n\t\ttry {\n\t\t\tconst allIds = Array.from(_tracks.keys());\n\n\t\t\tfunction renderIds(idObj) {\n\t\t\t\tconst id = idObj.id;\n\t\t\t\tlet ids;\n\n\t\t\t\tswitch (id) {\n\t\t\t\tcase ':all':     ids = allIds; break;\n\t\t\t\tcase ':looped':  ids = allIds.filter(id => _tracks.get(id).loop()); break;\n\t\t\t\tcase ':muted':   ids = allIds.filter(id => _tracks.get(id).mute()); break;\n\t\t\t\tcase ':paused':  ids = allIds.filter(id => _tracks.get(id).isPaused()); break;\n\t\t\t\tcase ':playing': ids = allIds.filter(id => _tracks.get(id).isPlaying()); break;\n\t\t\t\tdefault:         ids = id[0] === ':' ? _groups.get(id) : [id]; break;\n\t\t\t\t}\n\n\t\t\t\tif (idObj.hasOwnProperty('not')) {\n\t\t\t\t\tconst negated = idObj.not.map(idObj => renderIds(idObj)).flat(Infinity);\n\t\t\t\t\tids = ids.filter(id => !negated.includes(id));\n\t\t\t\t}\n\n\t\t\t\treturn ids;\n\t\t\t}\n\n\t\t\t_runnerParseSelector(selector).forEach(idObj => renderIds(idObj).forEach(id => {\n\t\t\t\tif (!_tracks.has(id)) {\n\t\t\t\t\tthrow new Error(`track \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\ttrackIds.add(id);\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`error during runner initialization: ${ex.message}`);\n\t\t}\n\n\t\treturn new AudioRunner(trackIds);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMaster Audio Functions.\n\t*******************************************************************************************************************/\n\tfunction masterLoad() {\n\t\tpublish('load');\n\t}\n\n\tfunction masterLoadWithScreen() {\n\t\tpublish('loadwithscreen');\n\t}\n\n\tfunction masterMute(mute) {\n\t\tif (mute == null) { // lazy equality for null\n\t\t\treturn _masterMute;\n\t\t}\n\n\t\t_masterMute = !!mute;\n\t\tpublish('mute', _masterMute);\n\t}\n\n\tfunction masterMuteOnHidden(mute) {\n\t\t// NOTE: Some older browsers—notably: IE 9—do not support the Page Visibility API.\n\t\tif (!Visibility.isEnabled()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (mute == null) { // lazy equality for null\n\t\t\treturn _masterMuteOnHidden;\n\t\t}\n\n\t\t_masterMuteOnHidden = !!mute;\n\n\t\tconst namespace = '.SimpleAudio_masterMuteOnHidden';\n\n\t\tif (_masterMuteOnHidden) {\n\t\t\tconst visibilityChange = `${Visibility.changeEvent}${namespace}`;\n\t\t\tjQuery(document)\n\t\t\t\t.off(namespace)\n\t\t\t\t.on(visibilityChange, () => masterMute(Visibility.isHidden()));\n\n\t\t\t// Only change the mute state initially if hidden.\n\t\t\tif (Visibility.isHidden()) {\n\t\t\t\tmasterMute(true);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tjQuery(document).off(namespace);\n\t\t}\n\t}\n\n\tfunction masterRate(rate) {\n\t\tif (rate == null) { // lazy equality for null\n\t\t\treturn _masterRate;\n\t\t}\n\n\t\tif (typeof rate !== 'number' || Number.isNaN(rate) || !Number.isFinite(rate)) {\n\t\t\tthrow new Error('rate must be a finite number');\n\t\t}\n\n\t\t_masterRate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\t\tpublish('rate', _masterRate);\n\t}\n\n\tfunction masterStop() {\n\t\tpublish('stop');\n\t}\n\n\tfunction masterUnload() {\n\t\tpublish('unload');\n\t}\n\n\tfunction masterVolume(volume) {\n\t\tif (volume == null) { // lazy equality for null\n\t\t\treturn _masterVolume;\n\t\t}\n\n\t\tif (typeof volume !== 'number' || Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\tthrow new Error('volume must be a finite number');\n\t\t}\n\n\t\t_masterVolume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\t\tpublish('volume', _masterVolume);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSubscription Functions.\n\t*******************************************************************************************************************/\n\tfunction subscribe(id, callback) {\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new Error('callback parameter must be a function');\n\t\t}\n\n\t\t_subscribers.set(id, callback);\n\t}\n\n\tfunction unsubscribe(id) {\n\t\t_subscribers.delete(id);\n\t}\n\n\tfunction publish(mesg, data) {\n\t\t_subscribers.forEach(fn => fn(mesg, data));\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _newTrack(sources) {\n\t\treturn new AudioTrack(sources.map(source => {\n\t\t\t// Handle audio passages.\n\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\tif (passage.tags.includes('Twine.audio')) {\n\t\t\t\t\treturn passage.text.trim();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle URIs—possibly prefixed with a format specifier.\n\t\t\tconst match = _formatSpecRe.exec(source);\n\t\t\treturn match === null ? source : {\n\t\t\t\tformat : match[1],\n\t\t\t\tsrc    : match[2]\n\t\t\t};\n\t\t}));\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Track Functions.\n\t\ttracks : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : trackAdd },\n\t\t\t\tdelete : { value : trackDelete },\n\t\t\t\tclear  : { value : trackClear },\n\t\t\t\thas    : { value : trackHas },\n\t\t\t\tget    : { value : trackGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Group Functions.\n\t\tgroups : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : groupAdd },\n\t\t\t\tdelete : { value : groupDelete },\n\t\t\t\tclear  : { value : groupClear },\n\t\t\t\thas    : { value : groupHas },\n\t\t\t\tget    : { value : groupGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Playlist Functions.\n\t\tlists : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : listAdd },\n\t\t\t\tdelete : { value : listDelete },\n\t\t\t\tclear  : { value : listClear },\n\t\t\t\thas    : { value : listHas },\n\t\t\t\tget    : { value : listGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Runner Functions.\n\t\tselect : { value : runnerGet },\n\n\t\t// Master Audio Functions.\n\t\tload           : { value : masterLoad },\n\t\tloadWithScreen : { value : masterLoadWithScreen },\n\t\tmute           : { value : masterMute },\n\t\tmuteOnHidden   : { value : masterMuteOnHidden },\n\t\trate           : { value : masterRate },\n\t\tstop           : { value : masterStop },\n\t\tunload         : { value : masterUnload },\n\t\tvolume         : { value : masterVolume }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tstate.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Diff, Engine, PRNGWrapper, Patterns, clone, session, storage */\n\nvar State = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// History moment stack.\n\tlet _history = [];\n\n\t// Currently active/played moment.\n\tlet _active = momentCreate();\n\n\t// Currently active/played moment index.\n\tlet _activeIndex = -1;\n\n\t// Titles of all moments which have expired (i.e. fallen off the bottom of the stack).\n\tlet _expired = [];\n\n\t// (optional) Seedable PRNG object.\n\tlet _prng = null;\n\n\t// Temporary variables object.\n\tlet _tempVariables = {};\n\n\n\t/*******************************************************************************************************************\n\t\tState Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tResets the story state.\n\t*/\n\tfunction stateReset() {\n\t\tif (DEBUG) { console.log('[State/stateReset()]'); }\n\n\t\t/*\n\t\t\tDelete the active session.\n\t\t*/\n\t\tsession.delete('state');\n\n\t\t/*\n\t\t\tReset the properties.\n\t\t*/\n\t\t_history     = [];\n\t\t_active      = momentCreate();\n\t\t_activeIndex = -1;\n\t\t_expired     = [];\n\t\t_prng        = _prng === null ? null : new PRNGWrapper(_prng.seed, false);\n\t}\n\n\t/*\n\t\tRestores the story state from the active session.\n\t*/\n\tfunction stateRestore() {\n\t\tif (DEBUG) { console.log('[State/stateRestore()]'); }\n\n\t\t/*\n\t\t\tAttempt to restore an active session.\n\t\t*/\n\t\tif (session.has('state')) {\n\t\t\t/*\n\t\t\t\tRetrieve the session.\n\t\t\t*/\n\t\t\tconst stateObj = session.get('state');\n\n\t\t\tif (DEBUG) { console.log('\\tsession state:', stateObj); }\n\n\t\t\tif (stateObj == null) { // lazy equality for null\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tRestore the session.\n\t\t\t*/\n\t\t\tstateUnmarshal(stateObj);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tReturns the current story state marshaled into a serializable object.\n\t*/\n\tfunction stateMarshal(noDelta) {\n\t\t/*\n\t\t\tGather the properties.\n\t\t*/\n\t\tconst stateObj = {\n\t\t\tindex : _activeIndex\n\t\t};\n\n\t\tif (noDelta) {\n\t\t\tstateObj.history = clone(_history);\n\t\t}\n\t\telse {\n\t\t\tstateObj.delta = historyDeltaEncode(_history);\n\t\t}\n\n\t\tif (_expired.length > 0) {\n\t\t\tstateObj.expired = [];\n\t\t}\n\n\t\tif (_prng !== null) {\n\t\t\tstateObj.seed = _prng.seed;\n\t\t}\n\n\t\treturn stateObj;\n\t}\n\n\t/*\n\t\tRestores the story state from a marshaled story state serialization object.\n\t*/\n\tfunction stateUnmarshal(stateObj, noDelta) {\n\t\tif (stateObj == null) { // lazy equality for null\n\t\t\tthrow new Error('state object is null or undefined');\n\t\t}\n\n\t\tif (\n\t\t\t   !stateObj.hasOwnProperty(noDelta ? 'history' : 'delta')\n\t\t\t|| stateObj[noDelta ? 'history' : 'delta'].length === 0\n\t\t) {\n\t\t\tthrow new Error('state object has no history or history is empty');\n\t\t}\n\n\t\tif (!stateObj.hasOwnProperty('index')) {\n\t\t\tthrow new Error('state object has no index');\n\t\t}\n\n\t\tif (_prng !== null && !stateObj.hasOwnProperty('seed')) {\n\t\t\tthrow new Error('state object has no seed, but PRNG is enabled');\n\t\t}\n\n\t\tif (_prng === null && stateObj.hasOwnProperty('seed')) {\n\t\t\tthrow new Error('state object has seed, but PRNG is disabled');\n\t\t}\n\n\t\t/*\n\t\t\tRestore the properties.\n\t\t*/\n\t\t_history     = noDelta ? clone(stateObj.history) : historyDeltaDecode(stateObj.delta);\n\t\t_activeIndex = stateObj.index;\n\t\t_expired     = stateObj.hasOwnProperty('expired') ? [...stateObj.expired] : [];\n\n\t\tif (stateObj.hasOwnProperty('seed')) {\n\t\t\t/*\n\t\t\t\tWe only need to restore the PRNG's seed here as `momentActivate()` will handle\n\t\t\t\tfully restoring the PRNG to its proper state.\n\t\t\t*/\n\t\t\t_prng.seed = stateObj.seed;\n\t\t}\n\n\t\t/*\n\t\t\tActivate the current moment (do this only after all properties have been restored).\n\t\t*/\n\t\tmomentActivate(_activeIndex);\n\t}\n\n\t/*\n\t\tReturns the current story state marshaled into a save-compatible serializable object.\n\t*/\n\tfunction stateMarshalForSave() {\n\t\treturn stateMarshal(true);\n\t}\n\n\t/*\n\t\tRestores the story state from a marshaled save-compatible story state serialization object.\n\t*/\n\tfunction stateUnmarshalForSave(stateObj) {\n\t\treturn stateUnmarshal(stateObj, true);\n\t}\n\n\t/*\n\t\tReturns the titles of expired moments.\n\t*/\n\tfunction stateExpired() {\n\t\treturn _expired;\n\t}\n\n\t/*\n\t\tReturns the total number of played moments (expired + in-play history moments).\n\t*/\n\tfunction stateTurns() {\n\t\treturn _expired.length + historyLength();\n\t}\n\n\t/*\n\t\tReturns the passage titles of all played moments (expired + in-play history moments).\n\t*/\n\tfunction stateTitles() {\n\t\treturn _expired.concat(_history.slice(0, historyLength()).map(moment => moment.title));\n\t}\n\n\t/*\n\t\tReturns whether a passage with the given title has been played (expired + in-play history moments).\n\t*/\n\tfunction stateHasPlayed(title) {\n\t\tif (title == null || title === '') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tif (_expired.includes(title)) {\n\t\t\treturn true;\n\t\t}\n\t\telse if (_history.slice(0, historyLength()).some(moment => moment.title === title)) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMoment Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a new moment object created from the given passage title and variables object.\n\t*/\n\tfunction momentCreate(title, variables) {\n\t\treturn {\n\t\t\ttitle     : title == null ? '' : String(title),       // lazy equality for null\n\t\t\tvariables : variables == null ? {} : clone(variables) // lazy equality for null\n\t\t};\n\t}\n\n\t/*\n\t\tReturns the active (present) moment.\n\t*/\n\tfunction momentActive() {\n\t\treturn _active;\n\t}\n\n\t/*\n\t\tReturns the index within the history of the active (present) moment.\n\t*/\n\tfunction momentActiveIndex() {\n\t\treturn _activeIndex;\n\t}\n\n\t/*\n\t\tReturns the title from the active (present) moment.\n\t*/\n\tfunction momentActiveTitle() {\n\t\treturn _active.title;\n\t}\n\n\t/*\n\t\tReturns the variables from the active (present) moment.\n\t*/\n\tfunction momentActiveVariables() {\n\t\treturn _active.variables;\n\t}\n\n\t/*\n\t\tReturns the active (present) moment after setting it to either the given moment object\n\t\tor the moment object at the given history index.  Additionally, updates the active session\n\t\tand triggers a history update event.\n\t*/\n\tfunction momentActivate(moment) {\n\t\tif (moment == null) { // lazy equality for null\n\t\t\tthrow new Error('moment activation attempted with null or undefined');\n\t\t}\n\n\t\t/*\n\t\t\tSet the active moment.\n\t\t*/\n\t\tswitch (typeof moment) {\n\t\tcase 'object':\n\t\t\t_active = clone(moment);\n\t\t\tbreak;\n\n\t\tcase 'number':\n\t\t\tif (historyIsEmpty()) {\n\t\t\t\tthrow new Error('moment activation attempted with index on empty history');\n\t\t\t}\n\n\t\t\tif (moment < 0 || moment >= historySize()) {\n\t\t\t\tthrow new RangeError(`moment activation attempted with out-of-bounds index; need [0, ${historySize() - 1}], got ${moment}`);\n\t\t\t}\n\n\t\t\t_active = clone(_history[moment]);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new TypeError(`moment activation attempted with a \"${typeof moment}\"; must be an object or valid history stack index`);\n\t\t}\n\n\t\t/*\n\t\t\tRestore the seedable PRNG.\n\n\t\t\tNOTE: We cannot simply set `_prng.pull` to `_active.pull` as that would\n\t\t\tnot properly mutate the PRNG's internal state.\n\t\t*/\n\t\tif (_prng !== null) {\n\t\t\t_prng = PRNGWrapper.unmarshal({\n\t\t\t\tseed : _prng.seed,\n\t\t\t\tpull : _active.pull\n\t\t\t});\n\t\t}\n\n\t\t/*\n\t\t\tUpdate the active session.\n\t\t*/\n\t\tsession.set('state', stateMarshal());\n\n\t\t/*\n\t\t\tTrigger a global `:historyupdate` event.\n\n\t\t\tNOTE: We do this here because setting a new active moment is a core component\n\t\t\tof, virtually, all history updates.\n\t\t*/\n\t\tjQuery.event.trigger(':historyupdate');\n\n\t\treturn _active;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tHistory Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the moment history.\n\t*/\n\tfunction historyGet() {\n\t\treturn _history;\n\t}\n\n\t/*\n\t\tReturns the number of active history moments (past only).\n\t*/\n\tfunction historyLength() {\n\t\treturn _activeIndex + 1;\n\t}\n\n\t/*\n\t\tReturns the total number of history moments (past + future).\n\t*/\n\tfunction historySize() {\n\t\treturn _history.length;\n\t}\n\n\t/*\n\t\tReturns whether the history is empty.\n\t*/\n\tfunction historyIsEmpty() {\n\t\treturn _history.length === 0;\n\t}\n\n\t/*\n\t\tReturns the current (pre-play version of the active) moment within the history.\n\t*/\n\tfunction historyCurrent() {\n\t\treturn _history.length > 0 ? _history[_activeIndex] : null;\n\t}\n\n\t/*\n\t\tReturns the topmost (most recent) moment within the history.\n\t*/\n\tfunction historyTop() {\n\t\treturn _history.length > 0 ? _history[_history.length - 1] : null;\n\t}\n\n\t/*\n\t\tReturns the bottommost (least recent) moment within the history.\n\t*/\n\tfunction historyBottom() {\n\t\treturn _history.length > 0 ? _history[0] : null;\n\t}\n\n\t/*\n\t\tReturns the moment at the given index within the history.\n\t*/\n\tfunction historyIndex(index) {\n\t\tif (historyIsEmpty() || index < 0 || index > _activeIndex) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn _history[index];\n\t}\n\n\t/*\n\t\tReturns the moment at the given offset from the active moment within the history.\n\t*/\n\tfunction historyPeek(offset) {\n\t\tif (historyIsEmpty()) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst lengthOffset = 1 + (offset ? Math.abs(offset) : 0);\n\n\t\tif (lengthOffset > historyLength()) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn _history[historyLength() - lengthOffset];\n\t}\n\n\t/*\n\t\tReturns whether a moment with the given title exists within the history.\n\t*/\n\tfunction historyHas(title) {\n\t\tif (historyIsEmpty() || title == null || title === '') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (let i = _activeIndex; i >= 0; --i) {\n\t\t\tif (_history[i].title === title) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tCreates a new moment and pushes it onto the history, discarding future moments if necessary.\n\t*/\n\tfunction historyCreate(title) {\n\t\tif (DEBUG) { console.log(`[State/historyCreate(title: \"${title}\")]`); }\n\n\t\t/*\n\t\t\tTODO: It might be good to have some assertions about the passage title here.\n\t\t*/\n\n\t\t/*\n\t\t\tIf we're not at the top of the stack, discard the future moments.\n\t\t*/\n\t\tif (historyLength() < historySize()) {\n\t\t\tif (DEBUG) { console.log(`\\tnon-top push; discarding ${historySize() - historyLength()} future moments`); }\n\n\t\t\t_history.splice(historyLength(), historySize() - historyLength());\n\t\t}\n\n\t\t/*\n\t\t\tPush the new moment onto the history stack.\n\t\t*/\n\t\t_history.push(momentCreate(title, _active.variables));\n\n\t\tif (_prng) {\n\t\t\thistoryTop().pull = _prng.pull;\n\t\t}\n\n\t\t/*\n\t\t\tTruncate the history, if necessary, by discarding moments from the bottom.\n\t\t*/\n\t\tif (Config.history.maxStates > 0) {\n\t\t\twhile (historySize() > Config.history.maxStates) {\n\t\t\t\t_expired.push(_history.shift().title);\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t\tActivate the new top moment.\n\t\t*/\n\t\t_activeIndex = historySize() - 1;\n\t\tmomentActivate(_activeIndex);\n\n\t\treturn historyLength();\n\t}\n\n\t/*\n\t\tActivate the moment at the given index within the history.\n\t*/\n\tfunction historyGoTo(index) {\n\t\tif (DEBUG) { console.log(`[State/historyGoTo(index: ${index})]`); }\n\n\t\tif (\n\t\t\t   index == null /* lazy equality for null */\n\t\t\t|| index < 0\n\t\t\t|| index >= historySize()\n\t\t\t|| index === _activeIndex\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\t_activeIndex = index;\n\t\tmomentActivate(_activeIndex);\n\n\t\treturn true;\n\t}\n\n\t/*\n\t\tActivate the moment at the given offset from the active moment within the history.\n\t*/\n\tfunction historyGo(offset) {\n\t\tif (DEBUG) { console.log(`[State/historyGo(offset: ${offset})]`); }\n\n\t\tif (offset == null || offset === 0) { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\treturn historyGoTo(_activeIndex + offset);\n\t}\n\n\t/*\n\t\tReturns the delta encoded form of the given history array.\n\t*/\n\tfunction historyDeltaEncode(historyArr) {\n\t\tif (!Array.isArray(historyArr)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (historyArr.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst delta = [clone(historyArr[0])];\n\n\t\tfor (let i = 1, iend = historyArr.length; i < iend; ++i) {\n\t\t\tdelta.push(Diff.diff(historyArr[i - 1], historyArr[i]));\n\t\t}\n\n\t\treturn delta;\n\t}\n\n\t/*\n\t\tReturns a history array from the given delta encoded history array.\n\t*/\n\tfunction historyDeltaDecode(delta) {\n\t\tif (!Array.isArray(delta)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (delta.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst historyArr = [clone(delta[0])];\n\n\t\tfor (let i = 1, iend = delta.length; i < iend; ++i) {\n\t\t\thistoryArr.push(Diff.patch(historyArr[i - 1], delta[i]));\n\t\t}\n\n\t\treturn historyArr;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPRNG Functions.\n\t*******************************************************************************************************************/\n\tfunction prngInit(seed, useEntropy) {\n\t\tif (DEBUG) { console.log(`[State/prngInit(seed: ${seed}, useEntropy: ${useEntropy})]`); }\n\n\t\tif (!historyIsEmpty()) {\n\t\t\tlet scriptSection;\n\n\t\t\tif (TWINE1) { // for Twine 1\n\t\t\t\tscriptSection = 'a script-tagged passage';\n\t\t\t}\n\t\t\telse { // for Twine 2\n\t\t\t\tscriptSection = 'the Story JavaScript';\n\t\t\t}\n\n\t\t\tthrow new Error(`State.initPRNG must be called during initialization, within either ${scriptSection} or the StoryInit special passage`);\n\t\t}\n\n\t\t_prng = new PRNGWrapper(seed, useEntropy);\n\t\t_active.pull = _prng.pull;\n\t}\n\n\tfunction prngIsEnabled() {\n\t\treturn _prng !== null;\n\t}\n\n\tfunction prngPull() {\n\t\treturn _prng ? _prng.pull : NaN;\n\t}\n\n\tfunction prngSeed() {\n\t\treturn _prng ? _prng.seed : null;\n\t}\n\n\tfunction prngRandom() {\n\t\tif (DEBUG) { console.log('[State/prngRandom()]'); }\n\n\t\treturn _prng ? _prng.random() : Math.random();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTemporary Variables Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tClear the temporary variables.\n\t*/\n\tfunction tempVariablesClear() {\n\t\tif (DEBUG) { console.log('[State/tempVariablesReset()]'); }\n\n\t\t_tempVariables = {};\n\n\t\t/* legacy */\n\t\tTempVariables = _tempVariables; // eslint-disable-line no-undef\n\t\t/* /legacy */\n\t}\n\n\t/*\n\t\tReturns the current temporary variables.\n\t*/\n\tfunction tempVariables() {\n\t\treturn _tempVariables;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tVariable Chain Parsing Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the value of the given story/temporary variable.\n\t*/\n\tfunction variableGet(name) {\n\t\tconst varData = _parseVariableChain(name);\n\n\t\tif (varData === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst pNames = varData.names;\n\t\tlet retVal = varData.store;\n\n\t\tfor (let i = 0, iend = pNames.length; i < iend; ++i) {\n\t\t\tif (typeof retVal[pNames[i]] === 'undefined') {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tretVal = retVal[pNames[i]];\n\t\t}\n\n\t\treturn retVal;\n\t}\n\n\t/*\n\t\tSets the value of the given story/temporary variable.\n\t*/\n\tfunction variableSet(name, value) {\n\t\tconst varData = _parseVariableChain(name);\n\n\t\tif (varData === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst pNames  = varData.names;\n\t\tconst varName = pNames.pop();\n\t\tlet baseObj = varData.store;\n\n\t\tfor (let i = 0, iend = pNames.length; i < iend; ++i) {\n\t\t\tif (typeof baseObj[pNames[i]] === 'undefined') {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tbaseObj = baseObj[pNames[i]];\n\t\t}\n\n\t\tbaseObj[varName] = value;\n\t\treturn true;\n\t}\n\n\t/*\n\t\tReturns the property name chain of the given story/temporary variable,\n\t\twhich may be of arbitrary complexity.\n\t*/\n\tconst _parseVarRegExp = new RegExp(`^(?:${Patterns.variableSigil}(${Patterns.identifier})|\\\\.(${Patterns.identifier})|\\\\[(?:(?:\"((?:\\\\\\\\.|[^\"\\\\\\\\])+)\")|(?:'((?:\\\\\\\\.|[^'\\\\\\\\])+)')|(${Patterns.variableSigil}${Patterns.identifierFirstChar}.*)|(\\\\d+))\\\\])`);\n\tfunction _parseVariableChain(varText) {\n\t\tconst retVal = {\n\t\t\tstore : varText[0] === '$' ? State.variables : State.temporary,\n\t\t\tnames : []\n\t\t};\n\t\tlet text  = varText;\n\t\tlet match;\n\n\t\twhile ((match = _parseVarRegExp.exec(text)) !== null) {\n\t\t\t// Remove full match from text.\n\t\t\ttext = text.slice(match[0].length);\n\n\t\t\t// Base variable.\n\t\t\tif (match[1]) {\n\t\t\t\tretVal.names.push(match[1]);\n\t\t\t}\n\n\t\t\t// Dot property.\n\t\t\telse if (match[2]) {\n\t\t\t\tretVal.names.push(match[2]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (double quoted).\n\t\t\telse if (match[3]) {\n\t\t\t\tretVal.names.push(match[3]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (single quoted).\n\t\t\telse if (match[4]) {\n\t\t\t\tretVal.names.push(match[4]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (embedded variable).\n\t\t\telse if (match[5]) {\n\t\t\t\tretVal.names.push(variableGet(match[5]));\n\t\t\t}\n\n\t\t\t// Square-bracketed property (numeric index).\n\t\t\telse if (match[6]) {\n\t\t\t\tretVal.names.push(Number(match[6]));\n\t\t\t}\n\t\t}\n\n\t\treturn text === '' ? retVal : null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tStory Metadata Functions.\n\t*******************************************************************************************************************/\n\tconst _METADATA_STORE = 'metadata';\n\n\tfunction metadataClear() {\n\t\tstorage.delete(_METADATA_STORE);\n\t}\n\n\tfunction metadataDelete(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.delete key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\n\t\tif (store && store.hasOwnProperty(key)) {\n\t\t\tif (Object.keys(store).length === 1) {\n\t\t\t\tstorage.delete(_METADATA_STORE);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdelete store[key];\n\t\t\t\tstorage.set(_METADATA_STORE, store);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction metadataGet(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.get key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store && store.hasOwnProperty(key) ? store[key] : undefined;\n\t}\n\n\tfunction metadataHas(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.has key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store && store.hasOwnProperty(key);\n\t}\n\n\tfunction metadataSet(key, value) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.set key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tif (typeof value === 'undefined') {\n\t\t\tmetadataDelete(key);\n\t\t}\n\t\telse {\n\t\t\tconst store = storage.get(_METADATA_STORE) || {};\n\t\t\tstore[key] = value;\n\t\t\tstorage.set(_METADATA_STORE, store);\n\t\t}\n\t}\n\n\tfunction metadataSize() {\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store ? Object.keys(store).length : 0;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tState Functions.\n\t\t*/\n\t\treset            : { value : stateReset },\n\t\trestore          : { value : stateRestore },\n\t\tmarshalForSave   : { value : stateMarshalForSave },\n\t\tunmarshalForSave : { value : stateUnmarshalForSave },\n\t\texpired          : { get : stateExpired },\n\t\tturns            : { get : stateTurns },\n\t\tpassages         : { get : stateTitles },\n\t\thasPlayed        : { value : stateHasPlayed },\n\n\t\t/*\n\t\t\tMoment Functions.\n\t\t*/\n\t\tactive      : { get : momentActive },\n\t\tactiveIndex : { get : momentActiveIndex },\n\t\tpassage     : { get : momentActiveTitle },     // shortcut for `State.active.title`\n\t\tvariables   : { get : momentActiveVariables }, // shortcut for `State.active.variables`\n\n\t\t/*\n\t\t\tHistory Functions.\n\t\t*/\n\t\thistory     : { get : historyGet },\n\t\tlength      : { get : historyLength },\n\t\tsize        : { get : historySize },\n\t\tisEmpty     : { value : historyIsEmpty },\n\t\tcurrent     : { get : historyCurrent },\n\t\ttop         : { get : historyTop },\n\t\tbottom      : { get : historyBottom },\n\t\tindex       : { value : historyIndex },\n\t\tpeek        : { value : historyPeek },\n\t\thas         : { value : historyHas },\n\t\tcreate      : { value : historyCreate },\n\t\tgoTo        : { value : historyGoTo },\n\t\tgo          : { value : historyGo },\n\t\tdeltaEncode : { value : historyDeltaEncode },\n\t\tdeltaDecode : { value : historyDeltaDecode },\n\n\t\t/*\n\t\t\tPRNG Functions.\n\t\t*/\n\t\tprng : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tinit      : { value : prngInit },\n\t\t\t\tisEnabled : { value : prngIsEnabled },\n\t\t\t\tpull      : { get : prngPull },\n\t\t\t\tseed      : { get : prngSeed }\n\t\t\t}))\n\t\t},\n\t\trandom : { value : prngRandom },\n\n\t\t/*\n\t\t\tTemporary Variables Functions.\n\t\t*/\n\t\tclearTemporary : { value : tempVariablesClear },\n\t\ttemporary      : { get : tempVariables },\n\n\t\t/*\n\t\t\tVariable Chain Parsing Functions.\n\t\t*/\n\t\tgetVar : { value : variableGet },\n\t\tsetVar : { value : variableSet },\n\n\t\t/*\n\t\t\tStory Metadata Functions.\n\t\t*/\n\t\tmetadata : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tclear  : { value : metadataClear },\n\t\t\t\tdelete : { value : metadataDelete },\n\t\t\t\tget    : { value : metadataGet },\n\t\t\t\thas    : { value : metadataHas },\n\t\t\t\tset    : { value : metadataSet },\n\t\t\t\tsize   : { get : metadataSize }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tinitPRNG : { value : prngInit },\n\t\trestart  : { value : () => Engine.restart() },\n\t\tbackward : { value : () => Engine.backward() },\n\t\tforward  : { value : () => Engine.forward() },\n\t\tdisplay  : { value : (...args) => Engine.display(...args) },\n\t\tshow     : { value : (...args) => Engine.show(...args) },\n\t\tplay     : { value : (...args) => Engine.play(...args) }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/scripting.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Engine, Patterns, State, Story, Util */\n\nvar Scripting = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/* eslint-disable no-unused-vars */\n\n\t/*******************************************************************************************************************\n\t\tDeprecated Legacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Returns the jQuery-wrapped target element(s) after making them accessible\n\t\tclickables (ARIA compatibility).\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction addAccessibleClickHandler(targets, selector, handler, one, namespace) {\n\t\tif (arguments.length < 2) {\n\t\t\tthrow new Error('addAccessibleClickHandler insufficient number of parameters');\n\t\t}\n\n\t\tlet fn;\n\t\tlet opts;\n\n\t\tif (typeof selector === 'function') {\n\t\t\tfn = selector;\n\t\t\topts = {\n\t\t\t\tnamespace : one,\n\t\t\t\tone       : !!handler\n\t\t\t};\n\t\t}\n\t\telse {\n\t\t\tfn = handler;\n\t\t\topts = {\n\t\t\t\tnamespace,\n\t\t\t\tone : !!one,\n\t\t\t\tselector\n\t\t\t};\n\t\t}\n\n\t\tif (typeof fn !== 'function') {\n\t\t\tthrow new TypeError('addAccessibleClickHandler handler parameter must be a function');\n\t\t}\n\n\t\treturn jQuery(targets).ariaClick(opts, fn);\n\t}\n\n\t/*\n\t\t[DEPRECATED] Returns a new DOM element, optionally appending it to the passed DOM element, if any.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction insertElement(place, type, id, classNames, text, title) { // eslint-disable-line max-params\n\t\tconst $el = jQuery(document.createElement(type));\n\n\t\t// Add attributes/properties.\n\t\tif (id) {\n\t\t\t$el.attr('id', id);\n\t\t}\n\n\t\tif (classNames) {\n\t\t\t$el.addClass(classNames);\n\t\t}\n\n\t\tif (title) {\n\t\t\t$el.attr('title', title);\n\t\t}\n\n\t\t// Add text content.\n\t\tif (text) {\n\t\t\t$el.text(text);\n\t\t}\n\n\t\t// Append it to the given node.\n\t\tif (place) {\n\t\t\t$el.appendTo(place);\n\t\t}\n\n\t\treturn $el[0];\n\t}\n\n\t/*\n\t\t[DEPRECATED] Creates a new text node and appends it to the passed DOM element.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction insertText(place, text) {\n\t\tjQuery(place).append(document.createTextNode(text));\n\t}\n\n\t/*\n\t\t[DEPRECATED] Removes all children from the passed DOM node.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction removeChildren(node) {\n\t\tjQuery(node).empty();\n\t}\n\n\t/*\n\t\t[DEPRECATED] Removes the passed DOM node.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction removeElement(node) {\n\t\tjQuery(node).remove();\n\t}\n\n\t/*\n\t\t[DEPRECATED] Fades a DOM element in or out.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction fade(el, options) {\n\t\t/* eslint-disable no-param-reassign */\n\t\tconst direction = options.fade === 'in' ? 1 : -1;\n\t\tlet current;\n\t\tlet proxy      = el.cloneNode(true);\n\t\tlet intervalId; // eslint-disable-line prefer-const\n\n\t\tfunction tick() {\n\t\t\tcurrent += 0.05 * direction;\n\t\t\tsetOpacity(proxy, Math.easeInOut(current));\n\n\t\t\tif (direction === 1 && current >= 1 || direction === -1 && current <= 0) {\n\t\t\t\tel.style.visibility = options.fade === 'in' ? 'visible' : 'hidden';\n\t\t\t\tproxy.parentNode.replaceChild(el, proxy);\n\t\t\t\tproxy = null;\n\t\t\t\twindow.clearInterval(intervalId);\n\n\t\t\t\tif (options.onComplete) {\n\t\t\t\t\toptions.onComplete();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction setOpacity(el, opacity) {\n\t\t\t// Old IE.\n\t\t\tel.style.zoom = 1;\n\t\t\tel.style.filter = `alpha(opacity=${Math.floor(opacity * 100)})`;\n\n\t\t\t// CSS.\n\t\t\tel.style.opacity = opacity;\n\t\t}\n\n\t\tel.parentNode.replaceChild(proxy, el);\n\n\t\tif (options.fade === 'in') {\n\t\t\tcurrent = 0;\n\t\t\tproxy.style.visibility = 'visible';\n\t\t}\n\t\telse {\n\t\t\tcurrent = 1;\n\t\t}\n\n\t\tsetOpacity(proxy, current);\n\t\tintervalId = window.setInterval(tick, 25);\n\t\t/* eslint-enable no-param-reassign */\n\t}\n\n\t/*\n\t\t[DEPRECATED] Scrolls the browser window to ensure that a DOM element is in view.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction scrollWindowTo(el, incrementBy) {\n\t\t/* eslint-disable no-param-reassign */\n\t\tlet increment = incrementBy != null ? Number(incrementBy) : 0.1; // lazy equality for null\n\n\t\tif (Number.isNaN(increment) || !Number.isFinite(increment) || increment < 0) {\n\t\t\tincrement = 0.1;\n\t\t}\n\t\telse if (increment > 1) {\n\t\t\tincrement = 1;\n\t\t}\n\n\t\tconst start     = window.scrollY ? window.scrollY : document.body.scrollTop;\n\t\tconst end       = ensureVisible(el);\n\t\tconst distance  = Math.abs(start - end);\n\t\tconst direction = start > end ? -1 : 1;\n\t\tlet progress   = 0;\n\t\tlet intervalId; // eslint-disable-line prefer-const\n\n\t\tfunction tick() {\n\t\t\tprogress += increment;\n\t\t\twindow.scroll(0, start + direction * (distance * Math.easeInOut(progress)));\n\n\t\t\tif (progress >= 1) {\n\t\t\t\twindow.clearInterval(intervalId);\n\t\t\t}\n\t\t}\n\n\t\tfunction findPosY(el) { // eslint-disable-line no-shadow\n\t\t\tlet curtop = 0;\n\n\t\t\twhile (el.offsetParent) {\n\t\t\t\tcurtop += el.offsetTop;\n\t\t\t\tel = el.offsetParent;\n\t\t\t}\n\n\t\t\treturn curtop;\n\t\t}\n\n\t\tfunction ensureVisible(el) { // eslint-disable-line no-shadow\n\t\t\tconst posTop    = findPosY(el);\n\t\t\tconst posBottom = posTop + el.offsetHeight;\n\t\t\tconst winTop    = window.scrollY ? window.scrollY : document.body.scrollTop;\n\t\t\tconst winHeight = window.innerHeight ? window.innerHeight : document.body.clientHeight;\n\t\t\tconst winBottom = winTop + winHeight;\n\n\t\t\treturn posTop >= winTop && posBottom > winBottom && el.offsetHeight < winHeight\n\t\t\t\t? posTop - (winHeight - el.offsetHeight) + 20\n\t\t\t\t: posTop;\n\t\t}\n\n\t\tintervalId = window.setInterval(tick, 25);\n\t\t/* eslint-enable no-param-reassign */\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUser Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a random value from its given arguments.\n\t*/\n\tfunction either(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn Array.prototype.concat.apply([], arguments).random();\n\t}\n\n\t/*\n\t\tRemoves the given key, and its value, from the story metadata store.\n\t*/\n\tfunction forget(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`forget key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\tState.metadata.delete(key);\n\t}\n\n\t/*\n\t\tReturns whether a passage with the given title exists within the story\n\t\thistory.  If multiple passage titles are given, returns the logical-AND\n\t\taggregate of the set.\n\t*/\n\tfunction hasVisited(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('hasVisited called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst played  = State.passages;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend; ++i) {\n\t\t\tif (!played.includes(needles[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/*\n\t\tReturns the number of turns that have passed since the last instance of the given passage\n\t\toccurred within the story history or `-1` if it does not exist.  If multiple passages are\n\t\tgiven, returns the lowest count (which can be `-1`).\n\t*/\n\tfunction lastVisited(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('lastVisited called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn -1;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst played  = State.passages;\n\t\tconst uBound  = played.length - 1;\n\t\tlet turns = State.turns;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend && turns > -1; ++i) {\n\t\t\tconst lastIndex = played.lastIndexOf(needles[i]);\n\t\t\tturns = Math.min(turns, lastIndex === -1 ? -1 : uBound - lastIndex);\n\t\t}\n\n\t\treturn turns;\n\t}\n\n\t/*\n\t\tSets the given key/value pair within the story metadata store.\n\t*/\n\tfunction memorize(key, value) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`memorize key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\tState.metadata.set(key, value);\n\t}\n\n\t/*\n\t\tReturns the title of the current passage.\n\t*/\n\tfunction passage() {\n\t\treturn State.passage;\n\t}\n\n\t/*\n\t\tReturns the title of a previous passage, either the most recent one whose title does not\n\t\tmatch that of the active passage or the one at the optional offset, or an empty string,\n\t\tif there is no such passage.\n\t*/\n\tfunction previous(/* legacy: offset */) {\n\t\tconst passages = State.passages;\n\n\t\t/* legacy: behavior with an offset */\n\t\tif (arguments.length > 0) {\n\t\t\tconst offset = Number(arguments[0]);\n\n\t\t\tif (!Number.isSafeInteger(offset) || offset < 1) {\n\t\t\t\tthrow new RangeError('previous offset parameter must be a positive integer greater than zero');\n\t\t\t}\n\n\t\t\treturn passages.length > offset ? passages[passages.length - 1 - offset] : '';\n\t\t}\n\t\t/* /legacy */\n\n\t\tfor (let i = passages.length - 2; i >= 0; --i) {\n\t\t\tif (passages[i] !== State.passage) {\n\t\t\t\treturn passages[i];\n\t\t\t}\n\t\t}\n\n\t\treturn '';\n\t}\n\n\t/*\n\t\tReturns a pseudo-random whole number (integer) within the range of the given bounds.\n\t*/\n\tfunction random(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('random called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = Math.trunc(arguments[0]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Math.trunc(arguments[0]);\n\t\t\tmax = Math.trunc(arguments[1]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (!Number.isInteger(min)) {\n\t\t\tthrow new Error('random min parameter must be an integer');\n\t\t}\n\t\tif (!Number.isInteger(max)) {\n\t\t\tthrow new Error('random max parameter must be an integer');\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn Math.floor(State.random() * (max - min + 1)) + min;\n\t}\n\n\t/*\n\t\tReturns a pseudo-random real number (floating-point) within the range of the given bounds.\n\n\t\tNOTE: Unlike with its sibling function `random()`, the `max` parameter\n\t\tis exclusive, not inclusive—i.e. the range goes to, but does not include,\n\t\tthe given value.\n\t*/\n\tfunction randomFloat(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('randomFloat called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0.0;\n\t\t\tmax = Number(arguments[0]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Number(arguments[0]);\n\t\t\tmax = Number(arguments[1]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (Number.isNaN(min) || !Number.isFinite(min)) {\n\t\t\tthrow new Error('randomFloat min parameter must be a number');\n\t\t}\n\t\tif (Number.isNaN(max) || !Number.isFinite(max)) {\n\t\t\tthrow new Error('randomFloat max parameter must be a number');\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn State.random() * (max - min) + min;\n\t}\n\n\t/*\n\t\tReturns the value of the given key from the story metadata store\n\t\tor the given default value if the key does not exist.\n\t*/\n\tfunction recall(key, defaultValue) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`recall key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\treturn State.metadata.has(key) ? State.metadata.get(key) : defaultValue;\n\t}\n\n\t/*\n\t\tReturns a new array consisting of all of the tags of the given passages.\n\t*/\n\tfunction tags(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\treturn Story.get(State.passage).tags.slice(0);\n\t\t}\n\n\t\tconst passages = Array.prototype.concat.apply([], arguments);\n\t\tlet tags = [];\n\n\t\tfor (let i = 0, iend = passages.length; i < iend; ++i) {\n\t\t\ttags = tags.concat(Story.get(passages[i]).tags);\n\t\t}\n\n\t\treturn tags;\n\t}\n\n\t/*\n\t\tReturns a reference to the current temporary _variables store.\n\t*/\n\tfunction temporary() {\n\t\treturn State.temporary;\n\t}\n\n\t/*\n\t\tReturns the number of milliseconds which have passed since the current passage was rendered.\n\t*/\n\tfunction time() {\n\t\treturn Engine.lastPlay === null ? 0 : Util.now() - Engine.lastPlay;\n\t}\n\n\t/*\n\t\tReturns the number of passages that the player has visited.\n\n\t\tNOTE: Passages which were visited but have been undone—e.g. via the backward\n\t\tbutton or the `<<back>>` macro—are no longer part of the in-play story\n\t\thistory and thus are not tallied.  Passages which were visited but have\n\t\texpired from the story history, on the other hand, are tallied.\n\t*/\n\tfunction turns() {\n\t\treturn State.turns;\n\t}\n\n\t/*\n\t\tReturns a reference to the current story $variables store.\n\t*/\n\tfunction variables() {\n\t\treturn State.variables;\n\t}\n\n\t/*\n\t\tReturns the number of times that the passage with the given title exists within the story\n\t\thistory.  If multiple passage titles are given, returns the lowest count.\n\t*/\n\tfunction visited(/* variadic */) {\n\t\tif (State.isEmpty()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments.length === 0 ? [State.passage] : arguments);\n\t\tconst played  = State.passages;\n\t\tlet count = State.turns;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend && count > 0; ++i) {\n\t\t\tcount = Math.min(count, played.count(needles[i]));\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/*\n\t\tReturns the number of passages within the story history which are tagged with all of the given tags.\n\t*/\n\tfunction visitedTags(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('visitedTags called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst nLength = needles.length;\n\t\tconst played  = State.passages;\n\t\tconst seen    = new Map();\n\t\tlet count = 0;\n\n\t\tfor (let i = 0, iend = played.length; i < iend; ++i) {\n\t\t\tconst title = played[i];\n\n\t\t\tif (seen.has(title)) {\n\t\t\t\tif (seen.get(title)) {\n\t\t\t\t\t++count;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst tags = Story.get(title).tags;\n\n\t\t\t\tif (tags.length > 0) {\n\t\t\t\t\tlet found = 0;\n\n\t\t\t\t\tfor (let j = 0; j < nLength; ++j) {\n\t\t\t\t\t\tif (tags.includes(needles[j])) {\n\t\t\t\t\t\t\t++found;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (found === nLength) {\n\t\t\t\t\t\t++count;\n\t\t\t\t\t\tseen.set(title, true);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tseen.set(title, false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/* eslint-enable no-unused-vars */\n\n\n\t/*******************************************************************************************************************\n\t\tImport Functions.\n\t*******************************************************************************************************************/\n\tvar { // eslint-disable-line no-var\n\t\t/* eslint-disable no-unused-vars */\n\t\timportScripts,\n\t\timportStyles\n\t\t/* eslint-enable no-unused-vars */\n\t} = (() => {\n\t\t// Slugify the given URL.\n\t\tfunction slugifyUrl(url) {\n\t\t\treturn Util.parseUrl(url).path\n\t\t\t\t.replace(/^[^\\w]+|[^\\w]+$/g, '')\n\t\t\t\t.replace(/[^\\w]+/g, '-')\n\t\t\t\t.toLocaleLowerCase();\n\t\t}\n\n\t\t// Add a <script> element which will load the script from the given URL.\n\t\tfunction addScript(url) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t/*\n\t\t\t\t\tWARNING: The ordering of the code within this function is important,\n\t\t\t\t\tas some browsers don't play well with different arrangements, so\n\t\t\t\t\tbe careful when mucking around with it.\n\n\t\t\t\t\tThe best supported ordering seems be: events → DOM append → attributes.\n\t\t\t\t*/\n\t\t\t\tjQuery(document.createElement('script'))\n\t\t\t\t\t.one('load abort error', ev => {\n\t\t\t\t\t\tjQuery(ev.target).off();\n\n\t\t\t\t\t\tif (ev.type === 'load') {\n\t\t\t\t\t\t\tresolve(ev.target);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treject(new Error(`importScripts failed to load the script \"${url}\".`));\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo(document.head)\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid   : `script-imported-${slugifyUrl(url)}`,\n\t\t\t\t\t\ttype : 'text/javascript',\n\t\t\t\t\t\tsrc  : url\n\t\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\t// Add a <link> element which will load the stylesheet from the given URL.\n\t\tfunction addStyle(url) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t/*\n\t\t\t\t\tWARNING: The ordering of the code within this function is important,\n\t\t\t\t\tas some browsers don't play well with different arrangements, so\n\t\t\t\t\tbe careful when mucking around with it.\n\n\t\t\t\t\tThe best supported ordering seems be: events → DOM append → attributes.\n\t\t\t\t*/\n\t\t\t\tjQuery(document.createElement('link'))\n\t\t\t\t\t.one('load abort error', ev => {\n\t\t\t\t\t\tjQuery(ev.target).off();\n\n\t\t\t\t\t\tif (ev.type === 'load') {\n\t\t\t\t\t\t\tresolve(ev.target);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treject(new Error(`importStyles failed to load the stylesheet \"${url}\".`));\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo(document.head)\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid   : `style-imported-${slugifyUrl(url)}`,\n\t\t\t\t\t\trel  : 'stylesheet',\n\t\t\t\t\t\thref : url\n\t\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\t// Turn a list of callbacks into a sequential chain of `Promise` objects.\n\t\tfunction sequence(callbacks) {\n\t\t\treturn callbacks.reduce((seq, fn) => seq = seq.then(fn), Promise.resolve()); // eslint-disable-line no-param-reassign\n\t\t}\n\n\t\t/*\n\t\t\tImport scripts from a URL.\n\t\t*/\n\t\tfunction importScripts(...urls) {\n\t\t\treturn Promise.all(urls.map(oneOrSeries => {\n\t\t\t\t// Array of URLs to be imported in sequence.\n\t\t\t\tif (Array.isArray(oneOrSeries)) {\n\t\t\t\t\treturn sequence(oneOrSeries.map(url => () => addScript(url)));\n\t\t\t\t}\n\n\t\t\t\t// Single URL to be imported.\n\t\t\t\treturn addScript(oneOrSeries);\n\t\t\t}));\n\t\t}\n\n\t\t/*\n\t\t\tImport stylesheets from a URL.\n\t\t*/\n\t\tfunction importStyles(...urls) {\n\t\t\treturn Promise.all(urls.map(oneOrSeries => {\n\t\t\t\t// Array of URLs to be imported in sequence.\n\t\t\t\tif (Array.isArray(oneOrSeries)) {\n\t\t\t\t\treturn sequence(oneOrSeries.map(url => () => addStyle(url)));\n\t\t\t\t}\n\n\t\t\t\t// Single URL to be imported.\n\t\t\t\treturn addStyle(oneOrSeries);\n\t\t\t}));\n\t\t}\n\n\t\t// Exports.\n\t\treturn {\n\t\t\timportScripts,\n\t\t\timportStyles\n\t\t};\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tParsing Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the given string after converting all TwineScript syntactical sugars to\n\t\ttheir native JavaScript counterparts.\n\t*/\n\tconst parse = (() => {\n\t\tconst parseMap = Object.freeze({\n\t\t\t/* eslint-disable quote-props */\n\t\t\t// Story $variable sigil-prefix.\n\t\t\t'$'     : 'State.variables.',\n\t\t\t// Temporary _variable sigil-prefix.\n\t\t\t'_'     : 'State.temporary.',\n\t\t\t// Assignment operators.\n\t\t\t'to'    : '=',\n\t\t\t// Equality operators.\n\t\t\t'eq'    : '==',\n\t\t\t'neq'   : '!=',\n\t\t\t'is'    : '===',\n\t\t\t'isnot' : '!==',\n\t\t\t// Relational operators.\n\t\t\t'gt'    : '>',\n\t\t\t'gte'   : '>=',\n\t\t\t'lt'    : '<',\n\t\t\t'lte'   : '<=',\n\t\t\t// Logical operators.\n\t\t\t'and'   : '&&',\n\t\t\t'or'    : '||',\n\t\t\t// Unary operators.\n\t\t\t'not'   : '!',\n\t\t\t'def'   : '\"undefined\" !== typeof',\n\t\t\t'ndef'  : '\"undefined\" === typeof'\n\t\t\t/* eslint-enable quote-props */\n\t\t});\n\t\tconst parseRe = new RegExp([\n\t\t\t'(\"\"|\\'\\')',                                          // 1=Empty quotes\n\t\t\t'(\"(?:\\\\\\\\.|[^\"\\\\\\\\])+\")',                            // 2=Double quoted, non-empty\n\t\t\t\"('(?:\\\\\\\\.|[^'\\\\\\\\])+')\",                            // 3=Single quoted, non-empty\n\t\t\t'([=+\\\\-*\\\\/%<>&\\\\|\\\\^~!?:,;\\\\(\\\\)\\\\[\\\\]{}]+)',       // 4=Operator delimiters\n\t\t\t'([^\"\\'=+\\\\-*\\\\/%<>&\\\\|\\\\^~!?:,;\\\\(\\\\)\\\\[\\\\]{}\\\\s]+)' // 5=Barewords\n\t\t].join('|'), 'g');\n\t\tconst varTest = new RegExp(`^${Patterns.variable}`);\n\n\t\tfunction parse(rawCodeString) {\n\t\t\tif (parseRe.lastIndex !== 0) {\n\t\t\t\tthrow new RangeError('Scripting.parse last index is non-zero at start');\n\t\t\t}\n\n\t\t\tlet code  = rawCodeString;\n\t\t\tlet match;\n\n\t\t\twhile ((match = parseRe.exec(code)) !== null) {\n\t\t\t\t// no-op: Empty quotes | Double quoted | Single quoted | Operator delimiters\n\n\t\t\t\t/*\n\t\t\t\t\tBarewords.\n\t\t\t\t*/\n\t\t\t\tif (match[5]) {\n\t\t\t\t\tlet token = match[5];\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is simply a dollar-sign or underscore, then it's either\n\t\t\t\t\t\tjust the raw character or, probably, a function alias, so skip it.\n\t\t\t\t\t*/\n\t\t\t\t\tif (token === '$' || token === '_') {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is a story $variable or temporary _variable, reset it\n\t\t\t\t\t\tto just its sigil—for later mapping.\n\t\t\t\t\t*/\n\t\t\t\t\telse if (varTest.test(token)) {\n\t\t\t\t\t\ttoken = token[0];\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is `is`, check to see if it's followed by `not`, if so,\n\t\t\t\t\t\tconvert them into the `isnot` operator.\n\n\t\t\t\t\t\tNOTE: This is a safety feature, since `$a is not $b` probably sounds\n\t\t\t\t\t\treasonable to most users.\n\t\t\t\t\t*/\n\t\t\t\t\telse if (token === 'is') {\n\t\t\t\t\t\tconst start = parseRe.lastIndex;\n\t\t\t\t\t\tconst part  = code.slice(start);\n\n\t\t\t\t\t\tif (/^\\s+not\\b/.test(part)) {\n\t\t\t\t\t\t\tcode = code.splice(start, part.search(/\\S/));\n\t\t\t\t\t\t\ttoken = 'isnot';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the finalized token has a mapping, replace it within the code string\n\t\t\t\t\t\twith its counterpart.\n\n\t\t\t\t\t\tNOTE: We must use `parseMap.hasOwnProperty(token)` here, rather than\n\t\t\t\t\t\tsimply using something like `parseMap[token]`, otherwise tokens which\n\t\t\t\t\t\tmatch properties from the prototype chain will cause shenanigans.\n\t\t\t\t\t*/\n\t\t\t\t\tif (parseMap.hasOwnProperty(token)) {\n\t\t\t\t\t\tcode = code.splice(\n\t\t\t\t\t\t\tmatch.index,    // starting index\n\t\t\t\t\t\t\ttoken.length,   // replace how many\n\t\t\t\t\t\t\tparseMap[token] // replacement string\n\t\t\t\t\t\t);\n\t\t\t\t\t\tparseRe.lastIndex += parseMap[token].length - token.length;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn code;\n\t\t}\n\n\t\treturn parse;\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tEval Functions.\n\t*******************************************************************************************************************/\n\t/* eslint-disable no-eval, no-extra-parens, no-unused-vars */\n\t/*\n\t\tEvaluates the given JavaScript code and returns the result, throwing if there were errors.\n\t*/\n\tfunction evalJavaScript(code, output) {\n\t\treturn (function (code, output) {\n\t\t\treturn eval(code);\n\t\t}).call(output ? { output } : null, String(code), output);\n\t}\n\n\t/*\n\t\tEvaluates the given TwineScript code and returns the result, throwing if there were errors.\n\t*/\n\tfunction evalTwineScript(code, output) {\n\t\treturn (function (code, output) {\n\t\t\treturn eval(code);\n\t\t}).call(output ? { output } : null, parse(String(code)), output);\n\t}\n\t/* eslint-enable no-eval, no-extra-parens, no-unused-vars */\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tparse           : { value : parse },\n\t\tevalJavaScript  : { value : evalJavaScript },\n\t\tevalTwineScript : { value : evalTwineScript }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/lexer.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar { // eslint-disable-line no-var\n\t/* eslint-disable no-unused-vars */\n\tEOF,\n\tLexer\n\t/* eslint-enable no-unused-vars */\n} = (() => {\n\t'use strict';\n\n\t// End of file (string, actually).\n\tconst EOF = -1;\n\n\n\t/*******************************************************************************************************************\n\t\tLexer Class.\n\t*******************************************************************************************************************/\n\tclass Lexer {\n\t\tconstructor(source, initialState) {\n\t\t\tif (arguments.length < 2) {\n\t\t\t\tthrow new Error('Lexer constructor called with too few parameters (source:string , initialState:function)');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tthis.source  → the string to be scanned\n\t\t\t\tthis.initial → initial state\n\t\t\t\tthis.state   → current state\n\t\t\t\tthis.start   → start position of an item\n\t\t\t\tthis.pos     → current position in the source string\n\t\t\t\tthis.depth   → current brace/bracket/parenthesis nesting depth\n\t\t\t\tthis.items   → scanned item queue\n\t\t\t\tthis.data    → lexing data\n\t\t\t*/\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : source\n\t\t\t\t},\n\n\t\t\t\tinitial : {\n\t\t\t\t\tvalue : initialState\n\t\t\t\t},\n\n\t\t\t\tstate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : initialState\n\t\t\t\t},\n\n\t\t\t\tstart : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\tpos : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\tdepth : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\titems : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : []\n\t\t\t\t},\n\n\t\t\t\tdata : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : {}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treset() {\n\t\t\tthis.state  = this.initial;\n\t\t\tthis.start  = 0;\n\t\t\tthis.pos    = 0;\n\t\t\tthis.depth  = 0;\n\t\t\tthis.items  = [];\n\t\t\tthis.data   = {};\n\t\t}\n\n\t\trun() {\n\t\t\t// scan the source string until no states remain\n\t\t\twhile (this.state !== null) {\n\t\t\t\tthis.state = this.state(this);\n\t\t\t}\n\n\t\t\t// return the array of items\n\t\t\treturn this.items;\n\t\t}\n\n\t\tnextItem() {\n\t\t\t// scan the source string until we have an item or no states remain\n\t\t\twhile (this.items.length === 0 && this.state !== null) {\n\t\t\t\tthis.state = this.state(this);\n\t\t\t}\n\n\t\t\t// return the current item\n\t\t\treturn this.items.shift();\n\t\t}\n\n\t\tnext() {\n\t\t\tif (this.pos >= this.source.length) {\n\t\t\t\treturn EOF;\n\t\t\t}\n\n\t\t\treturn this.source[this.pos++];\n\t\t}\n\n\t\tpeek() {\n\t\t\tif (this.pos >= this.source.length) {\n\t\t\t\treturn EOF;\n\t\t\t}\n\n\t\t\treturn this.source[this.pos];\n\t\t}\n\n\t\tbackup(num) {\n\t\t\t// if (num) {\n\t\t\t// \tthis.pos -= num;\n\t\t\t// }\n\t\t\t// else {\n\t\t\t// \t--this.pos;\n\t\t\t// }\n\t\t\tthis.pos -= num || 1;\n\t\t}\n\n\t\tforward(num) {\n\t\t\t// if (num) {\n\t\t\t// \tthis.pos += num;\n\t\t\t// }\n\t\t\t// else {\n\t\t\t// \t++this.pos;\n\t\t\t// }\n\t\t\tthis.pos += num || 1;\n\t\t}\n\n\t\tignore() {\n\t\t\tthis.start = this.pos;\n\t\t}\n\n\t\taccept(valid) {\n\t\t\tconst ch = this.next();\n\n\t\t\tif (ch === EOF) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (valid.includes(ch)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t\treturn false;\n\t\t}\n\n\t\tacceptRe(validRe) {\n\t\t\tconst ch = this.next();\n\n\t\t\tif (ch === EOF) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (validRe.test(ch)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t\treturn false;\n\t\t}\n\n\t\tacceptRun(valid) {\n\t\t\tfor (;;) {\n\t\t\t\tconst ch = this.next();\n\n\t\t\t\tif (ch === EOF) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!valid.includes(ch)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t}\n\n\t\tacceptRunRe(validRe) {\n\t\t\tfor (;;) {\n\t\t\t\tconst ch = this.next();\n\n\t\t\t\tif (ch === EOF) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!validRe.test(ch)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t}\n\n\t\temit(type) {\n\t\t\tthis.items.push({\n\t\t\t\ttype,\n\t\t\t\ttext  : this.source.slice(this.start, this.pos),\n\t\t\t\tstart : this.start,\n\t\t\t\tpos   : this.pos\n\t\t\t});\n\t\t\tthis.start = this.pos;\n\t\t}\n\n\t\terror(type, message) {\n\t\t\tif (arguments.length < 2) {\n\t\t\t\tthrow new Error('Lexer.prototype.error called with too few parameters (type:number , message:string)');\n\t\t\t}\n\n\t\t\tthis.items.push({\n\t\t\t\ttype,\n\t\t\t\tmessage,\n\t\t\t\ttext  : this.source.slice(this.start, this.pos),\n\t\t\t\tstart : this.start,\n\t\t\t\tpos   : this.pos\n\t\t\t});\n\t\t\treturn null;\n\t\t}\n\n\t\tstatic enumFromNames(names) {\n\t\t\tconst obj = names.reduce((obj, name, i) => {\n\t\t\t\tobj[name] = i; // eslint-disable-line no-param-reassign\n\t\t\t\treturn obj;\n\t\t\t}, {});\n\t\t\treturn Object.freeze(Object.assign(Object.create(null), obj));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn {\n\t\tEOF,\n\t\tLexer\n\t};\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/wikifier.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, EOF, Engine, Lexer, Patterns, Scripting, State, Story, TempState, Util, convertBreaks,\n\t       errorPrologRegExp\n*/\n\n/*\n\tTODO: The Wikifier, and associated code, could stand to receive a serious refactoring.\n*/\n/* eslint-disable max-len */\nvar Wikifier = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Wikifier call depth.\n\tlet _callDepth = 0;\n\n\n\t/*******************************************************************************************************************\n\t\tWikifier Class.\n\t*******************************************************************************************************************/\n\tclass Wikifier {\n\t\tconstructor(destination, source, options) {\n\t\t\tif (Wikifier.Parser.Profile.isEmpty()) {\n\t\t\t\tWikifier.Parser.Profile.compile();\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// General Wikifier properties.\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : String(source)\n\t\t\t\t},\n\n\t\t\t\toptions : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : Object.assign({\n\t\t\t\t\t\tprofile : 'all'\n\t\t\t\t\t}, options)\n\t\t\t\t},\n\n\t\t\t\tnextMatch : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\toutput : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t// Macro parser ('macro') related properties.\n\t\t\t\t_rawArgs : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : ''\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// No destination specified.  Create a fragment to act as the output buffer.\n\t\t\tif (destination == null) { // lazy equality for null\n\t\t\t\tthis.output = document.createDocumentFragment();\n\t\t\t}\n\n\t\t\t// jQuery-wrapped destination.  Grab the first element.\n\t\t\telse if (destination.jquery) { // cannot use `hasOwnProperty()` here as `jquery` is from jQuery's prototype\n\t\t\t\tthis.output = destination[0];\n\t\t\t}\n\n\t\t\t// Normal destination.\n\t\t\telse {\n\t\t\t\tthis.output = destination;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tWikify the source into the output buffer element, possibly converting line\n\t\t\t\tbreaks into paragraphs.\n\n\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\tto ensure that the call depth is properly restored in the event that an\n\t\t\t\tuncaught exception is thrown during the call to `subWikify()`.\n\t\t\t*/\n\t\t\ttry {\n\t\t\t\t++_callDepth;\n\n\t\t\t\tthis.subWikify(this.output);\n\n\t\t\t\t// Limit line break conversion to non-recursive calls.\n\t\t\t\tif (_callDepth === 1 && Config.cleanupWikifierOutput) {\n\t\t\t\t\tconvertBreaks(this.output);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\t--_callDepth;\n\t\t\t}\n\t\t}\n\n\t\tsubWikify(output, terminator, options) {\n\t\t\t// Cache and temporarily replace the current output buffer.\n\t\t\tconst oldOutput = this.output;\n\t\t\tthis.output = output;\n\n\t\t\tlet newOptions;\n\t\t\tlet oldOptions;\n\n\t\t\t// Parser option overrides.\n\t\t\tif (Wikifier.Option.length > 0) {\n\t\t\t\tnewOptions = Object.assign(newOptions || {}, Wikifier.Option.options);\n\t\t\t}\n\t\t\t// Local parameter option overrides.\n\t\t\tif (options !== null && typeof options === 'object') {\n\t\t\t\tnewOptions = Object.assign(newOptions || {}, options);\n\t\t\t}\n\t\t\t// If new options exist, cache and temporarily replace the current options.\n\t\t\tif (newOptions) {\n\t\t\t\toldOptions = this.options;\n\t\t\t\tthis.options = Object.assign({}, this.options, newOptions);\n\t\t\t}\n\n\t\t\tconst parsersProfile   = Wikifier.Parser.Profile.get(this.options.profile);\n\t\t\tconst terminatorRegExp = terminator\n\t\t\t\t? new RegExp(`(?:${terminator})`, this.options.ignoreTerminatorCase ? 'gim' : 'gm')\n\t\t\t\t: null;\n\t\t\tlet terminatorMatch;\n\t\t\tlet parserMatch;\n\n\t\t\tdo {\n\t\t\t\t// Prepare the RegExp match positions.\n\t\t\t\tparsersProfile.parserRegExp.lastIndex = this.nextMatch;\n\n\t\t\t\tif (terminatorRegExp) {\n\t\t\t\t\tterminatorRegExp.lastIndex = this.nextMatch;\n\t\t\t\t}\n\n\t\t\t\t// Get the first matches.\n\t\t\t\tparserMatch     = parsersProfile.parserRegExp.exec(this.source);\n\t\t\t\tterminatorMatch = terminatorRegExp ? terminatorRegExp.exec(this.source) : null;\n\n\t\t\t\t// Try for a terminator match, unless there's a closer parser match.\n\t\t\t\tif (terminatorMatch && (!parserMatch || terminatorMatch.index <= parserMatch.index)) {\n\t\t\t\t\t// Output any text before the match.\n\t\t\t\t\tif (terminatorMatch.index > this.nextMatch) {\n\t\t\t\t\t\tthis.outputText(this.output, this.nextMatch, terminatorMatch.index);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set the match parameters.\n\t\t\t\t\tthis.matchStart  = terminatorMatch.index;\n\t\t\t\t\tthis.matchLength = terminatorMatch[0].length;\n\t\t\t\t\tthis.matchText   = terminatorMatch[0];\n\t\t\t\t\tthis.nextMatch   = terminatorRegExp.lastIndex;\n\n\t\t\t\t\t// Restore the original output buffer and options.\n\t\t\t\t\tthis.output = oldOutput;\n\n\t\t\t\t\tif (oldOptions) {\n\t\t\t\t\t\tthis.options = oldOptions;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Exit.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Try for a parser match.\n\t\t\t\telse if (parserMatch) {\n\t\t\t\t\t// Output any text before the match.\n\t\t\t\t\tif (parserMatch.index > this.nextMatch) {\n\t\t\t\t\t\tthis.outputText(this.output, this.nextMatch, parserMatch.index);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set the match parameters.\n\t\t\t\t\tthis.matchStart  = parserMatch.index;\n\t\t\t\t\tthis.matchLength = parserMatch[0].length;\n\t\t\t\t\tthis.matchText   = parserMatch[0];\n\t\t\t\t\tthis.nextMatch   = parsersProfile.parserRegExp.lastIndex;\n\n\t\t\t\t\t// Figure out which parser matched.\n\t\t\t\t\tlet matchingParser;\n\n\t\t\t\t\tfor (let i = 1, iend = parserMatch.length; i < iend; ++i) {\n\t\t\t\t\t\tif (parserMatch[i]) {\n\t\t\t\t\t\t\tmatchingParser = i - 1;\n\t\t\t\t\t\t\tbreak; // stop once we've found the matching parser\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Call the parser.\n\t\t\t\t\tparsersProfile.parsers[matchingParser].handler(this);\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} while (terminatorMatch || parserMatch);\n\n\t\t\t// Output any text after the last match.\n\t\t\tif (TempState.break == null) { // lazy equality for null\n\t\t\t\tif (this.nextMatch < this.source.length) {\n\t\t\t\t\tthis.outputText(this.output, this.nextMatch, this.source.length);\n\t\t\t\t\tthis.nextMatch = this.source.length;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// In case of <<break>>/<<continue>>, remove the last <br>.\n\t\t\telse if (\n\t\t\t\t   this.output.lastChild\n\t\t\t\t&& this.output.lastChild.nodeType === Node.ELEMENT_NODE\n\t\t\t\t&& this.output.lastChild.nodeName.toUpperCase() === 'BR'\n\t\t\t) {\n\t\t\t\tjQuery(this.output.lastChild).remove();\n\t\t\t}\n\n\t\t\t// Restore the original output buffer and options.\n\t\t\tthis.output = oldOutput;\n\n\t\t\tif (oldOptions) {\n\t\t\t\tthis.options = oldOptions;\n\t\t\t}\n\t\t}\n\n\t\toutputText(destination, startPos, endPos) {\n\t\t\tdestination.appendChild(document.createTextNode(this.source.substring(startPos, endPos)));\n\t\t}\n\n\t\t/*\n\t\t\t[DEPRECATED] Meant to be called by legacy macros, this returns the raw, unprocessed\n\t\t\ttext given to the currently executing macro.\n\t\t*/\n\t\trawArgs() {\n\t\t\treturn this._rawArgs;\n\t\t}\n\n\t\t/*\n\t\t\t[DEPRECATED] Meant to be called by legacy macros, this returns the text given to\n\t\t\tthe currently executing macro after doing TwineScript-to-JavaScript transformations.\n\t\t*/\n\t\tfullArgs() {\n\t\t\treturn Scripting.parse(this._rawArgs);\n\t\t}\n\n\t\t/*\n\t\t\tReturns the output generated by wikifying the given text, throwing if there were errors.\n\t\t*/\n\t\tstatic wikifyEval(text) {\n\t\t\tconst output = document.createDocumentFragment();\n\n\t\t\tnew Wikifier(output, text);\n\n\t\t\tconst errors = output.querySelector('.error');\n\n\t\t\tif (errors !== null) {\n\t\t\t\tthrow new Error(errors.textContent.replace(errorPrologRegExp, ''));\n\t\t\t}\n\n\t\t\treturn output;\n\t\t}\n\n\t\t/*\n\t\t\tCreate and return an internal link.\n\t\t*/\n\t\tstatic createInternalLink(destination, passage, text, callback) {\n\t\t\tconst $link = jQuery(document.createElement('a'));\n\n\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t$link.attr('data-passage', passage);\n\n\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t$link.addClass('link-internal');\n\n\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t$link.addClass('link-visited');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$link.addClass('link-broken');\n\t\t\t\t}\n\n\t\t\t\t$link.ariaClick({ one : true }, () => {\n\t\t\t\t\tif (typeof callback === 'function') {\n\t\t\t\t\t\tcallback();\n\t\t\t\t\t}\n\n\t\t\t\t\tEngine.play(passage);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (text) {\n\t\t\t\t$link.append(document.createTextNode(text));\n\t\t\t}\n\n\t\t\tif (destination) {\n\t\t\t\t$link.appendTo(destination);\n\t\t\t}\n\n\t\t\t// For legacy-compatibility we must return the DOM node.\n\t\t\treturn $link[0];\n\t\t}\n\n\t\t/*\n\t\t\tCreate and return an external link.\n\t\t*/\n\t\tstatic createExternalLink(destination, url, text) {\n\t\t\tconst $link = jQuery(document.createElement('a'))\n\t\t\t\t.attr('target', '_blank')\n\t\t\t\t.addClass('link-external')\n\t\t\t\t.text(text)\n\t\t\t\t.appendTo(destination);\n\n\t\t\tif (url != null) { // lazy equality for null\n\t\t\t\t$link.attr({\n\t\t\t\t\thref     : url,\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// For legacy-compatibility we must return the DOM node.\n\t\t\treturn $link[0];\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the given link source is external (probably).\n\t\t*/\n\t\tstatic isExternalLink(link) {\n\t\t\tif (Story.has(link)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst urlRegExp = new RegExp(`^${Patterns.url}`, 'gim');\n\t\t\treturn urlRegExp.test(link) || /[/.?#]/.test(link);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tOption Static Object.\n\t*******************************************************************************************************************/\n\tObject.defineProperty(Wikifier, 'Option', {\n\t\tvalue : (() => {\n\t\t\t// Options array (stack).\n\t\t\tlet _optionsStack = [];\n\n\n\t\t\t/*\n\t\t\t\tGlobalOption Functions.\n\t\t\t*/\n\t\t\tfunction optionLength() {\n\t\t\t\treturn _optionsStack.length;\n\t\t\t}\n\n\t\t\tfunction optionGetter() {\n\t\t\t\treturn Object.assign({}, ..._optionsStack);\n\t\t\t}\n\n\t\t\tfunction optionClear() {\n\t\t\t\t_optionsStack = [];\n\t\t\t}\n\n\t\t\tfunction optionGet(idx) {\n\t\t\t\treturn _optionsStack[idx];\n\t\t\t}\n\n\t\t\tfunction optionPop() {\n\t\t\t\treturn _optionsStack.pop();\n\t\t\t}\n\n\t\t\tfunction optionPush(options) {\n\t\t\t\tif (typeof options !== 'object' || options === null) {\n\t\t\t\t\tthrow new TypeError(`Wikifier.Option.push options parameter must be an object (received: ${Util.getType(options)})`);\n\t\t\t\t}\n\n\t\t\t\treturn _optionsStack.push(options);\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tExports.\n\t\t\t*/\n\t\t\treturn Object.freeze(Object.defineProperties({}, {\n\t\t\t\tlength  : { get : optionLength },\n\t\t\t\toptions : { get : optionGetter },\n\t\t\t\tclear   : { value : optionClear },\n\t\t\t\tget     : { value : optionGet },\n\t\t\t\tpop     : { value : optionPop },\n\t\t\t\tpush    : { value : optionPush }\n\t\t\t}));\n\t\t})()\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tParser Static Object.\n\t*******************************************************************************************************************/\n\tObject.defineProperty(Wikifier, 'Parser', {\n\t\tvalue : (() => {\n\t\t\t// Parser definition array.  Ordering matters, so this must be an ordered list.\n\t\t\tconst _parsers = [];\n\n\t\t\t// Parser profiles object.\n\t\t\tlet _profiles;\n\n\n\t\t\t/*\n\t\t\t\tParser Functions.\n\t\t\t*/\n\t\t\tfunction parsersGetter() {\n\t\t\t\treturn _parsers;\n\t\t\t}\n\n\t\t\tfunction parsersAdd(parser) {\n\t\t\t\t// Parser object sanity checks.\n\t\t\t\tif (typeof parser !== 'object') {\n\t\t\t\t\tthrow new Error('Wikifier.Parser.add parser parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('name')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"name\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.name !== 'string') {\n\t\t\t\t\tthrow new Error('parser object \"name\" property must be a string');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('match')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"match\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.match !== 'string') {\n\t\t\t\t\tthrow new Error('parser object \"match\" property must be a string');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('handler')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"handler\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.handler !== 'function') {\n\t\t\t\t\tthrow new Error('parser object \"handler\" property must be a function');\n\t\t\t\t}\n\n\t\t\t\tif (parser.hasOwnProperty('profiles') && !Array.isArray(parser.profiles)) {\n\t\t\t\t\tthrow new Error('parser object \"profiles\" property must be an array');\n\t\t\t\t}\n\n\t\t\t\t// Check for an existing parser with the same name.\n\t\t\t\tif (parsersHas(parser.name)) {\n\t\t\t\t\tthrow new Error(`cannot clobber existing parser \"${parser.name}\"`);\n\t\t\t\t}\n\n\t\t\t\t// Add the parser to the end of the array.\n\t\t\t\t_parsers.push(parser);\n\t\t\t}\n\n\t\t\tfunction parsersDelete(name) {\n\t\t\t\tconst parser = _parsers.find(parser => parser.name === name);\n\n\t\t\t\tif (parser) {\n\t\t\t\t\t_parsers.delete(parser);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction parsersIsEmpty() {\n\t\t\t\treturn _parsers.length === 0;\n\t\t\t}\n\n\t\t\tfunction parsersHas(name) {\n\t\t\t\treturn !!_parsers.find(parser => parser.name === name);\n\t\t\t}\n\n\t\t\tfunction parsersGet(name) {\n\t\t\t\treturn _parsers.find(parser => parser.name === name) || null;\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tParser Profile Functions.\n\t\t\t*/\n\t\t\tfunction profilesGetter() {\n\t\t\t\treturn _profiles;\n\t\t\t}\n\n\t\t\tfunction profilesCompile() {\n\t\t\t\tif (DEBUG) { console.log('[Wikifier.Parser/profilesCompile()]'); }\n\n\t\t\t\tconst all  = _parsers;\n\t\t\t\tconst core = all.filter(parser => !Array.isArray(parser.profiles) || parser.profiles.includes('core'));\n\n\t\t\t\t_profiles = Object.freeze({\n\t\t\t\t\tall : {\n\t\t\t\t\t\tparsers      : all,\n\t\t\t\t\t\tparserRegExp : new RegExp(all.map(parser => `(${parser.match})`).join('|'), 'gm')\n\t\t\t\t\t},\n\t\t\t\t\tcore : {\n\t\t\t\t\t\tparsers      : core,\n\t\t\t\t\t\tparserRegExp : new RegExp(core.map(parser => `(${parser.match})`).join('|'), 'gm')\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\treturn _profiles;\n\t\t\t}\n\n\t\t\tfunction profilesIsEmpty() {\n\t\t\t\treturn typeof _profiles !== 'object' || Object.keys(_profiles).length === 0;\n\t\t\t}\n\n\t\t\tfunction profilesGet(profile) {\n\t\t\t\tif (typeof _profiles !== 'object' || !_profiles.hasOwnProperty(profile)) {\n\t\t\t\t\tthrow new Error(`nonexistent parser profile \"${profile}\"`);\n\t\t\t\t}\n\n\t\t\t\treturn _profiles[profile];\n\t\t\t}\n\n\t\t\tfunction profilesHas(profile) {\n\t\t\t\treturn typeof _profiles === 'object' && _profiles.hasOwnProperty(profile);\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tExports.\n\t\t\t*/\n\t\t\treturn Object.freeze(Object.defineProperties({}, {\n\t\t\t\t/*\n\t\t\t\t\tParser Containers.\n\t\t\t\t*/\n\t\t\t\tparsers : { get : parsersGetter },\n\n\t\t\t\t/*\n\t\t\t\t\tParser Functions.\n\t\t\t\t*/\n\t\t\t\tadd     : { value : parsersAdd },\n\t\t\t\tdelete  : { value : parsersDelete },\n\t\t\t\tisEmpty : { value : parsersIsEmpty },\n\t\t\t\thas     : { value : parsersHas },\n\t\t\t\tget     : { value : parsersGet },\n\n\t\t\t\t/*\n\t\t\t\t\tParser Profile.\n\t\t\t\t*/\n\t\t\t\tProfile : {\n\t\t\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tProfiles Containers.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tprofiles : { get : profilesGetter },\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tProfiles Functions.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tcompile : { value : profilesCompile },\n\t\t\t\t\t\tisEmpty : { value : profilesIsEmpty },\n\t\t\t\t\t\thas     : { value : profilesHas },\n\t\t\t\t\t\tget     : { value : profilesGet }\n\t\t\t\t\t}))\n\t\t\t\t}\n\t\t\t}));\n\t\t})()\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAdditional Static Properties.\n\t*******************************************************************************************************************/\n\tObject.defineProperties(Wikifier, {\n\t\thelpers : { value : {} },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tgetValue       : { value : State.getVar },              // SEE: `state.js`.\n\t\tsetValue       : { value : State.setVar },              // SEE: `state.js`.\n\t\tparse          : { value : Scripting.parse },           // SEE: `markup/scripting.js`.\n\t\tevalExpression : { value : Scripting.evalTwineScript }, // SEE: `markup/scripting.js`.\n\t\tevalStatements : { value : Scripting.evalTwineScript }, // SEE: `markup/scripting.js`.\n\t\ttextPrimitives : { value : Patterns }                   // SEE: `lib/patterns.js`.\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tHelper Static Methods.\n\t*******************************************************************************************************************/\n\tObject.defineProperties(Wikifier.helpers, {\n\t\tinlineCss : {\n\t\t\tvalue : (() => {\n\t\t\t\tconst lookaheadRe = new RegExp(Patterns.inlineCss, 'gm');\n\t\t\t\tconst idOrClassRe = new RegExp(`(${Patterns.cssIdOrClassSigil})(${Patterns.anyLetter}+)`, 'g');\n\n\t\t\t\tfunction helperInlineCss(w) {\n\t\t\t\t\tconst css = { classes : [], id : '', styles : {} };\n\t\t\t\t\tlet matched;\n\n\t\t\t\t\tdo {\n\t\t\t\t\t\tlookaheadRe.lastIndex = w.nextMatch;\n\n\t\t\t\t\t\tconst match = lookaheadRe.exec(w.source);\n\n\t\t\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\t\t\tif (matched) {\n\t\t\t\t\t\t\tif (match[1]) {\n\t\t\t\t\t\t\t\tcss.styles[Util.fromCssProperty(match[1])] = match[2].trim();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (match[3]) {\n\t\t\t\t\t\t\t\tcss.styles[Util.fromCssProperty(match[3])] = match[4].trim();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (match[5]) {\n\t\t\t\t\t\t\t\tlet subMatch;\n\n\t\t\t\t\t\t\t\tidOrClassRe.lastIndex = 0; // NOTE: Guard against buggy implementations.\n\n\t\t\t\t\t\t\t\twhile ((subMatch = idOrClassRe.exec(match[5])) !== null) {\n\t\t\t\t\t\t\t\t\tif (subMatch[1] === '.') {\n\t\t\t\t\t\t\t\t\t\tcss.classes.push(subMatch[2]);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tcss.id = subMatch[2];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tw.nextMatch = lookaheadRe.lastIndex; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\t\t\t\t\t} while (matched);\n\n\t\t\t\t\treturn css;\n\t\t\t\t}\n\n\t\t\t\treturn helperInlineCss;\n\t\t\t})()\n\t\t},\n\n\t\tevalText : {\n\t\t\tvalue(text) {\n\t\t\t\tlet result;\n\n\t\t\t\ttry {\n\t\t\t\t\tresult = Scripting.evalTwineScript(text);\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAttempt to prevent the leakage of auto-globals by enforcing that\n\t\t\t\t\t\tthe resultant value be either a string or a number.\n\n\t\t\t\t\t\tNOTE: This is not a foolproof solution to the problem of auto-global\n\t\t\t\t\t\tleakage.  Various auto-globals, which return strings or numbers, can\n\t\t\t\t\t\tstill leak through—e.g. `window.status` → string.\n\t\t\t\t\t*/\n\t\t\t\t\tswitch (typeof result) {\n\t\t\t\t\tcase 'string':\n\t\t\t\t\t\tif (result.trim() === '') {\n\t\t\t\t\t\t\tresult = text;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'number':\n\t\t\t\t\t\tresult = String(result);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tresult = text;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\tresult = text;\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}\n\t\t},\n\n\t\tevalPassageId : {\n\t\t\tvalue(passage) {\n\t\t\t\tif (passage == null || Story.has(passage)) { // lazy equality for null; `0` is a valid name, so we cannot simply evaluate `passage`\n\t\t\t\t\treturn passage;\n\t\t\t\t}\n\n\t\t\t\treturn Wikifier.helpers.evalText(passage);\n\t\t\t}\n\t\t},\n\n\t\thasBlockContext : {\n\t\t\tvalue(nodes) {\n\t\t\t\tconst hasGCS = typeof window.getComputedStyle === 'function';\n\n\t\t\t\tfor (let i = nodes.length - 1; i >= 0; --i) {\n\t\t\t\t\tconst node = nodes[i];\n\n\t\t\t\t\tswitch (node.nodeType) {\n\t\t\t\t\tcase Node.ELEMENT_NODE:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst tagName = node.nodeName.toUpperCase();\n\n\t\t\t\t\t\t\tif (tagName === 'BR') {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst styles = hasGCS ? window.getComputedStyle(node, null) : node.currentStyle;\n\n\t\t\t\t\t\t\tif (styles && styles.display) {\n\t\t\t\t\t\t\t\tif (styles.display === 'none') {\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn styles.display === 'block';\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tWebKit/Blink-based browsers do not attach any computed style\n\t\t\t\t\t\t\t\tinformation to elements until they're inserted into the DOM\n\t\t\t\t\t\t\t\t(and probably visible), not even the default browser styles\n\t\t\t\t\t\t\t\tand any user styles.  So, we make an assumption based on the\n\t\t\t\t\t\t\t\telement.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tswitch (tagName) {\n\t\t\t\t\t\t\tcase 'ADDRESS':\n\t\t\t\t\t\t\tcase 'ARTICLE':\n\t\t\t\t\t\t\tcase 'ASIDE':\n\t\t\t\t\t\t\tcase 'BLOCKQUOTE':\n\t\t\t\t\t\t\tcase 'CENTER':\n\t\t\t\t\t\t\tcase 'DIV':\n\t\t\t\t\t\t\tcase 'DL':\n\t\t\t\t\t\t\tcase 'FIGURE':\n\t\t\t\t\t\t\tcase 'FOOTER':\n\t\t\t\t\t\t\tcase 'FORM':\n\t\t\t\t\t\t\tcase 'H1':\n\t\t\t\t\t\t\tcase 'H2':\n\t\t\t\t\t\t\tcase 'H3':\n\t\t\t\t\t\t\tcase 'H4':\n\t\t\t\t\t\t\tcase 'H5':\n\t\t\t\t\t\t\tcase 'H6':\n\t\t\t\t\t\t\tcase 'HEADER':\n\t\t\t\t\t\t\tcase 'HR':\n\t\t\t\t\t\t\tcase 'MAIN':\n\t\t\t\t\t\t\tcase 'NAV':\n\t\t\t\t\t\t\tcase 'OL':\n\t\t\t\t\t\t\tcase 'P':\n\t\t\t\t\t\t\tcase 'PRE':\n\t\t\t\t\t\t\tcase 'SECTION':\n\t\t\t\t\t\t\tcase 'TABLE':\n\t\t\t\t\t\t\tcase 'UL':\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn false;\n\n\t\t\t\t\tcase Node.COMMENT_NODE:\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t},\n\n\t\tcreateShadowSetterCallback : {\n\t\t\tvalue : (() => {\n\t\t\t\tlet macroParser = null;\n\n\t\t\t\tfunction cacheMacroParser() {\n\t\t\t\t\tif (!macroParser) {\n\t\t\t\t\t\tmacroParser = Wikifier.Parser.get('macro');\n\n\t\t\t\t\t\tif (!macroParser) {\n\t\t\t\t\t\t\tthrow new Error('cannot find \"macro\" parser');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn macroParser;\n\t\t\t\t}\n\n\t\t\t\tfunction getMacroContextShadowView() {\n\t\t\t\t\tconst macro = macroParser || cacheMacroParser();\n\t\t\t\t\tconst view  = new Set();\n\n\t\t\t\t\tfor (let context = macro.context; context !== null; context = context.parent) {\n\t\t\t\t\t\tif (context._shadows) {\n\t\t\t\t\t\t\tcontext._shadows.forEach(name => view.add(name));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn [...view];\n\t\t\t\t}\n\n\t\t\t\tfunction helperCreateShadowSetterCallback(code) {\n\t\t\t\t\tconst shadowStore = {};\n\n\t\t\t\t\tgetMacroContextShadowView().forEach(varName => {\n\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\t\t\t\t\t});\n\n\t\t\t\t\treturn function () {\n\t\t\t\t\t\tconst shadowNames = Object.keys(shadowStore);\n\t\t\t\t\t\tconst valueCache  = shadowNames.length > 0 ? {} : null;\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t\t\tevaluation.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tCache the existing values of the variables to be shadowed and assign the\n\t\t\t\t\t\t\t\tshadow values.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tstore[varKey] = shadowStore[varName];\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t// Evaluate the JavaScript.\n\t\t\t\t\t\t\treturn Scripting.evalJavaScript(code);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t// Revert the variable shadowing.\n\t\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tUpdate the shadow store with the variable's current value, in case it\n\t\t\t\t\t\t\t\t\twas modified during the callback.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\n\t\t\t\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn helperCreateShadowSetterCallback;\n\t\t\t})()\n\t\t},\n\n\t\tparseSquareBracketedMarkup : {\n\t\t\tvalue : (() => {\n\t\t\t\t/* eslint-disable no-param-reassign */\n\t\t\t\tconst Item = Lexer.enumFromNames([ // lex item types object (pseudo-enumeration)\n\t\t\t\t\t'Error',     // error\n\t\t\t\t\t'DelimLTR',  // '|' or '->'\n\t\t\t\t\t'DelimRTL',  // '<-'\n\t\t\t\t\t'InnerMeta', // ']['\n\t\t\t\t\t'ImageMeta', // '[img[', '[<img[', or '[>img['\n\t\t\t\t\t'LinkMeta',  // '[['\n\t\t\t\t\t'Link',      // link destination\n\t\t\t\t\t'RightMeta', // ']]'\n\t\t\t\t\t'Setter',    // setter expression\n\t\t\t\t\t'Source',    // image source\n\t\t\t\t\t'Text'       // link text or image alt text\n\t\t\t\t]);\n\t\t\t\tconst Delim = Lexer.enumFromNames([ // delimiter state object (pseudo-enumeration)\n\t\t\t\t\t'None', // no delimiter encountered\n\t\t\t\t\t'LTR',  // '|' or '->'\n\t\t\t\t\t'RTL'   // '<-'\n\t\t\t\t]);\n\n\t\t\t\t// Lexing functions.\n\t\t\t\tfunction slurpQuote(lexer, endQuote) {\n\t\t\t\t\tloop: for (;;) {\n\t\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/* falls through */\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn EOF;\n\n\t\t\t\t\t\tcase endQuote:\n\t\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t\t}\n\n\t\t\t\t\treturn lexer.pos;\n\t\t\t\t}\n\n\t\t\t\tfunction lexLeftMeta(lexer) {\n\t\t\t\t\tif (!lexer.accept('[')) {\n\t\t\t\t\t\treturn lexer.error(Item.Error, 'malformed square-bracketed markup');\n\t\t\t\t\t}\n\n\t\t\t\t\t// Is link markup.\n\t\t\t\t\tif (lexer.accept('[')) {\n\t\t\t\t\t\tlexer.data.isLink = true;\n\t\t\t\t\t\tlexer.emit(Item.LinkMeta);\n\t\t\t\t\t}\n\n\t\t\t\t\t// May be image markup.\n\t\t\t\t\telse {\n\t\t\t\t\t\tlexer.accept('<>'); // aligner syntax\n\n\t\t\t\t\t\tif (!lexer.accept('Ii') || !lexer.accept('Mm') || !lexer.accept('Gg') || !lexer.accept('[')) {\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, 'malformed square-bracketed markup');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlexer.data.isLink = false;\n\t\t\t\t\t\tlexer.emit(Item.ImageMeta);\n\t\t\t\t\t}\n\n\t\t\t\t\tlexer.depth = 2; // account for both initial left square brackets\n\t\t\t\t\treturn lexCoreComponents;\n\t\t\t\t}\n\n\t\t\t\tfunction lexCoreComponents(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\t\t\t\t\tlet delim = Delim.None;\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tThis is not entirely reliable within sections that allow raw strings, since\n\t\t\t\t\t\t\t\tit's possible, however unlikely, for a raw string to contain unpaired double\n\t\t\t\t\t\t\t\tquotes.  The likelihood is low enough, however, that I'm deeming the risk as\n\t\t\t\t\t\t\t\tacceptable—for now, at least.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '|': // possible pipe ('|') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None) {\n\t\t\t\t\t\t\t\tdelim = Delim.LTR;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\tlexer.forward();\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimLTR);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '-': // possible right arrow ('->') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None && lexer.peek() === '>') {\n\t\t\t\t\t\t\t\tdelim = Delim.LTR;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimLTR);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '<': // possible left arrow ('<-') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None && lexer.peek() === '-') {\n\t\t\t\t\t\t\t\tdelim = Delim.RTL;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimRTL);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tswitch (lexer.peek()) {\n\t\t\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\n\t\t\t\t\t\t\t\t\tif (delim === Delim.RTL) {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.InnerMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn lexer.data.isLink ? lexSetter : lexImageLink;\n\n\t\t\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\n\t\t\t\t\t\t\t\t\tif (delim === Delim.RTL) {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfunction lexImageLink(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tThis is not entirely reliable within sections that allow raw strings, since\n\t\t\t\t\t\t\t\tit's possible, however unlikely, for a raw string to contain unpaired double\n\t\t\t\t\t\t\t\tquotes.  The likelihood is low enough, however, that I'm deeming the risk as\n\t\t\t\t\t\t\t\tacceptable—for now, at least.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup link component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tswitch (lexer.peek()) {\n\t\t\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.Link);\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.InnerMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn lexSetter;\n\n\t\t\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.Link);\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfunction lexSetter(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup setter component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase \"'\":\n\t\t\t\t\t\t\tif (slurpQuote(lexer, \"'\") === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated single quoted string in ${what} markup setter component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tif (lexer.peek() !== ']') {\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Setter);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Parse function.\n\t\t\t\tfunction parseSquareBracketedMarkup(w) {\n\t\t\t\t\t// Initialize the lexer.\n\t\t\t\t\tconst lexer  = new Lexer(w.source, lexLeftMeta);\n\n\t\t\t\t\t// Set the initial positions within the source string.\n\t\t\t\t\tlexer.start = lexer.pos = w.matchStart;\n\n\t\t\t\t\t// Lex the raw argument string.\n\t\t\t\t\tconst markup = {};\n\t\t\t\t\tconst items  = lexer.run();\n\t\t\t\t\tconst last   = items.last();\n\n\t\t\t\t\tif (last && last.type === Item.Error) {\n\t\t\t\t\t\tmarkup.error = last.message;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\titems.forEach(item => {\n\t\t\t\t\t\t\tconst text = item.text.trim();\n\n\t\t\t\t\t\t\tswitch (item.type) {\n\t\t\t\t\t\t\tcase Item.ImageMeta:\n\t\t\t\t\t\t\t\tmarkup.isImage = true;\n\n\t\t\t\t\t\t\t\tif (text[1] === '<') {\n\t\t\t\t\t\t\t\t\tmarkup.align = 'left';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (text[1] === '>') {\n\t\t\t\t\t\t\t\t\tmarkup.align = 'right';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.LinkMeta:\n\t\t\t\t\t\t\t\tmarkup.isLink = true;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Link:\n\t\t\t\t\t\t\t\tif (text[0] === '~') {\n\t\t\t\t\t\t\t\t\tmarkup.forceInternal = true;\n\t\t\t\t\t\t\t\t\tmarkup.link = text.slice(1);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tmarkup.link = text;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Setter:\n\t\t\t\t\t\t\t\tmarkup.setter = text;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Source:\n\t\t\t\t\t\t\t\tmarkup.source = text;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Text:\n\t\t\t\t\t\t\t\tmarkup.text = text;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tmarkup.pos = lexer.pos;\n\t\t\t\t\treturn markup;\n\t\t\t\t}\n\n\t\t\t\treturn parseSquareBracketedMarkup;\n\t\t\t\t/* eslint-enable no-param-reassign */\n\t\t\t})()\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Wikifier;\n})();\n/* eslint-enable max-len */\n\n/***********************************************************************************************************************\n\n\tmarkup/parserlib.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, DebugView, EOF, Engine, Lexer, Macro, MacroContext, Patterns, Scripting, State, Story, Template,\n\t       Wikifier, toStringOrDefault, throwError\n*/\n/* eslint \"no-param-reassign\": [ 2, { \"props\" : false } ] */\n\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _verbatimTagHandler(w) {\n\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\tconst match = this.lookahead.exec(w.source);\n\n\t\tif (match && match.index === w.matchStart) {\n\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t.append(match[1])\n\t\t\t\t.appendTo(w.output);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tParsers.\n\t*******************************************************************************************************************/\n\tWikifier.Parser.add({\n\t\tname       : 'quoteByBlock',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^<<<\\\\n',\n\t\tterminator : '^<<<\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.subWikify(\n\t\t\t\tjQuery(document.createElement('blockquote'))\n\t\t\t\t\t.appendTo(w.output)\n\t\t\t\t\t.get(0),\n\t\t\t\tthis.terminator\n\t\t\t);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'quoteByLine',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^>+',\n\t\tlookahead  : /^>+/gm,\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst destStack = [w.output];\n\t\t\tlet curLevel = 0;\n\t\t\tlet newLevel = w.matchLength;\n\t\t\tlet matched;\n\t\t\tlet i;\n\n\t\t\tdo {\n\t\t\t\tif (newLevel > curLevel) {\n\t\t\t\t\tfor (i = curLevel; i < newLevel; ++i) {\n\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\tjQuery(document.createElement('blockquote'))\n\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (newLevel < curLevel) {\n\t\t\t\t\tfor (i = curLevel; i > newLevel; --i) {\n\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcurLevel = newLevel;\n\t\t\t\tw.subWikify(destStack[destStack.length - 1], this.terminator);\n\t\t\t\tjQuery(document.createElement('br')).appendTo(destStack[destStack.length - 1]);\n\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tnewLevel = match[0].length;\n\t\t\t\t\tw.nextMatch += match[0].length;\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'macro',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<<',\n\t\tlookahead : new RegExp(`<<(/?${Patterns.macroName})(?:\\\\s*)((?:(?:\\`(?:\\\\\\\\.|[^\\`\\\\\\\\])*\\`)|(?:\"(?:\\\\\\\\.|[^\"\\\\\\\\])*\")|(?:'(?:\\\\\\\\.|[^'\\\\\\\\])*')|(?:\\\\[(?:[<>]?[Ii][Mm][Gg])?\\\\[[^\\\\r\\\\n]*?\\\\]\\\\]+)|[^>]|(?:>(?!>)))*)>>`, 'gm'),\n\t\tworking   : { source : '', name : '', arguments : '', index : 0 }, // the working parse object\n\t\tcontext   : null, // last execution context object (top-level macros, hierarchically, have a null context)\n\n\t\thandler(w) {\n\t\t\tconst matchStart = this.lookahead.lastIndex = w.matchStart;\n\n\t\t\tif (this.parseTag(w)) {\n\t\t\t\t/*\n\t\t\t\t\tIf `parseBody()` is called below, it will modify the current working\n\t\t\t\t\tvalues, so we must cache them now.\n\t\t\t\t*/\n\t\t\t\tconst nextMatch = w.nextMatch;\n\t\t\t\tconst name      = this.working.name;\n\t\t\t\tconst rawArgs   = this.working.arguments;\n\t\t\t\tlet macro;\n\n\t\t\t\ttry {\n\t\t\t\t\tmacro = Macro.get(name);\n\n\t\t\t\t\tif (macro) {\n\t\t\t\t\t\tlet payload = null;\n\n\t\t\t\t\t\tif (macro.hasOwnProperty('tags')) {\n\t\t\t\t\t\t\tpayload = this.parseBody(w, macro);\n\n\t\t\t\t\t\t\tif (!payload) {\n\t\t\t\t\t\t\t\tw.nextMatch = nextMatch; // we must reset `w.nextMatch` here, as `parseBody()` modifies it\n\t\t\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t\t`cannot find a closing tag for macro <<${name}>>`,\n\t\t\t\t\t\t\t\t\t`${w.source.slice(matchStart, w.nextMatch)}\\u2026`\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (typeof macro.handler === 'function') {\n\t\t\t\t\t\t\tconst args = !payload\n\t\t\t\t\t\t\t\t? this.createArgs(rawArgs, this.skipArgs(macro, macro.name))\n\t\t\t\t\t\t\t\t: payload[0].args;\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tNew-style macros.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (macro.hasOwnProperty('_MACRO_API')) {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tAdd the macro's execution context to the context chain.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tthis.context = new MacroContext({\n\t\t\t\t\t\t\t\t\tmacro,\n\t\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\t\targs,\n\t\t\t\t\t\t\t\t\tpayload,\n\t\t\t\t\t\t\t\t\tsource : w.source.slice(matchStart, w.nextMatch),\n\t\t\t\t\t\t\t\t\tparent : this.context,\n\t\t\t\t\t\t\t\t\tparser : w\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tCall the handler.\n\n\t\t\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\t\t\t\t\t\tto ensure that the execution context is properly restored in the event\n\t\t\t\t\t\t\t\t\tthat an uncaught exception is thrown during the handler call.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tmacro.handler.call(this.context);\n\t\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\t\tQUESTION: Swap to the following, which passes macro arguments in\n\t\t\t\t\t\t\t\t\t\tas parameters to the handler function, in addition to them being\n\t\t\t\t\t\t\t\t\t\tavailable on its `this`?  If so, it might still be something to\n\t\t\t\t\t\t\t\t\t\thold off on until v3, when the legacy macro API is removed.\n\n\t\t\t\t\t\t\t\t\t\tmacro.handler.apply(this.context, this.context.args);\n\t\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t\tthis.context = this.context.parent;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t[DEPRECATED] Old-style/legacy macros.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tSet up the raw arguments string.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tconst prevRawArgs = w._rawArgs;\n\t\t\t\t\t\t\t\tw._rawArgs = rawArgs;\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tCall the handler.\n\n\t\t\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\t\t\t\t\t\tto ensure that the previous raw arguments string is properly restored in\n\t\t\t\t\t\t\t\t\tthe event that an uncaught exception is thrown during the handler call.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tmacro.handler(w.output, name, args, w, payload);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t\tw._rawArgs = prevRawArgs;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t`macro <<${name}>> handler function ${macro.hasOwnProperty('handler') ? 'is not a function' : 'does not exist'}`,\n\t\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (Macro.tags.has(name)) {\n\t\t\t\t\t\tconst tags = Macro.tags.get(name);\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`child tag <<${name}>> was found outside of a call to its parent macro${tags.length === 1 ? '' : 's'} <<${tags.join('>>, <<')}>>`,\n\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`macro <<${name}>> does not exist`,\n\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot execute ${macro && macro.isWidget ? 'widget' : 'macro'} <<${name}>>: ${ex.message}`,\n\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\tthis.working.source    = '';\n\t\t\t\t\tthis.working.name      = '';\n\t\t\t\t\tthis.working.arguments = '';\n\t\t\t\t\tthis.working.index     = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t}\n\t\t},\n\n\t\tparseTag(w) {\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart && match[1]) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tthis.working.source    = w.source.slice(match.index, this.lookahead.lastIndex);\n\t\t\t\tthis.working.name      = match[1];\n\t\t\t\tthis.working.arguments = match[2];\n\t\t\t\tthis.working.index     = match.index;\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t},\n\n\t\tparseBody(w, macro) {\n\t\t\tconst openTag  = this.working.name;\n\t\t\tconst closeTag = `/${openTag}`;\n\t\t\tconst closeAlt = `end${openTag}`;\n\t\t\tconst bodyTags = Array.isArray(macro.tags) ? macro.tags : false;\n\t\t\tconst payload  = [];\n\t\t\tlet end          = -1;\n\t\t\tlet opened       = 1;\n\t\t\tlet curSource    = this.working.source;\n\t\t\tlet curTag       = this.working.name;\n\t\t\tlet curArgument  = this.working.arguments;\n\t\t\tlet contentStart = w.nextMatch;\n\n\t\t\twhile ((w.matchStart = w.source.indexOf(this.match, w.nextMatch)) !== -1) {\n\t\t\t\tif (!this.parseTag(w)) {\n\t\t\t\t\tthis.lookahead.lastIndex = w.nextMatch = w.matchStart + this.match.length;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst tagSource = this.working.source;\n\t\t\t\tconst tagName   = this.working.name;\n\t\t\t\tconst tagArgs   = this.working.arguments;\n\t\t\t\tconst tagBegin  = this.working.index;\n\t\t\t\tconst tagEnd    = w.nextMatch;\n\n\t\t\t\tswitch (tagName) {\n\t\t\t\tcase openTag:\n\t\t\t\t\t++opened;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase closeAlt:\n\t\t\t\tcase closeTag:\n\t\t\t\t\t--opened;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tif (opened === 1 && bodyTags) {\n\t\t\t\t\t\tfor (let i = 0, iend = bodyTags.length; i < iend; ++i) {\n\t\t\t\t\t\t\tif (tagName === bodyTags[i]) {\n\t\t\t\t\t\t\t\tpayload.push({\n\t\t\t\t\t\t\t\t\tsource    : curSource,\n\t\t\t\t\t\t\t\t\tname      : curTag,\n\t\t\t\t\t\t\t\t\targuments : curArgument,\n\t\t\t\t\t\t\t\t\targs      : this.createArgs(curArgument, this.skipArgs(macro, curTag)),\n\t\t\t\t\t\t\t\t\tcontents  : w.source.slice(contentStart, tagBegin)\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tcurSource    = tagSource;\n\t\t\t\t\t\t\t\tcurTag       = tagName;\n\t\t\t\t\t\t\t\tcurArgument  = tagArgs;\n\t\t\t\t\t\t\t\tcontentStart = tagEnd;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (opened === 0) {\n\t\t\t\t\tpayload.push({\n\t\t\t\t\t\tsource    : curSource,\n\t\t\t\t\t\tname      : curTag,\n\t\t\t\t\t\targuments : curArgument,\n\t\t\t\t\t\targs      : this.createArgs(curArgument, this.skipArgs(macro, curTag)),\n\t\t\t\t\t\tcontents  : w.source.slice(contentStart, tagBegin)\n\t\t\t\t\t});\n\t\t\t\t\tend = tagEnd;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (end !== -1) {\n\t\t\t\tw.nextMatch = end;\n\t\t\t\treturn payload;\n\t\t\t}\n\n\t\t\treturn null;\n\t\t},\n\n\t\tcreateArgs(rawArgsString, skipArgs) {\n\t\t\tconst args = skipArgs ? [] : this.parseArgs(rawArgsString);\n\n\t\t\t// Extend the args array with the raw and full argument strings.\n\t\t\tObject.defineProperties(args, {\n\t\t\t\traw : {\n\t\t\t\t\tvalue : rawArgsString\n\t\t\t\t},\n\t\t\t\tfull : {\n\t\t\t\t\tvalue : Scripting.parse(rawArgsString)\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn args;\n\t\t},\n\n\t\tskipArgs(macro, tagName) {\n\t\t\tif (macro.hasOwnProperty('skipArgs')) {\n\t\t\t\tconst sa = macro.skipArgs;\n\n\t\t\t\treturn typeof sa === 'boolean' && sa || Array.isArray(sa) && sa.includes(tagName);\n\t\t\t}\n\t\t\t/* legacy */\n\t\t\telse if (macro.hasOwnProperty('skipArg0')) {\n\t\t\t\treturn macro.skipArg0 && macro.name === tagName;\n\t\t\t}\n\t\t\t/* /legacy */\n\n\t\t\treturn false;\n\t\t},\n\n\t\tparseArgs : (() => {\n\t\t\tconst Item = Lexer.enumFromNames([ // lex item types object (pseudo-enumeration)\n\t\t\t\t'Error',        // error\n\t\t\t\t'Bareword',     // bare identifier\n\t\t\t\t'Expression',   // expression (backquoted)\n\t\t\t\t'String',       // quoted string (single or double)\n\t\t\t\t'SquareBracket' // [[…]] or [img[…]]\n\t\t\t]);\n\t\t\tconst spaceRe    = new RegExp(Patterns.space);\n\t\t\tconst notSpaceRe = new RegExp(Patterns.notSpace);\n\t\t\tconst varTest    = new RegExp(`^${Patterns.variable}`);\n\n\t\t\t// Lexing functions.\n\t\t\tfunction slurpQuote(lexer, endQuote) {\n\t\t\t\tloop: for (;;) {\n\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* falls through */\n\t\t\t\t\tcase EOF:\n\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\treturn EOF;\n\n\t\t\t\t\tcase endQuote:\n\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t}\n\n\t\t\t\treturn lexer.pos;\n\t\t\t}\n\n\t\t\tfunction lexSpace(lexer) {\n\t\t\t\tconst offset = lexer.source.slice(lexer.pos).search(notSpaceRe);\n\n\t\t\t\tif (offset === EOF) {\n\t\t\t\t\t// no non-whitespace characters, so bail\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\telse if (offset !== 0) {\n\t\t\t\t\tlexer.pos += offset;\n\t\t\t\t\tlexer.ignore();\n\t\t\t\t}\n\n\t\t\t\t// determine what the next state is\n\t\t\t\tswitch (lexer.next()) {\n\t\t\t\tcase '`':\n\t\t\t\t\treturn lexExpression;\n\t\t\t\tcase '\"':\n\t\t\t\t\treturn lexDoubleQuote;\n\t\t\t\tcase \"'\":\n\t\t\t\t\treturn lexSingleQuote;\n\t\t\t\tcase '[':\n\t\t\t\t\treturn lexSquareBracket;\n\t\t\t\tdefault:\n\t\t\t\t\treturn lexBareword;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction lexExpression(lexer) {\n\t\t\t\tif (slurpQuote(lexer, '`') === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated backquote expression');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.Expression);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexDoubleQuote(lexer) {\n\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated double quoted string');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.String);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexSingleQuote(lexer) {\n\t\t\t\tif (slurpQuote(lexer, \"'\") === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated single quoted string');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.String);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexSquareBracket(lexer) {\n\t\t\t\tconst imgMeta = '<>IiMmGg';\n\t\t\t\tlet what;\n\n\t\t\t\tif (lexer.accept(imgMeta)) {\n\t\t\t\t\twhat = 'image';\n\t\t\t\t\tlexer.acceptRun(imgMeta);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\twhat = 'link';\n\t\t\t\t}\n\n\t\t\t\tif (!lexer.accept('[')) {\n\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t}\n\n\t\t\t\tlexer.depth = 2; // account for both initial left square brackets\n\n\t\t\t\tloop: for (;;) {\n\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* falls through */\n\t\t\t\t\tcase EOF:\n\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\tcase '[':\n\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase ']':\n\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\tif (lexer.depth < 0) {\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, \"unexpected right square bracket ']'\");\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\tif (lexer.next() === ']') {\n\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.SquareBracket);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexBareword(lexer) {\n\t\t\t\tconst offset = lexer.source.slice(lexer.pos).search(spaceRe);\n\t\t\t\tlexer.pos = offset === EOF ? lexer.source.length : lexer.pos + offset;\n\t\t\t\tlexer.emit(Item.Bareword);\n\t\t\t\treturn offset === EOF ? null : lexSpace;\n\t\t\t}\n\n\t\t\t// Parse function.\n\t\t\tfunction parseMacroArgs(rawArgsString) {\n\t\t\t\t// Initialize the lexer.\n\t\t\t\tconst lexer = new Lexer(rawArgsString, lexSpace);\n\t\t\t\tconst args  = [];\n\n\t\t\t\t// Lex the raw argument string.\n\t\t\t\tlexer.run().forEach(item => {\n\t\t\t\t\tlet arg = item.text;\n\n\t\t\t\t\tswitch (item.type) {\n\t\t\t\t\tcase Item.Error:\n\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${item.message}`);\n\n\t\t\t\t\tcase Item.Bareword:\n\t\t\t\t\t\t// A variable, so substitute its value.\n\t\t\t\t\t\tif (varTest.test(arg)) {\n\t\t\t\t\t\t\targ = State.getVar(arg);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Property access on the settings or setup objects, so try to evaluate it.\n\t\t\t\t\t\telse if (/^(?:settings|setup)[.[]/.test(arg)) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\targ = Scripting.evalTwineScript(arg);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Null literal, so convert it into null.\n\t\t\t\t\t\telse if (arg === 'null') {\n\t\t\t\t\t\t\targ = null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Undefined literal, so convert it into undefined.\n\t\t\t\t\t\telse if (arg === 'undefined') {\n\t\t\t\t\t\t\targ = undefined;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Boolean true literal, so convert it into true.\n\t\t\t\t\t\telse if (arg === 'true') {\n\t\t\t\t\t\t\targ = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Boolean false literal, so convert it into false.\n\t\t\t\t\t\telse if (arg === 'false') {\n\t\t\t\t\t\t\targ = false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// NaN literal, so convert it into NaN.\n\t\t\t\t\t\telse if (arg === 'NaN') {\n\t\t\t\t\t\t\targ = NaN;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Attempt to convert it into a number, in case it's a numeric literal.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst argAsNum = Number(arg);\n\n\t\t\t\t\t\t\tif (!Number.isNaN(argAsNum)) {\n\t\t\t\t\t\t\t\targ = argAsNum;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.Expression:\n\t\t\t\t\t\targ = arg.slice(1, -1).trim(); // remove the backquotes and trim the expression\n\n\t\t\t\t\t\t// Empty backquotes.\n\t\t\t\t\t\tif (arg === '') {\n\t\t\t\t\t\t\targ = undefined;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Evaluate the expression.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tThe enclosing parenthesis here are necessary to force a code string\n\t\t\t\t\t\t\t\t\tconsisting solely of an object literal to be evaluated as such, rather\n\t\t\t\t\t\t\t\t\tthan as a code block.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\targ = Scripting.evalTwineScript(`(${arg})`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument expression \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.String:\n\t\t\t\t\t\t// Evaluate the string to handle escaped characters.\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\targ = Scripting.evalJavaScript(arg);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument string \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.SquareBracket:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\t\t\tsource     : arg,\n\t\t\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${markup.error}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (markup.pos < arg.length) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": unexpected character(s) \"${arg.slice(markup.pos)}\" (pos: ${markup.pos})`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert to a link or image object.\n\t\t\t\t\t\t\tif (markup.isLink) {\n\t\t\t\t\t\t\t\t// .isLink, [.text], [.forceInternal], .link, [.setter]\n\t\t\t\t\t\t\t\targ = { isLink : true };\n\t\t\t\t\t\t\t\targ.count    = markup.hasOwnProperty('text') ? 2 : 1;\n\t\t\t\t\t\t\t\targ.link     = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\t\t\t\t\t\targ.text     = markup.hasOwnProperty('text') ? Wikifier.helpers.evalText(markup.text) : arg.link;\n\t\t\t\t\t\t\t\targ.external = !markup.forceInternal && Wikifier.isExternalLink(arg.link);\n\t\t\t\t\t\t\t\targ.setFn    = markup.hasOwnProperty('setter')\n\t\t\t\t\t\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (markup.isImage) {\n\t\t\t\t\t\t\t\t// .isImage, [.align], [.title], .source, [.forceInternal], [.link], [.setter]\n\t\t\t\t\t\t\t\targ = (source => {\n\t\t\t\t\t\t\t\t\tconst imgObj = {\n\t\t\t\t\t\t\t\t\t\tsource,\n\t\t\t\t\t\t\t\t\t\tisImage : true\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t\t// Check for Twine 1.4 Base64 image passage transclusion.\n\t\t\t\t\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t\t\t\t\timgObj.source  = passage.text;\n\t\t\t\t\t\t\t\t\t\t\timgObj.passage = passage.title;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturn imgObj;\n\t\t\t\t\t\t\t\t})(Wikifier.helpers.evalPassageId(markup.source));\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('align')) {\n\t\t\t\t\t\t\t\t\targ.align = markup.align;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('text')) {\n\t\t\t\t\t\t\t\t\targ.title = Wikifier.helpers.evalText(markup.text);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('link')) {\n\t\t\t\t\t\t\t\t\targ.link     = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\t\t\t\t\t\t\targ.external = !markup.forceInternal && Wikifier.isExternalLink(arg.link);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\targ.setFn = markup.hasOwnProperty('setter')\n\t\t\t\t\t\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\targs.push(arg);\n\t\t\t\t});\n\n\t\t\t\treturn args;\n\t\t\t}\n\n\t\t\treturn parseMacroArgs;\n\t\t})()\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'link',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\[\\\\[[^[]',\n\n\t\thandler(w) {\n\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup(w);\n\n\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = markup.pos;\n\n\t\t\t// text=(text), forceInternal=(~), link=link, setter=(setter)\n\t\t\tconst link  = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\tconst text  = markup.hasOwnProperty('text') ? Wikifier.helpers.evalText(markup.text) : link;\n\t\t\tconst setFn = markup.hasOwnProperty('setter')\n\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t: null;\n\n\t\t\t// Debug view setup.\n\t\t\tconst output = (Config.debug\n\t\t\t\t? new DebugView(w.output, 'link-markup', '[[link]]', w.source.slice(w.matchStart, w.nextMatch))\n\t\t\t\t: w\n\t\t\t).output;\n\n\t\t\tif (markup.forceInternal || !Wikifier.isExternalLink(link)) {\n\t\t\t\tWikifier.createInternalLink(output, link, text, setFn);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tWikifier.createExternalLink(output, link, text);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'urlLink',\n\t\tprofiles : ['core'],\n\t\tmatch    : Patterns.url,\n\n\t\thandler(w) {\n\t\t\tw.outputText(Wikifier.createExternalLink(w.output, w.matchText), w.matchStart, w.nextMatch);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'image',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\[[<>]?[Ii][Mm][Gg]\\\\[',\n\n\t\thandler(w) {\n\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup(w);\n\n\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = markup.pos;\n\n\t\t\t// Debug view setup.\n\t\t\tlet debugView;\n\n\t\t\tif (Config.debug) {\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tw.output,\n\t\t\t\t\t'image-markup',\n\t\t\t\t\tmarkup.hasOwnProperty('link') ? '[img[][link]]' : '[img[]]',\n\t\t\t\t\tw.source.slice(w.matchStart, w.nextMatch)\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ block : true });\n\t\t\t}\n\n\t\t\t// align=(left|right), title=(title), source=source, forceInternal=(~), link=(link), setter=(setter)\n\t\t\tconst setFn = markup.hasOwnProperty('setter')\n\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t: null;\n\t\t\tlet el     = (Config.debug ? debugView : w).output;\n\t\t\tlet source;\n\n\t\t\tif (markup.hasOwnProperty('link')) {\n\t\t\t\tconst link = Wikifier.helpers.evalPassageId(markup.link);\n\n\t\t\t\tif (markup.forceInternal || !Wikifier.isExternalLink(link)) {\n\t\t\t\t\tel = Wikifier.createInternalLink(el, link, null, setFn);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tel = Wikifier.createExternalLink(el, link);\n\t\t\t\t}\n\n\t\t\t\tel.classList.add('link-image');\n\t\t\t}\n\n\t\t\tel = jQuery(document.createElement('img'))\n\t\t\t\t.appendTo(el)\n\t\t\t\t.get(0);\n\t\t\tsource = Wikifier.helpers.evalPassageId(markup.source);\n\n\t\t\t// Check for image passage transclusion.\n\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\tel.setAttribute('data-passage', passage.title);\n\t\t\t\t\tsource = passage.text.trim();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tel.src = source;\n\n\t\t\tif (markup.hasOwnProperty('text')) {\n\t\t\t\tel.title = Wikifier.helpers.evalText(markup.text);\n\t\t\t}\n\n\t\t\tif (markup.hasOwnProperty('align')) {\n\t\t\t\tel.align = markup.align;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'monospacedByBlock',\n\t\tprofiles  : ['block'],\n\t\tmatch     : '^\\\\{\\\\{\\\\{\\\\n',\n\t\tlookahead : /^\\{\\{\\{\\n((?:^[^\\n]*\\n)+?)(^\\}\\}\\}$\\n?)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tconst pre = jQuery(document.createElement('pre'));\n\t\t\t\tjQuery(document.createElement('code'))\n\t\t\t\t\t.text(match[1])\n\t\t\t\t\t.appendTo(pre);\n\t\t\t\tpre.appendTo(w.output);\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'formatByChar',\n\t\tprofiles : ['core'],\n\t\tmatch    : \"''|//|__|\\\\^\\\\^|~~|==|\\\\{\\\\{\\\\{\",\n\n\t\thandler(w) {\n\t\t\tswitch (w.matchText) {\n\t\t\tcase \"''\":\n\t\t\t\tw.subWikify(jQuery(document.createElement('strong')).appendTo(w.output).get(0), \"''\");\n\t\t\t\tbreak;\n\n\t\t\tcase '//':\n\t\t\t\tw.subWikify(jQuery(document.createElement('em')).appendTo(w.output).get(0), '//');\n\t\t\t\tbreak;\n\n\t\t\tcase '__':\n\t\t\t\tw.subWikify(jQuery(document.createElement('u')).appendTo(w.output).get(0), '__');\n\t\t\t\tbreak;\n\n\t\t\tcase '^^':\n\t\t\t\tw.subWikify(jQuery(document.createElement('sup')).appendTo(w.output).get(0), '\\\\^\\\\^');\n\t\t\t\tbreak;\n\n\t\t\tcase '~~':\n\t\t\t\tw.subWikify(jQuery(document.createElement('sub')).appendTo(w.output).get(0), '~~');\n\t\t\t\tbreak;\n\n\t\t\tcase '==':\n\t\t\t\tw.subWikify(jQuery(document.createElement('s')).appendTo(w.output).get(0), '==');\n\t\t\t\tbreak;\n\n\t\t\tcase '{{{':\n\t\t\t\t{\n\t\t\t\t\tconst lookahead = /\\{\\{\\{((?:.|\\n)*?)\\}\\}\\}/gm;\n\n\t\t\t\t\tlookahead.lastIndex = w.matchStart;\n\n\t\t\t\t\tconst match = lookahead.exec(w.source);\n\n\t\t\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\t\t\tjQuery(document.createElement('code'))\n\t\t\t\t\t\t\t.text(match[1])\n\t\t\t\t\t\t\t.appendTo(w.output);\n\t\t\t\t\t\tw.nextMatch = lookahead.lastIndex;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'customStyle',\n\t\tprofiles   : ['core'],\n\t\tmatch      : '@@',\n\t\tterminator : '@@',\n\t\tblockRe    : /\\s*\\n/gm,\n\n\t\thandler(w) {\n\t\t\tconst css = Wikifier.helpers.inlineCss(w);\n\n\t\t\tthis.blockRe.lastIndex = w.nextMatch; // must follow the call to `inlineCss()`\n\n\t\t\tconst blockMatch = this.blockRe.exec(w.source);\n\t\t\tconst blockLevel = blockMatch && blockMatch.index === w.nextMatch;\n\t\t\tconst $el        = jQuery(document.createElement(blockLevel ? 'div' : 'span'))\n\t\t\t\t.appendTo(w.output);\n\n\t\t\tif (css.classes.length === 0 && css.id === '' && Object.keys(css.styles).length === 0) {\n\t\t\t\t$el.addClass('marked');\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcss.classes.forEach(className => $el.addClass(className));\n\n\t\t\t\tif (css.id !== '') {\n\t\t\t\t\t$el.attr('id', css.id);\n\t\t\t\t}\n\n\t\t\t\t$el.css(css.styles);\n\t\t\t}\n\n\t\t\tif (blockLevel) {\n\t\t\t\t// Skip the leading and, if it exists, trailing newlines.\n\t\t\t\tw.nextMatch += blockMatch[0].length;\n\t\t\t\tw.subWikify($el[0], `\\\\n?${this.terminator}`);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tw.subWikify($el[0], this.terminator);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimText',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '\"{3}|<[Nn][Oo][Ww][Ii][Kk][Ii]>',\n\t\tlookahead : /(?:\"{3}((?:.|\\n)*?)\"{3})|(?:<[Nn][Oo][Ww][Ii][Kk][Ii]>((?:.|\\n)*?)<\\/[Nn][Oo][Ww][Ii][Kk][Ii]>)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tjQuery(document.createElement('span'))\n\t\t\t\t\t.addClass('verbatim')\n\t\t\t\t\t.text(match[1] || match[2])\n\t\t\t\t\t.appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'horizontalRule',\n\t\tprofiles : ['core'],\n\t\tmatch    : '^----+$\\\\n?|<[Hh][Rr]\\\\s*/?>\\\\n?',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createElement('hr')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'emdash',\n\t\tprofiles : ['core'],\n\t\tmatch    : '--',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createTextNode('\\u2014')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'doubleDollarSign',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\${2}', // eslint-disable-line no-template-curly-in-string\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createTextNode('$')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\t/*\n\t\t\tSupported syntax:\n\t\t\t\t$variable\n\t\t\t\t$variable.property\n\t\t\t\t$variable[numericIndex]\n\t\t\t\t$variable[\"property\"]\n\t\t\t\t$variable['property']\n\t\t\t\t$variable[$indexOrPropertyVariable]\n\t\t*/\n\t\tname     : 'nakedVariable',\n\t\tprofiles : ['core'],\n\t\tmatch    : `${Patterns.variable}(?:(?:\\\\.${Patterns.identifier})|(?:\\\\[\\\\d+\\\\])|(?:\\\\[\"(?:\\\\\\\\.|[^\"\\\\\\\\])+\"\\\\])|(?:\\\\['(?:\\\\\\\\.|[^'\\\\\\\\])+'\\\\])|(?:\\\\[${Patterns.variable}\\\\]))*`,\n\n\t\thandler(w) {\n\t\t\tconst result = toStringOrDefault(State.getVar(w.matchText), null);\n\n\t\t\tif (result === null) {\n\t\t\t\tjQuery(document.createTextNode(w.matchText)).appendTo(w.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnew Wikifier(\n\t\t\t\t\t(Config.debug\n\t\t\t\t\t\t? new DebugView(w.output, 'variable', w.matchText, w.matchText) // Debug view setup.\n\t\t\t\t\t\t: w\n\t\t\t\t\t).output,\n\t\t\t\t\tresult\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'template',\n\t\tprofiles : ['core'],\n\t\tmatch    : `\\\\?${Patterns.templateName}`,\n\n\t\thandler(w) {\n\t\t\tconst name = w.matchText.slice(1);\n\t\t\tlet template = Template.get(name);\n\t\t\tlet result   = null;\n\n\t\t\t// If we have an array of templates, randomly choose one.\n\t\t\tif (template instanceof Array) {\n\t\t\t\ttemplate = template.random();\n\t\t\t}\n\n\t\t\tswitch (typeof template) {\n\t\t\tcase 'function':\n\t\t\t\ttry {\n\t\t\t\t\tresult = toStringOrDefault(template.call({ name }), null);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot execute function template ?${name}: ${ex.message}`,\n\t\t\t\t\t\tw.source.slice(w.matchStart, w.nextMatch)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'string':\n\t\t\t\tresult = template;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (result === null) {\n\t\t\t\tjQuery(document.createTextNode(w.matchText)).appendTo(w.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnew Wikifier(\n\t\t\t\t\t(Config.debug\n\t\t\t\t\t\t? new DebugView(w.output, 'template', w.matchText, w.matchText) // Debug view setup.\n\t\t\t\t\t\t: w\n\t\t\t\t\t).output,\n\t\t\t\t\tresult\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'heading',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^!{1,6}',\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.subWikify(\n\t\t\t\tjQuery(document.createElement(`h${w.matchLength}`)).appendTo(w.output).get(0),\n\t\t\t\tthis.terminator\n\t\t\t);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname           : 'table',\n\t\tprofiles       : ['block'],\n\t\tmatch          : '^\\\\|(?:[^\\\\n]*)\\\\|(?:[fhck]?)$',\n\t\tlookahead      : /^\\|([^\\n]*)\\|([fhck]?)$/gm,\n\t\trowTerminator  : '\\\\|(?:[cfhk]?)$\\\\n?',\n\t\tcellPattern    : '(?:\\\\|([^\\\\n\\\\|]*)\\\\|)|(\\\\|[cfhk]?$\\\\n?)',\n\t\tcellTerminator : '(?:\\\\u0020*)\\\\|',\n\t\trowTypes       : { c : 'caption', f : 'tfoot', h : 'thead', '' : 'tbody' }, // eslint-disable-line id-length\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst table       = jQuery(document.createElement('table')).appendTo(w.output).get(0);\n\t\t\tconst prevColumns = [];\n\t\t\tlet curRowType    = null;\n\t\t\tlet $rowContainer = null;\n\t\t\tlet rowCount      = 0;\n\t\t\tlet matched;\n\n\t\t\tw.nextMatch = w.matchStart;\n\n\t\t\tdo {\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tconst nextRowType = match[2];\n\n\t\t\t\t\tif (nextRowType === 'k') {\n\t\t\t\t\t\ttable.className = match[1];\n\t\t\t\t\t\tw.nextMatch += match[0].length + 1;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (nextRowType !== curRowType) {\n\t\t\t\t\t\t\tcurRowType = nextRowType;\n\t\t\t\t\t\t\t$rowContainer = jQuery(document.createElement(this.rowTypes[nextRowType]))\n\t\t\t\t\t\t\t\t.appendTo(table);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (curRowType === 'c') {\n\t\t\t\t\t\t\t$rowContainer.css('caption-side', rowCount === 0 ? 'top' : 'bottom');\n\t\t\t\t\t\t\tw.nextMatch += 1;\n\t\t\t\t\t\t\tw.subWikify($rowContainer[0], this.rowTerminator);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tthis.rowHandler(\n\t\t\t\t\t\t\t\tw,\n\t\t\t\t\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t\t\t\t\t.appendTo($rowContainer)\n\t\t\t\t\t\t\t\t\t.get(0),\n\t\t\t\t\t\t\t\tprevColumns\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t++rowCount;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t},\n\n\t\trowHandler(w, rowEl, prevColumns) {\n\t\t\tconst cellRe = new RegExp(this.cellPattern, 'gm');\n\t\t\tlet col         = 0;\n\t\t\tlet curColCount = 1;\n\t\t\tlet matched;\n\n\t\t\tdo {\n\t\t\t\tcellRe.lastIndex = w.nextMatch;\n\n\t\t\t\tconst cellMatch = cellRe.exec(w.source);\n\n\t\t\t\tmatched = cellMatch && cellMatch.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tif (cellMatch[1] === '~') {\n\t\t\t\t\t\tconst last = prevColumns[col];\n\n\t\t\t\t\t\tif (last) {\n\t\t\t\t\t\t\t++last.rowCount;\n\t\t\t\t\t\t\tlast.$element\n\t\t\t\t\t\t\t\t.attr('rowspan', last.rowCount)\n\t\t\t\t\t\t\t\t.css('vertical-align', 'middle');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length - 1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (cellMatch[1] === '>') {\n\t\t\t\t\t\t++curColCount;\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length - 1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (cellMatch[2]) {\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t++w.nextMatch;\n\n\t\t\t\t\t\tconst css = Wikifier.helpers.inlineCss(w);\n\t\t\t\t\t\tlet spaceLeft  = false;\n\t\t\t\t\t\tlet spaceRight = false;\n\t\t\t\t\t\tlet $cell;\n\n\t\t\t\t\t\twhile (w.source.substr(w.nextMatch, 1) === ' ') {\n\t\t\t\t\t\t\tspaceLeft = true;\n\t\t\t\t\t\t\t++w.nextMatch;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (w.source.substr(w.nextMatch, 1) === '!') {\n\t\t\t\t\t\t\t$cell = jQuery(document.createElement('th')).appendTo(rowEl);\n\t\t\t\t\t\t\t++w.nextMatch;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t$cell = jQuery(document.createElement('td')).appendTo(rowEl);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tprevColumns[col] = {\n\t\t\t\t\t\t\trowCount : 1,\n\t\t\t\t\t\t\t$element : $cell\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (curColCount > 1) {\n\t\t\t\t\t\t\t$cell.attr('colspan', curColCount);\n\t\t\t\t\t\t\tcurColCount = 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tw.subWikify($cell[0], this.cellTerminator);\n\n\t\t\t\t\t\tif (w.matchText.substr(w.matchText.length - 2, 1) === ' ') {\n\t\t\t\t\t\t\tspaceRight = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcss.classes.forEach(className => $cell.addClass(className));\n\n\t\t\t\t\t\tif (css.id !== '') {\n\t\t\t\t\t\t\t$cell.attr('id', css.id);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (spaceLeft && spaceRight) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'center';\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (spaceLeft) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'right';\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (spaceRight) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'left';\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$cell.css(css.styles);\n\n\t\t\t\t\t\tw.nextMatch = w.nextMatch - 1;\n\t\t\t\t\t}\n\n\t\t\t\t\t++col;\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'list',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^(?:(?:\\\\*+)|(?:#+))',\n\t\tlookahead  : /^(?:(\\*+)|(#+))/gm,\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = w.matchStart;\n\n\t\t\tconst destStack = [w.output];\n\t\t\tlet curType  = null;\n\t\t\tlet curLevel = 0;\n\t\t\tlet matched;\n\t\t\tlet i;\n\n\t\t\tdo {\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tconst newType  = match[2] ? 'ol' : 'ul';\n\t\t\t\t\tconst newLevel = match[0].length;\n\n\t\t\t\t\tw.nextMatch += match[0].length;\n\n\t\t\t\t\tif (newLevel > curLevel) {\n\t\t\t\t\t\tfor (i = curLevel; i < newLevel; ++i) {\n\t\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\t\tjQuery(document.createElement(newType))\n\t\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (newLevel < curLevel) {\n\t\t\t\t\t\tfor (i = curLevel; i > newLevel; --i) {\n\t\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (newLevel === curLevel && newType !== curType) {\n\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\tjQuery(document.createElement(newType))\n\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tcurLevel = newLevel;\n\t\t\t\t\tcurType = newType;\n\t\t\t\t\tw.subWikify(\n\t\t\t\t\t\tjQuery(document.createElement('li'))\n\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t.get(0),\n\t\t\t\t\t\tthis.terminator\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'commentByBlock',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '(?:/(?:%|\\\\*))|(?:<!--)',\n\t\tlookahead : /(?:\\/(%|\\*)(?:(?:.|\\n)*?)\\1\\/)|(?:<!--(?:(?:.|\\n)*?)-->)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'lineContinuation',\n\t\tprofiles : ['core'],\n\n\t\t// WARNING: The ordering here is important: end-of-line, start-of-line, end-of-string, start-of-string.\n\t\tmatch : `\\\\\\\\${Patterns.spaceNoTerminator}*\\\\n|\\\\n${Patterns.spaceNoTerminator}*\\\\\\\\|\\\\n?\\\\\\\\${Patterns.spaceNoTerminator}*$|^${Patterns.spaceNoTerminator}*\\\\\\\\\\\\n?`,\n\n\t\thandler(w) {\n\t\t\tw.nextMatch = w.matchStart + w.matchLength;\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'lineBreak',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\n|<[Bb][Rr]\\\\s*/?>',\n\n\t\thandler(w) {\n\t\t\tif (!w.options.nobr) {\n\t\t\t\tjQuery(document.createElement('br')).appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'htmlCharacterReference',\n\t\tprofiles : ['core'],\n\t\tmatch    : '(?:(?:&#?[0-9A-Za-z]{2,8};|.)(?:&#?(?:x0*(?:3[0-6][0-9A-Fa-f]|1D[C-Fc-f][0-9A-Fa-f]|20[D-Fd-f][0-9A-Fa-f]|FE2[0-9A-Fa-f])|0*(?:76[89]|7[7-9][0-9]|8[0-7][0-9]|761[6-9]|76[2-7][0-9]|84[0-3][0-9]|844[0-7]|6505[6-9]|6506[0-9]|6507[0-1]));)+|&#?[0-9A-Za-z]{2,8};)',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t.append(w.matchText)\n\t\t\t\t.appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'xmlProlog',\n\t\tprofiles : ['core'],\n\t\tmatch    : '<\\\\?[Xx][Mm][Ll][^>]*\\\\?>',\n\n\t\thandler(w) {\n\t\t\tw.nextMatch = w.matchStart + w.matchLength;\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimHtml',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Hh][Tt][Mm][Ll]>',\n\t\tlookahead : /<[Hh][Tt][Mm][Ll]>((?:.|\\n)*?)<\\/[Hh][Tt][Mm][Ll]>/gm,\n\t\thandler   : _verbatimTagHandler\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimScriptTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Ss][Cc][Rr][Ii][Pp][Tt][^>]*>',\n\t\tlookahead : /(<[Ss][Cc][Rr][Ii][Pp][Tt]*>(?:.|\\n)*?<\\/[Ss][Cc][Rr][Ii][Pp][Tt]>)/gm,\n\t\thandler   : _verbatimTagHandler\n\t});\n\n\tWikifier.Parser.add({\n\t\tname           : 'styleTag',\n\t\tprofiles       : ['core'],\n\t\tmatch          : '<[Ss][Tt][Yy][Ll][Ee][^>]*>',\n\t\tlookahead      : /(<[Ss][Tt][Yy][Ll][Ee]*>)((?:.|\\n)*?)(<\\/[Ss][Tt][Yy][Ll][Ee]>)/gm,\n\t\timageMarkup    : new RegExp(Patterns.cssImage, 'g'),\n\t\thasImageMarkup : new RegExp(Patterns.cssImage),\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tlet css = match[2];\n\n\t\t\t\t// Check for wiki image transclusion.\n\t\t\t\tif (this.hasImageMarkup.test(css)) {\n\t\t\t\t\tthis.imageMarkup.lastIndex = 0;\n\n\t\t\t\t\tcss = css.replace(this.imageMarkup, wikiImage => {\n\t\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\t\tsource     : wikiImage,\n\t\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (markup.hasOwnProperty('error') || markup.pos < wikiImage.length) {\n\t\t\t\t\t\t\treturn wikiImage;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet source = markup.source;\n\n\t\t\t\t\t\t// Handle image passage transclusion.\n\t\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t\tsource = passage.text;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tThe source may be URI- or Base64-encoded, so we cannot use `encodeURIComponent()`\n\t\t\t\t\t\t\there.  Instead, we simply encode any double quotes, since the URI will be\n\t\t\t\t\t\t\tdelimited by them.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\treturn `url(\"${source.replace(/\"/g, '%22')}\")`;\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t\t.append(match[1] + css + match[3])\n\t\t\t\t\t.appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'svgTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Ss][Vv][Gg][^>]*>',\n\t\tlookahead : /(<[Ss][Vv][Gg][^>]*>(?:.|\\n)*?<\\/[Ss][Vv][Gg]>)/gm,\n\t\tnamespace : 'http://www.w3.org/2000/svg',\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tconst $frag = jQuery(document.createDocumentFragment()).append(match[1]);\n\n\t\t\t\t// Postprocess the relevant SVG element nodes.\n\t\t\t\t$frag.find('a[data-passage],image[data-passage]').each((_, el) => {\n\t\t\t\t\tconst tagName = el.tagName.toLowerCase();\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.processAttributeDirectives(el);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`svg|<${tagName}>: ${ex.message}`,\n\t\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (el.hasAttribute('data-passage')) {\n\t\t\t\t\t\tthis.processDataAttributes(el, tagName);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\t$frag.appendTo(w.output);\n\t\t\t}\n\t\t},\n\n\t\tprocessAttributeDirectives(el) {\n\t\t\t// NOTE: The `.attributes` property yields a live collection, so we\n\t\t\t// must make a non-live copy of it as we will be adding and removing\n\t\t\t// members of said collection if any directives are found.\n\t\t\t[...el.attributes].forEach(({ name, value }) => {\n\t\t\t\tconst evalShorthand = name[0] === '@';\n\n\t\t\t\tif (evalShorthand || name.startsWith('sc-eval:')) {\n\t\t\t\t\tconst newName = name.slice(evalShorthand ? 1 : 8); // Remove eval directive prefix.\n\n\t\t\t\t\tif (newName === 'data-setter') {\n\t\t\t\t\t\tthrow new Error(`evaluation directive is not allowed on the data-setter attribute: \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\t// Evaluate the value as TwineScript.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = Scripting.evalTwineScript(value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`bad evaluation from attribute directive \"${name}\": ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Assign the result to the new attribute and remove the old one.\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: Most browsers (ca. Nov 2017) have broken `setAttribute()`\n\t\t\t\t\t\t\tmethod implementations that throw on attribute names that start\n\t\t\t\t\t\t\twith, or contain, various symbols that are completely valid per\n\t\t\t\t\t\t\tthe specification.  Thus this code could fail if the user chooses\n\t\t\t\t\t\t\tattribute names that, after removing the directive prefix, are\n\t\t\t\t\t\t\tunpalatable to `setAttribute()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tel.setAttribute(newName, result);\n\t\t\t\t\t\tel.removeAttribute(name);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`cannot transform attribute directive \"${name}\" into attribute \"${newName}\"`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tprocessDataAttributes(el, tagName) {\n\t\t\tlet passage = el.getAttribute('data-passage');\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst evaluated = Wikifier.helpers.evalPassageId(passage);\n\n\t\t\tif (evaluated !== passage) {\n\t\t\t\tpassage = evaluated;\n\t\t\t\tel.setAttribute('data-passage', evaluated);\n\t\t\t}\n\n\t\t\tif (passage !== '') {\n\t\t\t\t// '<image>' element, so attempt media passage transclusion.\n\t\t\t\tif (tagName === 'image') {\n\t\t\t\t\tif (passage.slice(0, 5) !== 'data:' && Story.has(passage)) {\n\t\t\t\t\t\tpassage = Story.get(passage);\n\n\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t// NOTE: SVG `.href` IDL attribute is read-only,\n\t\t\t\t\t\t\t// so set its `href` content attribute instead.\n\t\t\t\t\t\t\tel.setAttribute('href', passage.text.trim());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Elsewise, assume a link element of some type—e.g., '<a>'.\n\t\t\t\telse {\n\t\t\t\t\tlet setter = el.getAttribute('data-setter');\n\t\t\t\t\tlet setFn;\n\n\t\t\t\t\tif (setter != null) { // lazy equality for null\n\t\t\t\t\t\tsetter = String(setter).trim();\n\n\t\t\t\t\t\tif (setter !== '') {\n\t\t\t\t\t\t\tsetFn = Wikifier.helpers.createShadowSetterCallback(Scripting.parse(setter));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tel.classList.add('link-internal');\n\n\t\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t\tel.classList.add('link-visited');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tel.classList.add('link-broken');\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery(el).ariaClick({ one : true }, function () {\n\t\t\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\t\t\tsetFn.call(this);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\t/*\n\t\t\tNOTE: This parser MUST come after any parser which handles HTML tag-\n\t\t\tlike constructs—e.g. 'verbatimText', 'horizontalRule', 'lineBreak',\n\t\t\t'xmlProlog', 'verbatimHtml', 'verbatimSvgTag', 'verbatimScriptTag',\n\t\t\tand 'styleTag'.\n\t\t*/\n\t\tname      : 'htmlTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<\\\\w+(?:\\\\s+[^\\\\u0000-\\\\u001F\\\\u007F-\\\\u009F\\\\s\"\\'>\\\\/=]+(?:\\\\s*=\\\\s*(?:\"[^\"]*?\"|\\'[^\\']*?\\'|[^\\\\s\"\\'=<>`]+))?)*\\\\s*\\\\/?>',\n\t\ttagRe     : /^<(\\w+)/,\n\t\tmediaTags : ['audio', 'img', 'source', 'track', 'video'], // NOTE: The `<picture>` element should not be in this list.\n\t\tnobrTags  : ['audio', 'colgroup', 'datalist', 'dl', 'figure', 'meter', 'ol', 'optgroup', 'picture', 'progress', 'ruby', 'select', 'table', 'tbody', 'tfoot', 'thead', 'tr', 'ul', 'video'],\n\t\tvoidTags  : ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'],\n\n\t\thandler(w) {\n\t\t\tconst tagMatch = this.tagRe.exec(w.matchText);\n\t\t\tconst tag      = tagMatch && tagMatch[1];\n\t\t\tconst tagName  = tag && tag.toLowerCase();\n\n\t\t\tif (tagName) {\n\t\t\t\tconst isVoid = this.voidTags.includes(tagName) || w.matchText.endsWith('/>');\n\t\t\t\tconst isNobr = this.nobrTags.includes(tagName);\n\t\t\t\tlet terminator;\n\t\t\t\tlet terminatorMatch;\n\n\t\t\t\tif (!isVoid) {\n\t\t\t\t\tterminator = `<\\\\/${tagName}\\\\s*>`;\n\n\t\t\t\t\tconst terminatorRe = new RegExp(terminator, 'gim'); // ignore case during match\n\n\t\t\t\t\tterminatorRe.lastIndex = w.matchStart;\n\t\t\t\t\tterminatorMatch = terminatorRe.exec(w.source);\n\t\t\t\t}\n\n\t\t\t\tif (isVoid || terminatorMatch) {\n\t\t\t\t\tlet output    = w.output;\n\t\t\t\t\tlet el        = document.createElement(w.output.tagName);\n\t\t\t\t\tlet debugView;\n\n\t\t\t\t\tel.innerHTML = w.matchText;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tNOTE: The use of a `while` statement here is curious, however,\n\t\t\t\t\t\tI'm hesitant to change it for fear of breaking some edge case.\n\t\t\t\t\t*/\n\t\t\t\t\twhile (el.firstChild) {\n\t\t\t\t\t\tel = el.firstChild;\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.processAttributeDirectives(el);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`<${tagName}>: ${ex.message}`,\n\t\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (el.hasAttribute('data-passage')) {\n\t\t\t\t\t\tthis.processDataAttributes(el, tagName);\n\n\t\t\t\t\t\t// Debug view setup.\n\t\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t`html-${tagName}`,\n\t\t\t\t\t\t\t\ttagName,\n\t\t\t\t\t\t\t\tw.matchText\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tdebugView.modes({\n\t\t\t\t\t\t\t\tblock   : tagName === 'img',\n\t\t\t\t\t\t\t\tnonvoid : terminatorMatch\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\toutput = debugView.output;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (terminatorMatch) {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists\n\t\t\t\t\t\t\tsolely to ensure that the options stack is properly restored in\n\t\t\t\t\t\t\tthe event that an uncaught exception is thrown during the call to\n\t\t\t\t\t\t\t`subWikify()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tWikifier.Option.push({ nobr : isNobr });\n\t\t\t\t\t\t\tw.subWikify(el, terminator, { ignoreTerminatorCase : true });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\tWikifier.Option.pop();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tDebug view modification.  If the current element has any debug\n\t\t\t\t\t\t\tview descendants who have \"block\" mode set, then set its debug\n\t\t\t\t\t\t\tview to the same.  It just makes things look a bit nicer.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tif (debugView && jQuery(el).find('.debug.block').length > 0) {\n\t\t\t\t\t\t\tdebugView.modes({ block : true });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tNOTE: The use of `cloneNode(true)` here for `<track>` elements\n\t\t\t\t\t\tis necessary to workaround a poorly understood rehoming issue.\n\t\t\t\t\t*/\n\t\t\t\t\toutput.appendChild(tagName === 'track' ? el.cloneNode(true) : el);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot find a closing tag for HTML <${tag}>`,\n\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tprocessAttributeDirectives(el) {\n\t\t\t// NOTE: The `.attributes` property yields a live collection, so we\n\t\t\t// must make a non-live copy of it as we will be adding and removing\n\t\t\t// members of said collection if any directives are found.\n\t\t\t[...el.attributes].forEach(({ name, value }) => {\n\t\t\t\tconst evalShorthand = name[0] === '@';\n\n\t\t\t\tif (evalShorthand || name.startsWith('sc-eval:')) {\n\t\t\t\t\tconst newName = name.slice(evalShorthand ? 1 : 8); // Remove eval directive prefix.\n\n\t\t\t\t\tif (newName === 'data-setter') {\n\t\t\t\t\t\tthrow new Error(`evaluation directive is not allowed on the data-setter attribute: \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\t// Evaluate the value as TwineScript.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = Scripting.evalTwineScript(value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`bad evaluation from attribute directive \"${name}\": ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Assign the result to the new attribute and remove the old one.\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: Most browsers (ca. Nov 2017) have broken `setAttribute()`\n\t\t\t\t\t\t\tmethod implementations that throw on attribute names that start\n\t\t\t\t\t\t\twith, or contain, various symbols that are completely valid per\n\t\t\t\t\t\t\tthe specification.  Thus this code could fail if the user chooses\n\t\t\t\t\t\t\tattribute names that, after removing the directive prefix, are\n\t\t\t\t\t\t\tunpalatable to `setAttribute()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tel.setAttribute(newName, result);\n\t\t\t\t\t\tel.removeAttribute(name);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`cannot transform attribute directive \"${name}\" into attribute \"${newName}\"`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tprocessDataAttributes(el, tagName) {\n\t\t\tlet passage = el.getAttribute('data-passage');\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst evaluated = Wikifier.helpers.evalPassageId(passage);\n\n\t\t\tif (evaluated !== passage) {\n\t\t\t\tpassage = evaluated;\n\t\t\t\tel.setAttribute('data-passage', evaluated);\n\t\t\t}\n\n\t\t\tif (passage !== '') {\n\t\t\t\t// Media element, so attempt media passage transclusion.\n\t\t\t\tif (this.mediaTags.includes(tagName)) {\n\t\t\t\t\tif (passage.slice(0, 5) !== 'data:' && Story.has(passage)) {\n\t\t\t\t\t\tpassage = Story.get(passage);\n\n\t\t\t\t\t\tlet parentName;\n\t\t\t\t\t\tlet twineTag;\n\n\t\t\t\t\t\tswitch (tagName) {\n\t\t\t\t\t\tcase 'audio':\n\t\t\t\t\t\tcase 'video':\n\t\t\t\t\t\t\ttwineTag = `Twine.${tagName}`;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'img':\n\t\t\t\t\t\t\ttwineTag = 'Twine.image';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'track':\n\t\t\t\t\t\t\ttwineTag = 'Twine.vtt';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'source':\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst $parent = $(el).closest('audio,picture,video');\n\n\t\t\t\t\t\t\t\tif ($parent.length) {\n\t\t\t\t\t\t\t\t\tparentName = $parent.get(0).tagName.toLowerCase();\n\t\t\t\t\t\t\t\t\ttwineTag = `Twine.${parentName === 'picture' ? 'image' : parentName}`;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (passage.tags.includes(twineTag)) {\n\t\t\t\t\t\t\tel[parentName === 'picture' ? 'srcset' : 'src'] = passage.text.trim();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Elsewise, assume a link element of some type—e.g., '<a>', '<area>', '<button>', etc.\n\t\t\t\telse {\n\t\t\t\t\tlet setter = el.getAttribute('data-setter');\n\t\t\t\t\tlet setFn;\n\n\t\t\t\t\tif (setter != null) { // lazy equality for null\n\t\t\t\t\t\tsetter = String(setter).trim();\n\n\t\t\t\t\t\tif (setter !== '') {\n\t\t\t\t\t\t\tsetFn = Wikifier.helpers.createShadowSetterCallback(Scripting.parse(setter));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tel.classList.add('link-internal');\n\n\t\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t\tel.classList.add('link-visited');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tel.classList.add('link-broken');\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery(el).ariaClick({ one : true }, function () {\n\t\t\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\t\t\tsetFn.call(this);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/template.js\n\n\tCopyright © 2019–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns */\n\nvar Template = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Template definitions.\n\tconst _templates = new Map();\n\n\t// Valid template name regular expression.\n\tconst _validNameRe = new RegExp(`^(?:${Patterns.templateName})$`);\n\n\t// Valid template type predicate.\n\tconst _validType = template => {\n\t\tconst templateType = typeof template;\n\t\treturn templateType === 'function' || templateType === 'string';\n\t};\n\n\n\t/*******************************************************************************\n\t\tTemplate Functions.\n\t*******************************************************************************/\n\n\tfunction templateAdd(name, template) {\n\t\tif (\n\t\t\t   !_validType(template)\n\t\t\t&& !(template instanceof Array && template.length > 0 && template.every(_validType))\n\t\t) {\n\t\t\tthrow new TypeError(`invalid template type (${name}); templates must be: functions, strings, or an array of either`);\n\t\t}\n\n\t\t(name instanceof Array ? name : [name]).forEach(name => {\n\t\t\tif (!_validNameRe.test(name)) {\n\t\t\t\tthrow new Error(`invalid template name \"${name}\"`);\n\t\t\t}\n\t\t\tif (_templates.has(name)) {\n\t\t\t\tthrow new Error(`cannot clobber existing template ?${name}`);\n\t\t\t}\n\n\t\t\t_templates.set(name, template);\n\t\t});\n\t}\n\n\tfunction templateDelete(name) {\n\t\t(name instanceof Array ? name : [name]).forEach(name => _templates.delete(name));\n\t}\n\n\tfunction templateGet(name) {\n\t\treturn _templates.has(name) ? _templates.get(name) : null;\n\t}\n\n\tfunction templateHas(name) {\n\t\treturn _templates.has(name);\n\t}\n\n\tfunction templateSize() {\n\t\treturn _templates.size;\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tadd    : { value : templateAdd },\n\t\tdelete : { value : templateDelete },\n\t\tget    : { value : templateGet },\n\t\thas    : { value : templateHas },\n\t\tsize   : { get : templateSize }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macro.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns, Scripting, clone, macros */\n\nvar Macro = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Macro definitions.\n\tconst _macros = {};\n\n\t// Map of all macro tags and their parents (key: 'tag name' => value: ['list of parent names']).\n\tconst _tags = {};\n\n\t// Valid macro name regular expression.\n\tconst _validNameRe = new RegExp(`^(?:${Patterns.macroName})$`);\n\n\n\t/*******************************************************************************************************************\n\t\tMacros Functions.\n\t*******************************************************************************************************************/\n\tfunction macrosAdd(name, def, deep) {\n\t\tif (Array.isArray(name)) {\n\t\t\tname.forEach(name => macrosAdd(name, def, deep));\n\t\t\treturn;\n\t\t}\n\n\t\tif (!_validNameRe.test(name)) {\n\t\t\tthrow new Error(`invalid macro name \"${name}\"`);\n\t\t}\n\n\t\tif (macrosHas(name)) {\n\t\t\tthrow new Error(`cannot clobber existing macro <<${name}>>`);\n\t\t}\n\t\telse if (tagsHas(name)) {\n\t\t\tthrow new Error(`cannot clobber child tag <<${name}>> of parent macro${_tags[name].length === 1 ? '' : 's'} <<${_tags[name].join('>>, <<')}>>`);\n\t\t}\n\n\t\ttry {\n\t\t\tif (typeof def === 'object') {\n\t\t\t\t// Add the macro definition.\n\t\t\t\t_macros[name] = deep ? clone(def) : def;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Add the macro alias.\n\t\t\t\tif (macrosHas(def)) {\n\t\t\t\t\t_macros[name] = deep ? clone(_macros[def]) : _macros[def];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new Error(`cannot create alias of nonexistent macro <<${def}>>`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tObject.defineProperty(_macros, name, { writable : false });\n\n\t\t\t/* legacy */\n\t\t\t/*\n\t\t\t\tSince `macrosGet()` may return legacy macros, we have to add a flag to (modern)\n\t\t\t\tAPI macros, so that the macro formatter will know how to call the macro.\n\t\t\t*/\n\t\t\t_macros[name]._MACRO_API = true;\n\t\t\t/* /legacy */\n\t\t}\n\t\tcatch (ex) {\n\t\t\tif (ex.name === 'TypeError') {\n\t\t\t\tthrow new Error(`cannot clobber protected macro <<${name}>>`);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error(`unknown error when attempting to add macro <<${name}>>: [${ex.name}] ${ex.message}`);\n\t\t\t}\n\t\t}\n\n\t\t// Tags post-processing.\n\t\tif (_macros[name].hasOwnProperty('tags')) {\n\t\t\tif (_macros[name].tags == null) { // lazy equality for null\n\t\t\t\ttagsRegister(name);\n\t\t\t}\n\t\t\telse if (Array.isArray(_macros[name].tags)) {\n\t\t\t\ttagsRegister(name, _macros[name].tags);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error(`bad value for \"tags\" property of macro <<${name}>>`);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction macrosDelete(name) {\n\t\tif (Array.isArray(name)) {\n\t\t\tname.forEach(name => macrosDelete(name));\n\t\t\treturn;\n\t\t}\n\n\t\tif (macrosHas(name)) {\n\t\t\t// Tags pre-processing.\n\t\t\tif (_macros[name].hasOwnProperty('tags')) {\n\t\t\t\ttagsUnregister(name);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t// Remove the macro definition.\n\t\t\t\tObject.defineProperty(_macros, name, { writable : true });\n\t\t\t\tdelete _macros[name];\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tthrow new Error(`unknown error removing macro <<${name}>>: ${ex.message}`);\n\t\t\t}\n\t\t}\n\t\telse if (tagsHas(name)) {\n\t\t\tthrow new Error(`cannot remove child tag <<${name}>> of parent macro <<${_tags[name]}>>`);\n\t\t}\n\t}\n\n\tfunction macrosIsEmpty() {\n\t\treturn Object.keys(_macros).length === 0;\n\t}\n\n\tfunction macrosHas(name) {\n\t\treturn _macros.hasOwnProperty(name);\n\t}\n\n\tfunction macrosGet(name) {\n\t\tlet macro = null;\n\n\t\tif (macrosHas(name) && typeof _macros[name].handler === 'function') {\n\t\t\tmacro = _macros[name];\n\t\t}\n\t\t/* legacy macro support */\n\t\telse if (macros.hasOwnProperty(name) && typeof macros[name].handler === 'function') {\n\t\t\tmacro = macros[name];\n\t\t}\n\t\t/* /legacy macro support */\n\n\t\treturn macro;\n\t}\n\n\tfunction macrosInit(handler = 'init') { // eslint-disable-line no-unused-vars\n\t\tObject.keys(_macros).forEach(name => {\n\t\t\tif (typeof _macros[name][handler] === 'function') {\n\t\t\t\t_macros[name][handler](name);\n\t\t\t}\n\t\t});\n\n\t\t/* legacy macro support */\n\t\tObject.keys(macros).forEach(name => {\n\t\t\tif (typeof macros[name][handler] === 'function') {\n\t\t\t\tmacros[name][handler](name);\n\t\t\t}\n\t\t});\n\t\t/* /legacy macro support */\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTags Functions.\n\t*******************************************************************************************************************/\n\tfunction tagsRegister(parent, bodyTags) {\n\t\tif (!parent) {\n\t\t\tthrow new Error('no parent specified');\n\t\t}\n\n\t\tconst endTags = [`/${parent}`, `end${parent}`]; // automatically create the closing tags\n\t\tconst allTags = [].concat(endTags, Array.isArray(bodyTags) ? bodyTags : []);\n\n\t\tfor (let i = 0; i < allTags.length; ++i) {\n\t\t\tconst tag = allTags[i];\n\n\t\t\tif (macrosHas(tag)) {\n\t\t\t\tthrow new Error('cannot register tag for an existing macro');\n\t\t\t}\n\n\t\t\tif (tagsHas(tag)) {\n\t\t\t\tif (!_tags[tag].includes(parent)) {\n\t\t\t\t\t_tags[tag].push(parent);\n\t\t\t\t\t_tags[tag].sort();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_tags[tag] = [parent];\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction tagsUnregister(parent) {\n\t\tif (!parent) {\n\t\t\tthrow new Error('no parent specified');\n\t\t}\n\n\t\tObject.keys(_tags).forEach(tag => {\n\t\t\tconst i = _tags[tag].indexOf(parent);\n\n\t\t\tif (i !== -1) {\n\t\t\t\tif (_tags[tag].length === 1) {\n\t\t\t\t\tdelete _tags[tag];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_tags[tag].splice(i, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction tagsHas(name) {\n\t\treturn _tags.hasOwnProperty(name);\n\t}\n\n\tfunction tagsGet(name) {\n\t\treturn tagsHas(name) ? _tags[name] : null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tMacro Functions.\n\t\t*/\n\t\tadd     : { value : macrosAdd },\n\t\tdelete  : { value : macrosDelete },\n\t\tisEmpty : { value : macrosIsEmpty },\n\t\thas     : { value : macrosHas },\n\t\tget     : { value : macrosGet },\n\t\tinit    : { value : macrosInit },\n\n\t\t/*\n\t\t\tTags Functions.\n\t\t*/\n\t\ttags : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tregister   : { value : tagsRegister },\n\t\t\t\tunregister : { value : tagsUnregister },\n\t\t\t\thas        : { value : tagsHas },\n\t\t\t\tget        : { value : tagsGet }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tevalStatements : { value : (...args) => Scripting.evalJavaScript(...args) } // SEE: `markup/scripting.js`.\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macrocontext.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, DebugView, Patterns, State, Wikifier, throwError */\n\nvar MacroContext = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tMacroContext Class.\n\t*******************************************************************************************************************/\n\tclass MacroContext {\n\t\tconstructor(contextData) {\n\t\t\tconst context = Object.assign({\n\t\t\t\tparent  : null,\n\t\t\t\tmacro   : null,\n\t\t\t\tname    : '',\n\t\t\t\targs    : null,\n\t\t\t\tpayload : null,\n\t\t\t\tparser  : null,\n\t\t\t\tsource  : ''\n\t\t\t}, contextData);\n\n\t\t\tif (context.macro === null || context.name === '' || context.parser === null) {\n\t\t\t\tthrow new TypeError('context object missing required properties');\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tself : {\n\t\t\t\t\tvalue : context.macro\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : context.name\n\t\t\t\t},\n\n\t\t\t\targs : {\n\t\t\t\t\tvalue : context.args\n\t\t\t\t},\n\n\t\t\t\tpayload : {\n\t\t\t\t\tvalue : context.payload\n\t\t\t\t},\n\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : context.source\n\t\t\t\t},\n\n\t\t\t\tparent : {\n\t\t\t\t\tvalue : context.parent\n\t\t\t\t},\n\n\t\t\t\tparser : {\n\t\t\t\t\tvalue : context.parser\n\t\t\t\t},\n\n\t\t\t\t_output : {\n\t\t\t\t\tvalue : context.parser.output\n\t\t\t\t},\n\n\t\t\t\t_shadows : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_debugView : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_debugViewEnabled : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : Config.debug\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tget output() {\n\t\t\treturn this._debugViewEnabled ? this.debugView.output : this._output;\n\t\t}\n\n\t\tget shadows() {\n\t\t\treturn [...this._shadows];\n\t\t}\n\n\t\tget shadowView() {\n\t\t\tconst view = new Set();\n\t\t\tthis.contextSelectAll(ctx => ctx._shadows)\n\t\t\t\t.forEach(ctx => ctx._shadows.forEach(name => view.add(name)));\n\t\t\treturn [...view];\n\t\t}\n\n\t\tget debugView() {\n\t\t\tif (this._debugViewEnabled) {\n\t\t\t\treturn this._debugView !== null ? this._debugView : this.createDebugView();\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tcontextHas(filter) {\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tcontextSelect(filter) {\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\treturn context;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tcontextSelectAll(filter) {\n\t\t\tconst result = [];\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\tresult.push(context);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\taddShadow(...names) {\n\t\t\tif (!this._shadows) {\n\t\t\t\tthis._shadows = new Set();\n\t\t\t}\n\n\t\t\tconst varRe = new RegExp(`^${Patterns.variable}$`);\n\n\t\t\tnames\n\t\t\t\t.flat(Infinity)\n\t\t\t\t.forEach(name => {\n\t\t\t\t\tif (typeof name !== 'string') {\n\t\t\t\t\t\tthrow new TypeError(`variable name must be a string; type: ${typeof name}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!varRe.test(name)) {\n\t\t\t\t\t\tthrow new Error(`invalid variable name \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._shadows.add(name);\n\t\t\t\t});\n\t\t}\n\n\t\tcreateShadowWrapper(callback, doneCallback, startCallback) {\n\t\t\tconst shadowContext = this;\n\t\t\tlet shadowStore;\n\n\t\t\tif (typeof callback === 'function') {\n\t\t\t\tshadowStore = {};\n\t\t\t\tthis.shadowView.forEach(varName => {\n\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\t\t\tshadowStore[varName] = store[varKey];\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn function (...args) {\n\t\t\t\tif (typeof startCallback === 'function') {\n\t\t\t\t\tstartCallback.apply(this, args);\n\t\t\t\t}\n\n\t\t\t\tif (typeof callback === 'function') {\n\t\t\t\t\tconst shadowNames = Object.keys(shadowStore);\n\t\t\t\t\tconst valueCache  = shadowNames.length > 0 ? {} : null;\n\t\t\t\t\tconst macroParser = Wikifier.Parser.get('macro');\n\t\t\t\t\tlet contextCache;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t\tcallback.\n\t\t\t\t\t*/\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tCache the existing values of the variables to be shadowed and assign the\n\t\t\t\t\t\t\tshadow values.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tstore[varKey] = shadowStore[varName];\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Cache the existing macro execution context and assign the shadow context.\n\t\t\t\t\t\tcontextCache = macroParser.context;\n\t\t\t\t\t\tmacroParser.context = shadowContext;\n\n\t\t\t\t\t\t// Call the callback function.\n\t\t\t\t\t\tcallback.apply(this, args);\n\t\t\t\t\t}\n\t\t\t\t\tfinally {\n\t\t\t\t\t\t// Revert the macro execution context shadowing.\n\t\t\t\t\t\tif (contextCache !== undefined) {\n\t\t\t\t\t\t\tmacroParser.context = contextCache;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Revert the variable shadowing.\n\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tUpdate the shadow store with the variable's current value, in case it\n\t\t\t\t\t\t\t\twas modified during the callback.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\n\t\t\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (typeof doneCallback === 'function') {\n\t\t\t\t\tdoneCallback.apply(this, args);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tcreateDebugView(name, title) {\n\t\t\tthis._debugView = new DebugView(\n\t\t\t\tthis._output,\n\t\t\t\t'macro',\n\t\t\t\tname ? name : this.name,\n\t\t\t\ttitle ? title : this.source\n\t\t\t);\n\n\t\t\tif (this.payload !== null && this.payload.length > 0) {\n\t\t\t\tthis._debugView.modes({ nonvoid : true });\n\t\t\t}\n\n\t\t\tthis._debugViewEnabled = true;\n\t\t\treturn this._debugView;\n\t\t}\n\n\t\tremoveDebugView() {\n\t\t\tif (this._debugView !== null) {\n\t\t\t\tthis._debugView.remove();\n\t\t\t\tthis._debugView = null;\n\t\t\t}\n\n\t\t\tthis._debugViewEnabled = false;\n\t\t}\n\n\t\terror(message, source, stack) {\n\t\t\treturn throwError(this._output, `<<${this.name}>>: ${message}`, source ? source : this.source, stack);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn MacroContext;\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macrolib.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, DebugView, Engine, Has, L10n, Macro, Patterns, Scripting, SimpleAudio, State, Story,\n\t       TempState, Util, Wikifier, postdisplay, prehistory, storage, toStringOrDefault\n*/\n\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tVariables Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<capture>>\n\t*/\n\tMacro.add('capture', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tif (this.args.raw.length === 0) {\n\t\t\t\treturn this.error('no story/temporary variable list specified');\n\t\t\t}\n\n\t\t\tconst valueCache = {};\n\n\t\t\t/*\n\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t`Wikifier` call.\n\t\t\t*/\n\t\t\ttry {\n\t\t\t\tconst varRe = new RegExp(`(${Patterns.variable})`,'g');\n\t\t\t\tlet match;\n\n\t\t\t\t/*\n\t\t\t\t\tCache the existing values of the variables and add a shadow.\n\t\t\t\t*/\n\t\t\t\twhile ((match = varRe.exec(this.args.raw)) !== null) {\n\t\t\t\t\tconst varName = match[1];\n\t\t\t\t\tconst varKey  = varName.slice(1);\n\t\t\t\t\tconst store   = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.addShadow(varName);\n\t\t\t\t}\n\n\t\t\t\tnew Wikifier(this.output, this.payload[0].contents);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\t// Revert the variable shadowing.\n\t\t\t\tthis.shadows.forEach(varName => {\n\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<set>>\n\t*/\n\tMacro.add('set', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<unset>>\n\t*/\n\tMacro.add('unset', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no story/temporary variable list specified');\n\t\t\t}\n\n\t\t\tconst re = new RegExp(\n\t\t\t\t`State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})`,\n\t\t\t\t'g'\n\t\t\t);\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst store = State[match[1]];\n\t\t\t\tconst name  = match[2];\n\n\t\t\t\tif (store.hasOwnProperty(name)) {\n\t\t\t\t\tdelete store[name];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<remember>>\n\t*/\n\tMacro.add('remember', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\tconst remember = storage.get('remember') || {};\n\t\t\tconst re       = new RegExp(`State\\\\.variables\\\\.(${Patterns.identifier})`, 'g');\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst name = match[1];\n\t\t\t\tremember[name] = State.variables[name];\n\t\t\t}\n\n\t\t\tif (!storage.set('remember', remember)) {\n\t\t\t\treturn this.error(`unknown error, cannot remember: ${this.args.raw}`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t},\n\n\t\tinit() {\n\t\t\tconst remember = storage.get('remember');\n\n\t\t\tif (remember) {\n\t\t\t\tObject.keys(remember).forEach(name => State.variables[name] = remember[name]);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<forget>>\n\t*/\n\tMacro.add('forget', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no story variable list specified');\n\t\t\t}\n\n\t\t\tconst remember = storage.get('remember');\n\t\t\tconst re       = new RegExp(`State\\\\.variables\\\\.(${Patterns.identifier})`, 'g');\n\t\t\tlet match;\n\t\t\tlet needStore = false;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst name = match[1];\n\n\t\t\t\tif (State.variables.hasOwnProperty(name)) {\n\t\t\t\t\tdelete State.variables[name];\n\t\t\t\t}\n\n\t\t\t\tif (remember && remember.hasOwnProperty(name)) {\n\t\t\t\t\tneedStore = true;\n\t\t\t\t\tdelete remember[name];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (needStore) {\n\t\t\t\tif (Object.keys(remember).length === 0) {\n\t\t\t\t\tif (!storage.delete('remember')) {\n\t\t\t\t\t\treturn this.error('unknown error, cannot update remember store');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (!storage.set('remember', remember)) {\n\t\t\t\t\treturn this.error('unknown error, cannot update remember store');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tScripting Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<run>>\n\t*/\n\tMacro.add('run', 'set'); // add <<run>> as an alias of <<set>>\n\n\t/*\n\t\t<<script>>\n\t*/\n\tMacro.add('script', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tconst output = document.createDocumentFragment();\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.payload[0].contents, output);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.createDebugView();\n\t\t\t}\n\n\t\t\tif (output.hasChildNodes()) {\n\t\t\t\tthis.output.appendChild(output);\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tDisplay Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<include>>\n\t*/\n\tMacro.add('include', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = this.args[0].link;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the passage name.\n\t\t\t\tpassage = this.args[0];\n\t\t\t}\n\n\t\t\tif (!Story.has(passage)) {\n\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tpassage = Story.get(passage);\n\t\t\tlet $el;\n\n\t\t\tif (this.args[1]) {\n\t\t\t\t$el = jQuery(document.createElement(this.args[1]))\n\t\t\t\t\t.addClass(`${passage.domId} macro-${this.name}`)\n\t\t\t\t\t.attr('data-passage', passage.title)\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$el = jQuery(this.output);\n\t\t\t}\n\n\t\t\t$el.wiki(passage.processText());\n\t\t}\n\t});\n\n\t/*\n\t\t<<nobr>>\n\t*/\n\tMacro.add('nobr', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\t/*\n\t\t\t\tWikify the contents, after removing all leading & trailing newlines and compacting\n\t\t\t\tall internal sequences of newlines into single spaces.\n\t\t\t*/\n\t\t\tnew Wikifier(this.output, this.payload[0].contents.replace(/^\\n+|\\n+$/g, '').replace(/\\n+/g, ' '));\n\t\t}\n\t});\n\n\t/*\n\t\t<<print>>, <<=>>, & <<->>\n\t*/\n\tMacro.add(['print', '=', '-'], {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = toStringOrDefault(Scripting.evalJavaScript(this.args.full), null);\n\n\t\t\t\tif (result !== null) {\n\t\t\t\t\tnew Wikifier(this.output, this.name === '-' ? Util.escape(result) : result);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<silently>>\n\t*/\n\tMacro.add('silently', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, this.payload[0].contents.trim());\n\n\t\t\tif (Config.debug) {\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tthis.debugView.modes({ block : true, hidden : true });\n\t\t\t\tthis.output.appendChild(frag);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Discard the output, unless there were errors.\n\t\t\t\tconst errList = [...frag.querySelectorAll('.error')].map(errEl => errEl.textContent);\n\n\t\t\t\tif (errList.length > 0) {\n\t\t\t\t\treturn this.error(`error${errList.length === 1 ? '' : 's'} within contents (${errList.join('; ')})`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] <<display>>\n\t*/\n\tMacro.add('display', 'include'); // add <<display>> as an alias of <<include>>\n\n\n\t/*******************************************************************************************************************\n\t\tControl Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<if>>, <<elseif>>, & <<else>>\n\t*/\n\tMacro.add('if', {\n\t\tskipArgs : true,\n\t\ttags     : ['elseif', 'else'],\n\n\t\thandler() {\n\t\t\tlet i;\n\n\t\t\ttry {\n\t\t\t\tconst len = this.payload.length;\n\n\t\t\t\t// Sanity checks.\n\t\t\t\tfor (/* declared previously */ i = 0; i < len; ++i) {\n\t\t\t\t\t/* eslint-disable prefer-template */\n\t\t\t\t\tswitch (this.payload[i].name) {\n\t\t\t\t\tcase 'else':\n\t\t\t\t\t\tif (this.payload[i].args.raw.length > 0) {\n\t\t\t\t\t\t\tif (/^\\s*if\\b/i.test(this.payload[i].args.raw)) {\n\t\t\t\t\t\t\t\treturn this.error(`whitespace is not allowed between the \"else\" and \"if\" in <<elseif>> clause${i > 0 ? ' (#' + i + ')' : ''}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn this.error(`<<else>> does not accept a conditional expression (perhaps you meant to use <<elseif>>), invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (i + 1 !== len) {\n\t\t\t\t\t\t\treturn this.error('<<else>> must be the final clause');\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif (this.payload[i].args.full.length === 0) {\n\t\t\t\t\t\t\treturn this.error(`no conditional expression specified for <<${this.payload[i].name}>> clause${i > 0 ? ' (#' + i + ')' : ''}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (\n\t\t\t\t\t\t\t   Config.macros.ifAssignmentError\n\t\t\t\t\t\t\t&& /[^!=&^|<>*/%+-]=[^=>]/.test(this.payload[i].args.full)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn this.error(`assignment operator found within <<${this.payload[i].name}>> clause${i > 0 ? ' (#' + i + ')' : ''} (perhaps you meant to use an equality operator: ==, ===, eq, is), invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable prefer-template */\n\t\t\t\t}\n\n\t\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\t\tlet success = false;\n\n\t\t\t\t// Evaluate the clauses.\n\t\t\t\tfor (/* declared previously */ i = 0; i < len; ++i) {\n\t\t\t\t\t// Custom debug view setup for the current clause.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({ nonvoid : false });\n\t\t\t\t\t}\n\n\t\t\t\t\t// Conditional test.\n\t\t\t\t\tif (this.payload[i].name === 'else' || !!evalJavaScript(this.payload[i].args.full)) {\n\t\t\t\t\t\tsuccess = true;\n\t\t\t\t\t\tnew Wikifier(this.output, this.payload[i].contents);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse if (Config.debug) {\n\t\t\t\t\t\t// Custom debug view setup for a failed conditional.\n\t\t\t\t\t\tthis.debugView.modes({\n\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup for the remaining clauses.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tfor (++i; i < len; ++i) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tFake a debug view for `<</if>>`.  We do this to aid the checking of nesting\n\t\t\t\t\t\tand as a quick indicator of if any of the clauses matched.\n\t\t\t\t\t*/\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : !success,\n\t\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad conditional expression in <<${i === 0 ? 'if' : 'elseif'}>> clause${i > 0 ? ' (#' + i + ')' : ''}: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack); // eslint-disable-line prefer-template\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<switch>>, <<case>>, & <<default>>\n\t*/\n\tMacro.add('switch', {\n\t\tskipArgs : ['switch'],\n\t\ttags     : ['case', 'default'],\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\tconst len = this.payload.length;\n\n\t\t\t// if (len === 1 || !this.payload.some(p => p.name === 'case')) {\n\t\t\tif (len === 1) {\n\t\t\t\treturn this.error('no cases specified');\n\t\t\t}\n\n\t\t\tlet i;\n\n\t\t\t// Sanity checks.\n\t\t\tfor (/* declared previously */ i = 1; i < len; ++i) {\n\t\t\t\tswitch (this.payload[i].name) {\n\t\t\t\tcase 'default':\n\t\t\t\t\tif (this.payload[i].args.length > 0) {\n\t\t\t\t\t\treturn this.error(`<<default>> does not accept values, invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (i + 1 !== len) {\n\t\t\t\t\t\treturn this.error('<<default>> must be the final case');\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tif (this.payload[i].args.length === 0) {\n\t\t\t\t\t\treturn this.error(`no value(s) specified for <<${this.payload[i].name}>> (#${i})`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet result;\n\n\t\t\ttry {\n\t\t\t\tresult = Scripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\tconst debugView = this.debugView; // cache it now, to be modified later\n\t\t\tlet success = false;\n\n\t\t\t// Initial debug view setup for `<<switch>>`.\n\t\t\tif (Config.debug) {\n\t\t\t\tdebugView\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true\n\t\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Evaluate the clauses.\n\t\t\tfor (/* declared previously */ i = 1; i < len; ++i) {\n\t\t\t\t// Custom debug view setup for the current case.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t.modes({ nonvoid : false });\n\t\t\t\t}\n\n\t\t\t\t// Case test(s).\n\t\t\t\tif (this.payload[i].name === 'default' || this.payload[i].args.some(val => val === result)) {\n\t\t\t\t\tsuccess = true;\n\t\t\t\t\tnew Wikifier(this.output, this.payload[i].contents);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (Config.debug) {\n\t\t\t\t\t// Custom debug view setup for a failed case.\n\t\t\t\t\tthis.debugView.modes({\n\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup for the remaining cases.\n\t\t\tif (Config.debug) {\n\t\t\t\tfor (++i; i < len; ++i) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t/*\n\t\t\t\t\tFinalize the debug view for `<<switch>>` and fake a debug view for `<</switch>>`.\n\t\t\t\t\tWe do both as a quick indicator of if any of the cases matched and the latter\n\t\t\t\t\tto aid the checking of nesting.\n\t\t\t\t*/\n\t\t\t\tdebugView\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true, // !success,\n\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t});\n\t\t\t\tthis\n\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true, // !success,\n\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<for>>, <<break>>, & <<continue>>\n\t*/\n\tMacro.add('for', {\n\t\t/* eslint-disable max-len */\n\t\tskipArgs    : true,\n\t\ttags        : null,\n\t\t_hasRangeRe : new RegExp(`^\\\\S${Patterns.anyChar}*?\\\\s+range\\\\s+\\\\S${Patterns.anyChar}*?$`),\n\t\t_rangeRe    : new RegExp(`^(?:State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})\\\\s*,\\\\s*)?State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})\\\\s+range\\\\s+(\\\\S${Patterns.anyChar}*?)$`),\n\t\t_3PartRe    : /^([^;]*?)\\s*;\\s*([^;]*?)\\s*;\\s*([^;]*?)$/,\n\t\t/* eslint-enable max-len */\n\n\t\thandler() {\n\t\t\tconst argsStr = this.args.full.trim();\n\t\t\tconst payload = this.payload[0].contents.replace(/\\n$/, '');\n\n\t\t\t// Empty form.\n\t\t\tif (argsStr.length === 0) {\n\t\t\t\tthis.self._handleFor.call(this, payload, null, true, null);\n\t\t\t}\n\n\t\t\t// Range form.\n\t\t\telse if (this.self._hasRangeRe.test(argsStr)) {\n\t\t\t\tconst parts = argsStr.match(this.self._rangeRe);\n\n\t\t\t\tif (parts === null) {\n\t\t\t\t\treturn this.error('invalid range form syntax, format: [index ,] value range collection');\n\t\t\t\t}\n\n\t\t\t\tthis.self._handleForRange.call(\n\t\t\t\t\tthis,\n\t\t\t\t\tpayload,\n\t\t\t\t\t{ type : parts[1], name : parts[2] },\n\t\t\t\t\t{ type : parts[3], name : parts[4] },\n\t\t\t\t\tparts[5]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Conditional forms.\n\t\t\telse {\n\t\t\t\tlet init;\n\t\t\t\tlet condition;\n\t\t\t\tlet post;\n\n\t\t\t\t// Conditional-only form.\n\t\t\t\tif (argsStr.indexOf(';') === -1) {\n\t\t\t\t\t// Sanity checks.\n\t\t\t\t\tif (/^\\S+\\s+in\\s+\\S+/i.test(argsStr)) {\n\t\t\t\t\t\treturn this.error('invalid syntax, for…in is not supported; see: for…range');\n\t\t\t\t\t}\n\t\t\t\t\telse if (/^\\S+\\s+of\\s+\\S+/i.test(argsStr)) {\n\t\t\t\t\t\treturn this.error('invalid syntax, for…of is not supported; see: for…range');\n\t\t\t\t\t}\n\n\t\t\t\t\tcondition = argsStr;\n\t\t\t\t}\n\n\t\t\t\t// 3-part conditional form.\n\t\t\t\telse {\n\t\t\t\t\tconst parts = argsStr.match(this.self._3PartRe);\n\n\t\t\t\t\tif (parts === null) {\n\t\t\t\t\t\treturn this.error('invalid 3-part conditional form syntax, format: [init] ; [condition] ; [post]');\n\t\t\t\t\t}\n\n\t\t\t\t\tinit      = parts[1];\n\t\t\t\t\tcondition = parts[2].trim();\n\t\t\t\t\tpost      = parts[3];\n\n\t\t\t\t\tif (condition.length === 0) {\n\t\t\t\t\t\tcondition = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis.self._handleFor.call(this, payload, init, condition, post);\n\t\t\t}\n\t\t},\n\n\t\t_handleFor(payload, init, condition, post) {\n\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\tlet first  = true;\n\t\t\tlet safety = Config.macros.maxLoopIterations;\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tTempState.break = null;\n\n\t\t\t\tif (init) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tevalJavaScript(init);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn this.error(`bad init expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\twhile (evalJavaScript(condition)) {\n\t\t\t\t\tif (--safety < 0) {\n\t\t\t\t\t\treturn this.error(`exceeded configured maximum loop iterations (${Config.macros.maxLoopIterations})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tnew Wikifier(this.output, first ? payload.replace(/^\\n/, '') : payload);\n\n\t\t\t\t\tif (first) {\n\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tif (TempState.break === 1) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (TempState.break === 2) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (post) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tevalJavaScript(post);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\treturn this.error(`bad post expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad conditional expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tTempState.break = null;\n\t\t\t}\n\t\t},\n\n\t\t_handleForRange(payload, indexVar, valueVar, rangeExp) {\n\t\t\tlet first     = true;\n\t\t\tlet rangeList;\n\n\t\t\ttry {\n\t\t\t\trangeList = this.self._toRangeList(rangeExp);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(ex.message);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tTempState.break = null;\n\n\t\t\t\tfor (let i = 0; i < rangeList.length; ++i) {\n\t\t\t\t\tif (indexVar.name) {\n\t\t\t\t\t\tState[indexVar.type][indexVar.name] = rangeList[i][0];\n\t\t\t\t\t}\n\n\t\t\t\t\tState[valueVar.type][valueVar.name] = rangeList[i][1];\n\n\t\t\t\t\tnew Wikifier(this.output, first ? payload.replace(/^\\n/, '') : payload);\n\n\t\t\t\t\tif (first) {\n\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tif (TempState.break === 1) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (TempState.break === 2) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tTempState.break = null;\n\t\t\t}\n\t\t},\n\n\t\t_toRangeList(rangeExp) {\n\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\tlet value;\n\n\t\t\ttry {\n\t\t\t\t/*\n\t\t\t\t\tNOTE: If the first character is the left curly brace, then we\n\t\t\t\t\tassume that it's part of an object literal and wrap it within\n\t\t\t\t\tparenthesis to ensure that it is not mistaken for a block\n\t\t\t\t\tduring evaluation—which would cause an error.\n\t\t\t\t*/\n\t\t\t\tvalue = evalJavaScript(rangeExp[0] === '{' ? `(${rangeExp})` : rangeExp);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tif (typeof ex !== 'object') {\n\t\t\t\t\tthrow new Error(`bad range expression: ${ex}`);\n\t\t\t\t}\n\n\t\t\t\tex.message = `bad range expression: ${ex.message}`;\n\t\t\t\tthrow ex;\n\t\t\t}\n\n\t\t\tlet list;\n\n\t\t\tswitch (typeof value) {\n\t\t\tcase 'string':\n\t\t\t\tlist = [];\n\t\t\t\tfor (let i = 0; i < value.length; /* empty */) {\n\t\t\t\t\tconst obj = Util.charAndPosAt(value, i);\n\t\t\t\t\tlist.push([i, obj.char]);\n\t\t\t\t\ti = 1 + obj.end;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'object':\n\t\t\t\tif (Array.isArray(value)) {\n\t\t\t\t\tlist = value.map((val, i) => [i, val]);\n\t\t\t\t}\n\t\t\t\telse if (value instanceof Set) {\n\t\t\t\t\tlist = [...value].map((val, i) => [i, val]);\n\t\t\t\t}\n\t\t\t\telse if (value instanceof Map) {\n\t\t\t\t\tlist = [...value.entries()];\n\t\t\t\t}\n\t\t\t\telse if (Util.toStringTag(value) === 'Object') {\n\t\t\t\t\tlist = Object.keys(value).map(key => [key, value[key]]);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new Error(`unsupported range expression type: ${Util.toStringTag(value)}`);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unsupported range expression type: ${typeof value}`);\n\t\t\t}\n\n\t\t\treturn list;\n\t\t}\n\t});\n\tMacro.add(['break', 'continue'], {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.contextHas(ctx => ctx.name === 'for')) {\n\t\t\t\tTempState.break = this.name === 'continue' ? 1 : 2;\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn this.error('must only be used in conjunction with its parent macro <<for>>');\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tInteractive Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<button>> & <<link>>\n\t*/\n\tMacro.add(['button', 'link'], {\n\t\tisAsync : true,\n\t\ttags    : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error(`no ${this.name === 'button' ? 'button' : 'link'} text specified`);\n\t\t\t}\n\n\t\t\tconst $link = jQuery(document.createElement(this.name === 'button' ? 'button' : 'a'));\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\tconst $image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t.attr('src', this.args[0].source)\n\t\t\t\t\t\t.appendTo($link);\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t}\n\n\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t$link.append(document.createTextNode(this.args[0].text));\n\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the link text.\n\t\t\t\t$link.wikiWithOptions({ profile : 'core' }, this.args[0]);\n\t\t\t\tpassage = this.args.length > 1 ? this.args[1] : undefined;\n\t\t\t}\n\n\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t$link.attr('data-passage', passage);\n\n\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t$link.addClass('link-internal');\n\n\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t$link.addClass('link-visited');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$link.addClass('link-broken');\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$link.addClass('link-internal');\n\t\t\t}\n\n\t\t\t$link\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tnamespace : '.macros',\n\t\t\t\t\tone       : passage != null // lazy equality for null\n\t\t\t\t}, this.createShadowWrapper(\n\t\t\t\t\tthis.payload[0].contents !== ''\n\t\t\t\t\t\t? () => Wikifier.wikifyEval(this.payload[0].contents.trim())\n\t\t\t\t\t\t: null,\n\t\t\t\t\tpassage != null // lazy equality for null\n\t\t\t\t\t\t? () => Engine.play(passage)\n\t\t\t\t\t\t: null\n\t\t\t\t))\n\t\t\t\t.appendTo(this.output);\n\t\t}\n\t});\n\n\t/*\n\t\t<<checkbox>>\n\t*/\n\tMacro.add('checkbox', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 3) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('unchecked value'); }\n\t\t\t\tif (this.args.length < 3) { errors.push('checked value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst uncheckValue = this.args[1];\n\t\t\tconst checkValue   = this.args[2];\n\t\t\tconst el           = document.createElement('input');\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'checkbox',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.checked ? checkValue : uncheckValue);\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and input element to the appropriate value and state, as requested.\n\t\t\t*/\n\t\t\tif (this.args.length > 3 && this.args[3] === 'checked') {\n\t\t\t\tel.checked = true;\n\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tState.setVar(varName, uncheckValue);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<cycle>>, <<listbox>>, <<option>>, & <<optionsfrom>>\n\t*/\n\tMacro.add(['cycle', 'listbox'], {\n\t\tisAsync  : true,\n\t\tskipArgs : ['optionsfrom'],\n\t\ttags     : ['option', 'optionsfrom'],\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no variable name specified');\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId = Util.slugify(varName);\n\t\t\tconst len   = this.payload.length;\n\n\t\t\tif (len === 1) {\n\t\t\t\treturn this.error('no options specified');\n\t\t\t}\n\n\t\t\tconst autoselect = this.args.length > 1 && this.args[1] === 'autoselect';\n\t\t\tconst options    = [];\n\t\t\tconst tagCount   = { option : 0, optionsfrom : 0 };\n\t\t\tlet selectedIdx = -1;\n\n\t\t\t// Get the options and selected index, if any.\n\t\t\tfor (let i = 1; i < len; ++i) {\n\t\t\t\tconst payload = this.payload[i];\n\n\t\t\t\t// <<option label value [selected]>>\n\t\t\t\tif (payload.name === 'option') {\n\t\t\t\t\t++tagCount.option;\n\n\t\t\t\t\tif (payload.args.length === 0) {\n\t\t\t\t\t\treturn this.error(`no arguments specified for <<${payload.name}>> (#${tagCount.option})`);\n\t\t\t\t\t}\n\n\t\t\t\t\toptions.push({\n\t\t\t\t\t\tlabel : String(payload.args[0]),\n\t\t\t\t\t\tvalue : payload.args.length === 1 ? payload.args[0] : payload.args[1]\n\t\t\t\t\t});\n\n\t\t\t\t\tif (payload.args.length > 2 && payload.args[2] === 'selected') {\n\t\t\t\t\t\tif (autoselect) {\n\t\t\t\t\t\t\treturn this.error('cannot specify both the autoselect and selected keywords');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (selectedIdx !== -1) {\n\t\t\t\t\t\t\treturn this.error(`multiple selected keywords specified for <<${payload.name}>> (#${selectedIdx + 1} & #${tagCount.option})`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tselectedIdx = options.length - 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// <<optionsfrom expression>>\n\t\t\t\telse {\n\t\t\t\t\t++tagCount.optionsfrom;\n\n\t\t\t\t\tif (payload.args.full.length === 0) {\n\t\t\t\t\t\treturn this.error(`no expression specified for <<${payload.name}>> (#${tagCount.optionsfrom})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: If the first character is the left curly brace, then we\n\t\t\t\t\t\t\tassume that it's part of an object literal and wrap it within\n\t\t\t\t\t\t\tparenthesis to ensure that it is not mistaken for a block\n\t\t\t\t\t\t\tduring evaluation—which would cause an error.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tconst exp = payload.args.full;\n\t\t\t\t\t\tresult = Scripting.evalJavaScript(exp[0] === '{' ? `(${exp})` : exp);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (typeof result !== 'object' || result === null) {\n\t\t\t\t\t\treturn this.error(`expression must yield a supported collection or generic object (type: ${result === null ? 'null' : typeof result})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (result instanceof Array || result instanceof Set) {\n\t\t\t\t\t\tresult.forEach(val => options.push({ label : String(val), value : val }));\n\t\t\t\t\t}\n\t\t\t\t\telse if (result instanceof Map) {\n\t\t\t\t\t\tresult.forEach((val, key) => options.push({ label : String(key), value : val }));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tconst oType = Util.toStringTag(result);\n\n\t\t\t\t\t\tif (oType !== 'Object') {\n\t\t\t\t\t\t\treturn this.error(`expression must yield a supported collection or generic object (object type: ${oType})`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tObject.keys(result).forEach(key => options.push({ label : key, value : result[key] }));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// No options were selected by the user, so we must select one.\n\t\t\tif (selectedIdx === -1) {\n\t\t\t\t// Attempt to automatically select an option by matching the variable's current value.\n\t\t\t\tif (autoselect) {\n\t\t\t\t\t// NOTE: This will usually fail for objects due to a variety of reasons.\n\t\t\t\t\tconst sameValueZero = Util.sameValueZero;\n\t\t\t\t\tconst curValue      = State.getVar(varName);\n\t\t\t\t\tconst curValueIdx   = options.findIndex(opt => sameValueZero(opt.value, curValue));\n\t\t\t\t\tselectedIdx = curValueIdx === -1 ? 0 : curValueIdx;\n\t\t\t\t}\n\n\t\t\t\t// Simply select the first option.\n\t\t\t\telse {\n\t\t\t\t\tselectedIdx = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set up and append the appropriate element to the output buffer.\n\t\t\tif (this.name === 'cycle') {\n\t\t\t\tlet cycleIdx = selectedIdx;\n\t\t\t\tjQuery(document.createElement('a'))\n\t\t\t\t\t.wikiWithOptions({ profile : 'core' }, options[selectedIdx].label)\n\t\t\t\t\t.attr('id', `${this.name}-${varId}`)\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.ariaClick({ namespace : '.macros' }, this.createShadowWrapper(function () {\n\t\t\t\t\t\tcycleIdx = (cycleIdx + 1) % options.length;\n\t\t\t\t\t\t$(this).empty().wikiWithOptions({ profile : 'core' }, options[cycleIdx].label);\n\t\t\t\t\t\tState.setVar(varName, options[cycleIdx].value);\n\t\t\t\t\t}))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\t\t\telse { // this.name === 'listbox'\n\t\t\t\tconst $select = jQuery(document.createElement('select'));\n\n\t\t\t\toptions.forEach((opt, i) => {\n\t\t\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t\t\t.val(i)\n\t\t\t\t\t\t.text(opt.label)\n\t\t\t\t\t\t.appendTo($select);\n\t\t\t\t});\n\n\t\t\t\t$select\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t\t})\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.val(selectedIdx)\n\t\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\t\tState.setVar(varName, options[Number(this.value)].value);\n\t\t\t\t\t}))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\n\t\t\t// Set the variable to the appropriate value, as requested.\n\t\t\tState.setVar(varName, options[selectedIdx].value);\n\t\t}\n\t});\n\n\t/*\n\t\t<<linkappend>>, <<linkprepend>>, & <<linkreplace>>\n\t*/\n\tMacro.add(['linkappend', 'linkprepend', 'linkreplace'], {\n\t\tisAsync : true,\n\t\ttags    : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no link text specified');\n\t\t\t}\n\n\t\t\tconst $link      = jQuery(document.createElement('a'));\n\t\t\tconst $insert    = jQuery(document.createElement('span'));\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\n\t\t\t$link\n\t\t\t\t.wikiWithOptions({ profile : 'core' }, this.args[0])\n\t\t\t\t.addClass(`link-internal macro-${this.name}`)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tnamespace : '.macros',\n\t\t\t\t\tone       : true\n\t\t\t\t}, this.createShadowWrapper(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tif (this.name === 'linkreplace') {\n\t\t\t\t\t\t\t$link.remove();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t$link\n\t\t\t\t\t\t\t\t.wrap(`<span class=\"macro-${this.name}\"></span>`)\n\t\t\t\t\t\t\t\t.replaceWith(() => $link.html());\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.payload[0].contents !== '') {\n\t\t\t\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\t\t\t\tnew Wikifier(frag, this.payload[0].contents);\n\t\t\t\t\t\t\t$insert.append(frag);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (transition) {\n\t\t\t\t\t\t\tsetTimeout(() => $insert.removeClass(`macro-${this.name}-in`), Engine.minDomActionDelay);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t$insert.addClass(`macro-${this.name}-insert`);\n\n\t\t\tif (transition) {\n\t\t\t\t$insert.addClass(`macro-${this.name}-in`);\n\t\t\t}\n\n\t\t\tif (this.name === 'linkprepend') {\n\t\t\t\t$insert.insertBefore($link);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$insert.insertAfter($link);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<radiobutton>>\n\t*/\n\tMacro.add('radiobutton', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('checked value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId      = Util.slugify(varName);\n\t\t\tconst checkValue = this.args[1];\n\t\t\tconst el         = document.createElement('input');\n\n\t\t\t/*\n\t\t\t\tSet up and initialize the group counter.\n\t\t\t*/\n\t\t\tif (!TempState.hasOwnProperty(this.name)) {\n\t\t\t\tTempState[this.name] = {};\n\t\t\t}\n\n\t\t\tif (!TempState[this.name].hasOwnProperty(varId)) {\n\t\t\t\tTempState[this.name][varId] = 0;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}-${TempState[this.name][varId]++}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'radio',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tif (this.checked) {\n\t\t\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable to the checked value and the input element to checked, if requested.\n\t\t\t*/\n\t\t\tif (this.args.length > 2 && this.args[2] === 'checked') {\n\t\t\t\tel.checked = true;\n\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<textarea>>\n\t*/\n\tMacro.add('textarea', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('default value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst defaultValue = this.args[1];\n\t\t\tconst autofocus    = this.args[2] === 'autofocus';\n\t\t\tconst el           = document.createElement('textarea');\n\n\t\t\t/*\n\t\t\t\tSet up and append the textarea element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\trows     : 4,\n\t\t\t\t\t// cols     : 68, // instead of setting \"cols\" we set the `min-width` in CSS\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.value);\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and textarea element to the default value.\n\t\t\t*/\n\t\t\tState.setVar(varName, defaultValue);\n\t\t\t// Ideally, we should be setting `.defaultValue` here, but IE doesn't support it,\n\t\t\t// so we have to use `.textContent`, which is equivalent.\n\t\t\tel.textContent = defaultValue;\n\n\t\t\t/*\n\t\t\t\tAutofocus the textarea element, if requested.\n\t\t\t*/\n\t\t\tif (autofocus) {\n\t\t\t\t// Set the element's \"autofocus\" attribute.\n\t\t\t\tel.setAttribute('autofocus', 'autofocus');\n\n\t\t\t\t// Set up a single-use post-display task to autofocus the element.\n\t\t\t\tpostdisplay[`#autofocus:${el.id}`] = task => {\n\t\t\t\t\tdelete postdisplay[task]; // single-use task\n\t\t\t\t\tsetTimeout(() => el.focus(), Engine.minDomActionDelay);\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<textbox>>\n\t*/\n\tMacro.add('textbox', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('default value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst defaultValue = this.args[1];\n\t\t\tconst el           = document.createElement('input');\n\t\t\tlet autofocus = false;\n\t\t\tlet passage;\n\n\t\t\tif (this.args.length > 3) {\n\t\t\t\tpassage   = this.args[2];\n\t\t\t\tautofocus = this.args[3] === 'autofocus';\n\t\t\t}\n\t\t\telse if (this.args.length > 2) {\n\t\t\t\tif (this.args[2] === 'autofocus') {\n\t\t\t\t\tautofocus = true;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tpassage = this.args[2];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (typeof passage === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = passage.link;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'text',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.value);\n\t\t\t\t}))\n\t\t\t\t.on('keypress.macros', this.createShadowWrapper(function (ev) {\n\t\t\t\t\t// If Return/Enter is pressed, set the variable and, optionally, forward to another passage.\n\t\t\t\t\tif (ev.which === 13) { // 13 is Return/Enter\n\t\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t\tState.setVar(varName, this.value);\n\n\t\t\t\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and input element to the default value.\n\t\t\t*/\n\t\t\tState.setVar(varName, defaultValue);\n\t\t\tel.value = defaultValue;\n\n\t\t\t/*\n\t\t\t\tAutofocus the input element, if requested.\n\t\t\t*/\n\t\t\tif (autofocus) {\n\t\t\t\t// Set the element's \"autofocus\" attribute.\n\t\t\t\tel.setAttribute('autofocus', 'autofocus');\n\n\t\t\t\t// Set up a single-use post-display task to autofocus the element.\n\t\t\t\tpostdisplay[`#autofocus:${el.id}`] = task => {\n\t\t\t\t\tdelete postdisplay[task]; // single-use task\n\t\t\t\t\tsetTimeout(() => el.focus(), Engine.minDomActionDelay);\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] <<click>>\n\t*/\n\tMacro.add('click', 'link'); // add <<click>> as an alias of <<link>>\n\n\n\t/*******************************************************************************************************************\n\t\tLinks Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<actions>>\n\t*/\n\tMacro.add('actions', {\n\t\thandler() {\n\t\t\tconst $list = jQuery(document.createElement('ul'))\n\t\t\t\t.addClass(this.name)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\tfor (let i = 0; i < this.args.length; ++i) {\n\t\t\t\tlet passage;\n\t\t\t\tlet text;\n\t\t\t\tlet $image;\n\t\t\t\tlet setFn;\n\n\t\t\t\tif (typeof this.args[i] === 'object') {\n\t\t\t\t\tif (this.args[i].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[i].source);\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[i].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[i].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[i].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tpassage = this.args[i].link;\n\t\t\t\t\t\tsetFn   = this.args[i].setFn;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\ttext    = this.args[i].text;\n\t\t\t\t\t\tpassage = this.args[i].link;\n\t\t\t\t\t\tsetFn   = this.args[i].setFn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\ttext = passage = this.args[i];\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\t   State.variables.hasOwnProperty('#actions')\n\t\t\t\t\t&& State.variables['#actions'].hasOwnProperty(passage)\n\t\t\t\t\t&& State.variables['#actions'][passage]\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tjQuery(Wikifier.createInternalLink(\n\t\t\t\t\tjQuery(document.createElement('li')).appendTo($list),\n\t\t\t\t\tpassage,\n\t\t\t\t\tnull,\n\t\t\t\t\t((passage, fn) => () => {\n\t\t\t\t\t\tif (!State.variables.hasOwnProperty('#actions')) {\n\t\t\t\t\t\t\tState.variables['#actions'] = {};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tState.variables['#actions'][passage] = true;\n\n\t\t\t\t\t\tif (typeof fn === 'function') {\n\t\t\t\t\t\t\tfn();\n\t\t\t\t\t\t}\n\t\t\t\t\t})(passage, setFn)\n\t\t\t\t))\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.append($image || document.createTextNode(text));\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<back>> & <<return>>\n\t*/\n\tMacro.add(['back', 'return'], {\n\t\thandler() {\n\t\t\t/* legacy */\n\t\t\tif (this.args.length > 1) {\n\t\t\t\treturn this.error('too many arguments specified, check the documentation for details');\n\t\t\t}\n\t\t\t/* /legacy */\n\n\t\t\tlet momentIndex = -1;\n\t\t\tlet passage;\n\t\t\tlet text;\n\t\t\tlet $image;\n\n\t\t\tif (this.args.length === 1) {\n\t\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[0].source);\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('link')) {\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\tif (this.args[0].count === 1) {\n\t\t\t\t\t\t\t// Simple link syntax: `[[...]]`.\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Pretty link syntax: `[[...|...]]`.\n\t\t\t\t\t\t\ttext    = this.args[0].text;\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (this.args.length === 1) {\n\t\t\t\t\t// Argument was simply the link text.\n\t\t\t\t\ttext = this.args[0];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\t/*\n\t\t\t\t\tFind the index and title of the most recent moment whose title does not match\n\t\t\t\t\tthat of the active (present) moment's.\n\t\t\t\t*/\n\t\t\t\tfor (let i = State.length - 2; i >= 0; --i) {\n\t\t\t\t\tif (State.history[i].title !== State.passage) {\n\t\t\t\t\t\tmomentIndex = i;\n\t\t\t\t\t\tpassage = State.history[i].title;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If we failed to find a passage and we're `<<return>>`, fallback to `State.expired`.\n\t\t\t\tif (passage == null && this.name === 'return') { // lazy equality for null\n\t\t\t\t\tfor (let i = State.expired.length - 1; i >= 0; --i) {\n\t\t\t\t\t\tif (State.expired[i] !== State.passage) {\n\t\t\t\t\t\t\tpassage = State.expired[i];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (!Story.has(passage)) {\n\t\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tif (this.name === 'back') {\n\t\t\t\t\t/*\n\t\t\t\t\t\tFind the index of the most recent moment whose title matches that of the\n\t\t\t\t\t\tspecified passage.\n\t\t\t\t\t*/\n\t\t\t\t\tfor (let i = State.length - 2; i >= 0; --i) {\n\t\t\t\t\t\tif (State.history[i].title === passage) {\n\t\t\t\t\t\t\tmomentIndex = i;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (momentIndex === -1) {\n\t\t\t\t\t\treturn this.error(`cannot find passage \"${passage}\" in the current story history`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn this.error('cannot find passage');\n\t\t\t}\n\n\t\t\t// if (this.name === \"back\" && momentIndex === -1) {\n\t\t\t// \t// no-op; we're already at the first passage in the current story history\n\t\t\t// \treturn;\n\t\t\t// }\n\n\t\t\tlet $el;\n\n\t\t\tif (this.name !== 'back' || momentIndex !== -1) {\n\t\t\t\t$el = jQuery(document.createElement('a'))\n\t\t\t\t\t.addClass('link-internal')\n\t\t\t\t\t.ariaClick(\n\t\t\t\t\t\t{ one : true },\n\t\t\t\t\t\tthis.name === 'return'\n\t\t\t\t\t\t\t? () => Engine.play(passage)\n\t\t\t\t\t\t\t: () => Engine.goTo(momentIndex)\n\t\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$el = jQuery(document.createElement('span'))\n\t\t\t\t\t.addClass('link-disabled');\n\t\t\t}\n\n\t\t\t$el\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.append($image || document.createTextNode(text || L10n.get(`macro${this.name.toUpperFirst()}Text`)))\n\t\t\t\t.appendTo(this.output);\n\t\t}\n\t});\n\n\t/*\n\t\t<<choice>>\n\t*/\n\tMacro.add('choice', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tconst choiceId = State.passage;\n\t\t\tlet passage;\n\t\t\tlet text;\n\t\t\tlet $image;\n\t\t\tlet setFn;\n\n\t\t\tif (this.args.length === 1) {\n\t\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[0].source);\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\tsetFn   = this.args[0].setFn;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\ttext    = this.args[0].text;\n\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\tsetFn   = this.args[0].setFn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\ttext = passage = this.args[0];\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// NOTE: The arguments here are backwards.\n\t\t\t\tpassage = this.args[0];\n\t\t\t\ttext    = this.args[1];\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t   State.variables.hasOwnProperty('#choice')\n\t\t\t\t&& State.variables['#choice'].hasOwnProperty(choiceId)\n\t\t\t\t&& State.variables['#choice'][choiceId]\n\t\t\t) {\n\t\t\t\tjQuery(document.createElement('span'))\n\t\t\t\t\t.addClass(`link-disabled macro-${this.name}`)\n\t\t\t\t\t.attr('tabindex', -1)\n\t\t\t\t\t.append($image || document.createTextNode(text))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tjQuery(Wikifier.createInternalLink(this.output, passage, null, () => {\n\t\t\t\tif (!State.variables.hasOwnProperty('#choice')) {\n\t\t\t\t\tState.variables['#choice'] = {};\n\t\t\t\t}\n\n\t\t\t\tState.variables['#choice'][choiceId] = true;\n\n\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\tsetFn();\n\t\t\t\t}\n\t\t\t}))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.append($image || document.createTextNode(text));\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tDOM Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<addclass>> & <<toggleclass>>\n\t*/\n\tMacro.add(['addclass', 'toggleclass'], {\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('selector'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('class names'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tswitch (this.name) {\n\t\t\tcase 'addclass':\n\t\t\t\t$targets.addClass(this.args[1].trim());\n\t\t\t\tbreak;\n\n\t\t\tcase 'toggleclass':\n\t\t\t\t$targets.toggleClass(this.args[1].trim());\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<removeclass>>\n\t*/\n\tMacro.add('removeclass', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tif (this.args.length > 1) {\n\t\t\t\t$targets.removeClass(this.args[1].trim());\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$targets.removeClass();\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<copy>>\n\t*/\n\tMacro.add('copy', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tjQuery(this.output).append($targets.html());\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<append>>, <<prepend>>, & <<replace>>\n\t*/\n\tMacro.add(['append', 'prepend', 'replace'], {\n\t\ttags : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tif (this.payload[0].contents !== '') {\n\t\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\t\tlet $insert;\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$insert = jQuery(document.createElement('span'));\n\t\t\t\t\t$insert.addClass(`macro-${this.name}-insert macro-${this.name}-in`);\n\t\t\t\t\tsetTimeout(() => $insert.removeClass(`macro-${this.name}-in`), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$insert = jQuery(document.createDocumentFragment());\n\t\t\t\t}\n\n\t\t\t\t$insert.wiki(this.payload[0].contents);\n\n\t\t\t\tswitch (this.name) {\n\t\t\t\tcase 'replace':\n\t\t\t\t\t$targets.empty();\n\t\t\t\t\t/* falls through */\n\n\t\t\t\tcase 'append':\n\t\t\t\t\t$targets.append($insert);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'prepend':\n\t\t\t\t\t$targets.prepend($insert);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (this.name === 'replace') {\n\t\t\t\t$targets.empty();\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<remove>>\n\t*/\n\tMacro.add('remove', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\t$targets.remove();\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAudio Macros.\n\t*******************************************************************************************************************/\n\tif (Has.audio) {\n\t\tconst errorOnePlaybackAction = (cur, prev) => `only one playback action allowed per invocation, \"${cur}\" cannot be combined with \"${prev}\"`;\n\n\t\t/*\n\t\t\t<<audio>>\n\t\t*/\n\t\tMacro.add('audio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\tconst errors = [];\n\t\t\t\t\tif (this.args.length < 1) { errors.push('track and/or group IDs'); }\n\t\t\t\t\tif (this.args.length < 2) { errors.push('actions'); }\n\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t}\n\n\t\t\t\tlet selected;\n\n\t\t\t\t// Process the track and/or group IDs.\n\t\t\t\ttry {\n\t\t\t\t\tselected = SimpleAudio.select(this.args[0]);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\tconst args = this.args.slice(1);\n\t\t\t\tlet action;\n\t\t\t\tlet fadeOver = 5;\n\t\t\t\tlet fadeTo;\n\t\t\t\tlet loop;\n\t\t\t\tlet mute;\n\t\t\t\tlet passage;\n\t\t\t\tlet time;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\tcase 'play':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadein':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 1;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeout':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 0;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('fadeto missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeoverto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length < 2) {\n\t\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\t\tif (args.length < 1) { errors.push('seconds'); }\n\t\t\t\t\t\t\tif (args.length < 2) { errors.push('level'); }\n\t\t\t\t\t\t\treturn this.error(`fadeoverto missing required ${errors.join(' and ')} value${errors.length > 1 ? 's' : ''}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeOver = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeOver) || !Number.isFinite(fadeOver)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'time':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('time missing required seconds value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\ttime = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(time) || !Number.isFinite(time)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse time: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'loop':\n\t\t\t\t\tcase 'unloop':\n\t\t\t\t\t\tloop = arg === 'loop';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'goto':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('goto missing required passage title');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\n\t\t\t\t\t\tif (typeof raw === 'object') {\n\t\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\t\tpassage = raw.link;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\t\t\tpassage = raw;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!Story.has(passage)) {\n\t\t\t\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tselected.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (time != null) { // lazy equality for null\n\t\t\t\t\t\tselected.time(time);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tselected.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (loop != null) { // lazy equality for null\n\t\t\t\t\t\tselected.loop(loop);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t\t\tconst nsEnded = `ended.macros.macro-${this.name}_goto`;\n\t\t\t\t\t\tselected\n\t\t\t\t\t\t\t.off(nsEnded)\n\t\t\t\t\t\t\t.one(nsEnded, () => {\n\t\t\t\t\t\t\t\tselected.off(nsEnded);\n\t\t\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'fade':\n\t\t\t\t\t\tselected.fade(fadeOver, fadeTo);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tselected.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\t\tselected.pause();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'play':\n\t\t\t\t\t\tselected.playWhenAllowed();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tselected.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tselected.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<cacheaudio track_id source_list>>\n\t\t*/\n\t\tMacro.add('cacheaudio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\tconst errors = [];\n\t\t\t\t\tif (this.args.length < 1) { errors.push('track ID'); }\n\t\t\t\t\tif (this.args.length < 2) { errors.push('sources'); }\n\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t}\n\n\t\t\t\tconst id       = String(this.args[0]).trim();\n\t\t\t\tconst oldFmtRe = /^format:\\s*([\\w-]+)\\s*;\\s*/i;\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.tracks.add(id, this.args.slice(1).map(source => {\n\t\t\t\t\t\t/* legacy */\n\t\t\t\t\t\t// Transform an old format specifier into the new style.\n\t\t\t\t\t\tif (oldFmtRe.test(source)) {\n\t\t\t\t\t\t\t// If in Test Mode, return an error.\n\t\t\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\t\t\treturn this.error(`track ID \"${id}\": format specifier migration required, \"format:formatId;\" \\u2192 \"formatId|\"`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tsource = source.replace(oldFmtRe, '$1|'); // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn source;\n\t\t\t\t\t\t/* /legacy */\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// If in Test Mode and no supported sources were specified, return an error.\n\t\t\t\tif (Config.debug && !SimpleAudio.tracks.get(id).hasSource()) {\n\t\t\t\t\treturn this.error(`track ID \"${id}\": no supported audio sources found`);\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<createaudiogroup group_id>>\n\t\t\t\t<<track track_id>>\n\t\t\t\t…\n\t\t\t<</createaudiogroup>>\n\t\t*/\n\t\tMacro.add('createaudiogroup', {\n\t\t\ttags : ['track'],\n\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no group ID specified');\n\t\t\t\t}\n\n\t\t\t\tif (this.payload.length === 1) {\n\t\t\t\t\treturn this.error('no tracks defined via <<track>>');\n\t\t\t\t}\n\n\t\t\t\t// Initial debug view setup for `<<createaudiogroup>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst groupId  = String(this.args[0]).trim();\n\t\t\t\tconst trackIds = [];\n\n\t\t\t\tfor (let i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\tif (this.payload[i].args.length < 1) {\n\t\t\t\t\t\treturn this.error('no track ID specified');\n\t\t\t\t\t}\n\n\t\t\t\t\ttrackIds.push(String(this.payload[i].args[0]).trim());\n\n\t\t\t\t\t// Custom debug view setup for the current `<<track>>`.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.groups.add(groupId, trackIds);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Custom fake debug view setup for `<</createaudiogroup>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<createplaylist list_id>>\n\t\t\t\t<<track track_id action_list>>\n\t\t\t\t…\n\t\t\t<</createplaylist>>\n\t\t*/\n\t\tMacro.add('createplaylist', {\n\t\t\ttags : ['track'],\n\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no list ID specified');\n\t\t\t\t}\n\n\t\t\t\tif (this.payload.length === 1) {\n\t\t\t\t\treturn this.error('no tracks defined via <<track>>');\n\t\t\t\t}\n\n\t\t\t\tconst playlist = Macro.get('playlist');\n\n\t\t\t\tif (playlist.from !== null && playlist.from !== 'createplaylist') {\n\t\t\t\t\treturn this.error('a playlist has already been defined with <<setplaylist>>');\n\t\t\t\t}\n\n\t\t\t\t// Initial debug view setup for `<<createplaylist>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst listId    = String(this.args[0]).trim();\n\t\t\t\tconst trackObjs = [];\n\n\t\t\t\tfor (let i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\tif (this.payload[i].args.length === 0) {\n\t\t\t\t\t\treturn this.error('no track ID specified');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst trackObj = { id : String(this.payload[i].args[0]).trim() };\n\t\t\t\t\tconst args     = this.payload[i].args.slice(1);\n\n\t\t\t\t\t// Process arguments.\n\t\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\t\tlet raw;\n\t\t\t\t\t\tlet parsed;\n\n\t\t\t\t\t\tswitch (arg) {\n\t\t\t\t\t\tcase 'copy': // [DEPRECATED]\n\t\t\t\t\t\tcase 'own':\n\t\t\t\t\t\t\ttrackObj.own = true;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'rate':\n\t\t\t\t\t\t\t// if (args.length === 0) {\n\t\t\t\t\t\t\t// \treturn this.error('rate missing required speed value');\n\t\t\t\t\t\t\t// }\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// raw = args.shift();\n\t\t\t\t\t\t\t// parsed = Number.parseFloat(raw);\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// if (Number.isNaN(parsed) || !Number.isFinite(parsed)) {\n\t\t\t\t\t\t\t// \treturn this.error(`cannot parse rate: ${raw}`);\n\t\t\t\t\t\t\t// }\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// trackObj.rate = parsed;\n\t\t\t\t\t\t\tif (args.length > 0) {\n\t\t\t\t\t\t\t\targs.shift();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\t\tparsed = Number.parseFloat(raw);\n\n\t\t\t\t\t\t\tif (Number.isNaN(parsed) || !Number.isFinite(parsed)) {\n\t\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ttrackObj.volume = parsed;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\ttrackObjs.push(trackObj);\n\n\t\t\t\t\t// Custom debug view setup for the current `<<track>>`.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.lists.add(listId, trackObjs);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Lock `<<playlist>>` into our syntax.\n\t\t\t\tif (playlist.from === null) {\n\t\t\t\t\tplaylist.from = 'createplaylist';\n\t\t\t\t}\n\n\t\t\t\t// Custom fake debug view setup for `<</createplaylist>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<masteraudio action_list>>\n\t\t*/\n\t\tMacro.add('masteraudio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no actions specified');\n\t\t\t\t}\n\n\t\t\t\tconst args = this.args.slice(0);\n\t\t\t\tlet action;\n\t\t\t\tlet mute;\n\t\t\t\tlet muteOnHide;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'muteonhide':\n\t\t\t\t\tcase 'nomuteonhide':\n\t\t\t\t\t\tmuteOnHide = arg === 'muteonhide';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (muteOnHide != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.muteOnHidden(muteOnHide);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tSimpleAudio.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tSimpleAudio.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tSimpleAudio.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<playlist list_id action_list>>  ← <<createplaylist>> syntax\n\t\t\t<<playlist action_list>>          ← <<setplaylist>> syntax\n\t\t*/\n\t\tMacro.add('playlist', {\n\t\t\tfrom : null,\n\n\t\t\thandler() {\n\t\t\t\tconst from = this.self.from;\n\n\t\t\t\tif (from === null) {\n\t\t\t\t\treturn this.error('no playlists have been created');\n\t\t\t\t}\n\n\t\t\t\tlet list;\n\t\t\t\tlet args;\n\n\t\t\t\tif (from === 'createplaylist') {\n\t\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\tif (this.args.length < 1) { errors.push('list ID'); }\n\t\t\t\t\t\tif (this.args.length < 2) { errors.push('actions'); }\n\t\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\t\tif (!SimpleAudio.lists.has(id)) {\n\t\t\t\t\t\treturn this.error(`playlist \"${id}\" does not exist`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlist = SimpleAudio.lists.get(id);\n\t\t\t\t\targs = this.args.slice(1);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\t\treturn this.error('no actions specified');\n\t\t\t\t\t}\n\n\t\t\t\t\tlist = SimpleAudio.lists.get('setplaylist');\n\t\t\t\t\targs = this.args.slice(0);\n\t\t\t\t}\n\n\t\t\t\tlet action;\n\t\t\t\tlet fadeOver = 5;\n\t\t\t\tlet fadeTo;\n\t\t\t\tlet loop;\n\t\t\t\tlet mute;\n\t\t\t\tlet shuffle;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\tcase 'play':\n\t\t\t\t\tcase 'skip':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadein':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 1;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeout':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 0;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('fadeto missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeoverto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length < 2) {\n\t\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\t\tif (args.length < 1) { errors.push('seconds'); }\n\t\t\t\t\t\t\tif (args.length < 2) { errors.push('level'); }\n\t\t\t\t\t\t\treturn this.error(`fadeoverto missing required ${errors.join(' and ')} value${errors.length > 1 ? 's' : ''}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeOver = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeOver) || !Number.isFinite(fadeOver)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'loop':\n\t\t\t\t\tcase 'unloop':\n\t\t\t\t\t\tloop = arg === 'loop';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'shuffle':\n\t\t\t\t\tcase 'unshuffle':\n\t\t\t\t\t\tshuffle = arg === 'shuffle';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tlist.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tlist.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (loop != null) { // lazy equality for null\n\t\t\t\t\t\tlist.loop(loop);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (shuffle != null) { // lazy equality for null\n\t\t\t\t\t\tlist.shuffle(shuffle);\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'fade':\n\t\t\t\t\t\tlist.fade(fadeOver, fadeTo);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tlist.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\t\tlist.pause();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'play':\n\t\t\t\t\t\tlist.playWhenAllowed();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'skip':\n\t\t\t\t\t\tlist.skip();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tlist.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tlist.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<removeaudiogroup group_id>>\n\t\t*/\n\t\tMacro.add('removeaudiogroup', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no group ID specified');\n\t\t\t\t}\n\n\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\tif (!SimpleAudio.groups.has(id)) {\n\t\t\t\t\treturn this.error(`group \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tSimpleAudio.groups.delete(id);\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<removeplaylist list_id>>\n\t\t*/\n\t\tMacro.add('removeplaylist', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no list ID specified');\n\t\t\t\t}\n\n\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\tif (!SimpleAudio.lists.has(id)) {\n\t\t\t\t\treturn this.error(`playlist \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tSimpleAudio.lists.delete(id);\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<waitforaudio>>\n\t\t*/\n\t\tMacro.add('waitforaudio', {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\tSimpleAudio.loadWithScreen();\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t[DEPRECATED] <<setplaylist track_id_list>>\n\t\t*/\n\t\tMacro.add('setplaylist', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no track ID(s) specified');\n\t\t\t\t}\n\n\t\t\t\tconst playlist = Macro.get('playlist');\n\n\t\t\t\tif (playlist.from !== null && playlist.from !== 'setplaylist') {\n\t\t\t\t\treturn this.error('playlists have already been defined with <<createplaylist>>');\n\t\t\t\t}\n\n\t\t\t\t// Create the new playlist.\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.lists.add('setplaylist', this.args.slice(0));\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Lock `<<playlist>>` into our syntax.\n\t\t\t\tif (playlist.from === null) {\n\t\t\t\t\tplaylist.from = 'setplaylist';\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t[DEPRECATED] <<stopallaudio>>\n\t\t*/\n\t\tMacro.add('stopallaudio', {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\tSimpleAudio.select(':all').stop();\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\telse {\n\t\t/* The HTML5 <audio> API appears to be missing or disabled, set up no-op macros. */\n\t\tMacro.add([\n\t\t\t'audio',\n\t\t\t'cacheaudio',\n\t\t\t'createaudiogroup',\n\t\t\t'createplaylist',\n\t\t\t'masteraudio',\n\t\t\t'playlist',\n\t\t\t'removeaudiogroup',\n\t\t\t'removeplaylist',\n\t\t\t'waitforaudio',\n\n\t\t\t// Deprecated.\n\t\t\t'setplaylist',\n\t\t\t'stopallaudio'\n\t\t], {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\t/* no-op */\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMiscellaneous Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<goto>>\n\t*/\n\tMacro.add('goto', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = this.args[0].link;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the passage name.\n\t\t\t\tpassage = this.args[0];\n\t\t\t}\n\n\t\t\tif (!Story.has(passage)) {\n\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tCall `Engine.play()` asynchronously.\n\n\t\t\t\tNOTE: This does not terminate the current Wikifier call chain,\n\t\t\t\tthough, ideally, it should.  Doing so would not be trivial, however,\n\t\t\t\tand there's also the question of whether that behavior would be\n\t\t\t\tunwanted by users, who are used to the current behavior from\n\t\t\t\tsimilar macros and constructs.\n\t\t\t*/\n\t\t\tsetTimeout(() => Engine.play(passage), Engine.minDomActionDelay);\n\t\t}\n\t});\n\n\t/*\n\t\t<<repeat>> & <<stop>>\n\t*/\n\tMacro.add('repeat', {\n\t\tisAsync : true,\n\t\ttags    : null,\n\t\ttimers  : new Set(),\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no time value specified');\n\t\t\t}\n\n\t\t\tlet delay;\n\n\t\t\ttry {\n\t\t\t\tdelay = Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.args[0]));\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(ex.message);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\tconst $wrapper   = jQuery(document.createElement('span'))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t// Register the timer.\n\t\t\tthis.self.registerInterval(this.createShadowWrapper(() => {\n\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(frag, this.payload[0].contents);\n\n\t\t\t\tlet $output = $wrapper;\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$output = jQuery(document.createElement('span'))\n\t\t\t\t\t\t.addClass('macro-repeat-insert macro-repeat-in')\n\t\t\t\t\t\t.appendTo($output);\n\t\t\t\t}\n\n\t\t\t\t$output.append(frag);\n\n\t\t\t\tif (transition) {\n\t\t\t\t\tsetTimeout(() => $output.removeClass('macro-repeat-in'), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t}), delay);\n\t\t},\n\n\t\tregisterInterval(callback, delay) {\n\t\t\tif (typeof callback !== 'function') {\n\t\t\t\tthrow new TypeError('callback parameter must be a function');\n\t\t\t}\n\n\t\t\tconst turnId = State.turns;\n\t\t\tconst timers = this.timers;\n\t\t\tlet timerId = null;\n\n\t\t\t// Set up the interval.\n\t\t\ttimerId = setInterval(() => {\n\t\t\t\t// Terminate the timer if the turn IDs do not match.\n\t\t\t\tif (turnId !== State.turns) {\n\t\t\t\t\tclearInterval(timerId);\n\t\t\t\t\ttimers.delete(timerId);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet timerIdCache;\n\t\t\t\t/*\n\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t`Wikifier` call.\n\t\t\t\t*/\n\t\t\t\ttry {\n\t\t\t\t\tTempState.break = null;\n\n\t\t\t\t\t// Set up the `repeatTimerId` value, caching the existing value, if necessary.\n\t\t\t\t\tif (TempState.hasOwnProperty('repeatTimerId')) {\n\t\t\t\t\t\ttimerIdCache = TempState.repeatTimerId;\n\t\t\t\t\t}\n\n\t\t\t\t\tTempState.repeatTimerId = timerId;\n\n\t\t\t\t\t// Execute the callback.\n\t\t\t\t\tcallback.call(this);\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\t// Teardown the `repeatTimerId` property, restoring the cached value, if necessary.\n\t\t\t\t\tif (typeof timerIdCache !== 'undefined') {\n\t\t\t\t\t\tTempState.repeatTimerId = timerIdCache;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdelete TempState.repeatTimerId;\n\t\t\t\t\t}\n\n\t\t\t\t\tTempState.break = null;\n\t\t\t\t}\n\t\t\t}, delay);\n\t\t\ttimers.add(timerId);\n\n\t\t\t// Set up a single-use `prehistory` task to remove pending timers.\n\t\t\tif (!prehistory.hasOwnProperty('#repeat-timers-cleanup')) {\n\t\t\t\tprehistory['#repeat-timers-cleanup'] = task => {\n\t\t\t\t\tdelete prehistory[task]; // single-use task\n\t\t\t\t\ttimers.forEach(timerId => clearInterval(timerId));\n\t\t\t\t\ttimers.clear();\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\tMacro.add('stop', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (!TempState.hasOwnProperty('repeatTimerId')) {\n\t\t\t\treturn this.error('must only be used in conjunction with its parent macro <<repeat>>');\n\t\t\t}\n\n\t\t\tconst timers  = Macro.get('repeat').timers;\n\t\t\tconst timerId = TempState.repeatTimerId;\n\t\t\tclearInterval(timerId);\n\t\t\ttimers.delete(timerId);\n\t\t\tTempState.break = 2;\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<timed>> & <<next>>\n\t*/\n\tMacro.add('timed', {\n\t\tisAsync : true,\n\t\ttags    : ['next'],\n\t\ttimers  : new Set(),\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no time value specified in <<timed>>');\n\t\t\t}\n\n\t\t\tconst items = [];\n\n\t\t\ttry {\n\t\t\t\titems.push({\n\t\t\t\t\tname    : this.name,\n\t\t\t\t\tsource  : this.source,\n\t\t\t\t\tdelay   : Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.args[0])),\n\t\t\t\t\tcontent : this.payload[0].contents\n\t\t\t\t});\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`${ex.message} in <<timed>>`);\n\t\t\t}\n\n\t\t\tif (this.payload.length > 1) {\n\t\t\t\tlet i;\n\n\t\t\t\ttry {\n\t\t\t\t\tlet len;\n\n\t\t\t\t\tfor (i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\t\titems.push({\n\t\t\t\t\t\t\tname   : this.payload[i].name,\n\t\t\t\t\t\t\tsource : this.payload[i].source,\n\t\t\t\t\t\t\tdelay  : this.payload[i].args.length === 0\n\t\t\t\t\t\t\t\t? items[items.length - 1].delay\n\t\t\t\t\t\t\t\t: Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.payload[i].args[0])),\n\t\t\t\t\t\t\tcontent : this.payload[i].contents\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`${ex.message} in <<next>> (#${i})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\tconst $wrapper   = jQuery(document.createElement('span'))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t// Register the timer.\n\t\t\tthis.self.registerTimeout(this.createShadowWrapper(item => {\n\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(frag, item.content);\n\n\t\t\t\t// Output.\n\t\t\t\tlet $output = $wrapper;\n\n\t\t\t\t// Custom debug view setup for `<<next>>`.\n\t\t\t\tif (Config.debug && item.name === 'next') {\n\t\t\t\t\t$output = jQuery((new DebugView( // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t$output[0],\n\t\t\t\t\t\t'macro',\n\t\t\t\t\t\titem.name,\n\t\t\t\t\t\titem.source\n\t\t\t\t\t)).output);\n\t\t\t\t}\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$output = jQuery(document.createElement('span'))\n\t\t\t\t\t\t.addClass('macro-timed-insert macro-timed-in')\n\t\t\t\t\t\t.appendTo($output);\n\t\t\t\t}\n\n\t\t\t\t$output.append(frag);\n\n\t\t\t\tif (transition) {\n\t\t\t\t\tsetTimeout(() => $output.removeClass('macro-timed-in'), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t}), items);\n\t\t},\n\n\t\tregisterTimeout(callback, items) {\n\t\t\tif (typeof callback !== 'function') {\n\t\t\t\tthrow new TypeError('callback parameter must be a function');\n\t\t\t}\n\n\t\t\tconst turnId = State.turns;\n\t\t\tconst timers = this.timers;\n\t\t\tlet timerId  = null;\n\t\t\tlet nextItem = items.shift();\n\n\t\t\tconst worker = function () {\n\t\t\t\t// Bookkeeping.\n\t\t\t\ttimers.delete(timerId);\n\n\t\t\t\tif (turnId !== State.turns) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Set the current item and set up the next worker, if any.\n\t\t\t\tconst curItem = nextItem;\n\n\t\t\t\tif ((nextItem = items.shift()) != null) { // lazy equality for null\n\t\t\t\t\ttimerId = setTimeout(worker, nextItem.delay);\n\t\t\t\t\ttimers.add(timerId);\n\t\t\t\t}\n\n\t\t\t\t// Execute the callback.\n\t\t\t\tcallback.call(this, curItem);\n\t\t\t};\n\n\t\t\t// Setup the timeout.\n\t\t\ttimerId = setTimeout(worker, nextItem.delay);\n\t\t\ttimers.add(timerId);\n\n\t\t\t// Set up a single-use `prehistory` task to remove pending timers.\n\t\t\tif (!prehistory.hasOwnProperty('#timed-timers-cleanup')) {\n\t\t\t\tprehistory['#timed-timers-cleanup'] = task => {\n\t\t\t\t\tdelete prehistory[task]; // single-use task\n\t\t\t\t\ttimers.forEach(timerId => clearTimeout(timerId)); // eslint-disable-line no-shadow\n\t\t\t\t\ttimers.clear();\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<widget>>\n\t*/\n\tMacro.add('widget', {\n\t\ttags : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no widget name specified');\n\t\t\t}\n\n\t\t\tconst widgetName = this.args[0];\n\n\t\t\tif (Macro.has(widgetName)) {\n\t\t\t\tif (!Macro.get(widgetName).isWidget) {\n\t\t\t\t\treturn this.error(`cannot clobber existing macro \"${widgetName}\"`);\n\t\t\t\t}\n\n\t\t\t\t// Delete the existing widget.\n\t\t\t\tMacro.delete(widgetName);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tMacro.add(widgetName, {\n\t\t\t\t\tisWidget : true,\n\t\t\t\t\thandler  : (function (contents) {\n\t\t\t\t\t\treturn function () {\n\t\t\t\t\t\t\tlet argsCache;\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t// Cache the existing value of the `$args` variable, if necessary.\n\t\t\t\t\t\t\t\tif (State.variables.hasOwnProperty('args')) {\n\t\t\t\t\t\t\t\t\targsCache = State.variables.args;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Set up the widget `$args` variable and add a shadow.\n\t\t\t\t\t\t\t\tState.variables.args = [...this.args];\n\t\t\t\t\t\t\t\tState.variables.args.raw = this.args.raw;\n\t\t\t\t\t\t\t\tState.variables.args.full = this.args.full;\n\t\t\t\t\t\t\t\tthis.addShadow('$args');\n\n\t\t\t\t\t\t\t\t// Set up the error trapping variables.\n\t\t\t\t\t\t\t\tconst resFrag = document.createDocumentFragment();\n\t\t\t\t\t\t\t\tconst errList = [];\n\n\t\t\t\t\t\t\t\t// Wikify the widget contents.\n\t\t\t\t\t\t\t\tnew Wikifier(resFrag, contents);\n\n\t\t\t\t\t\t\t\t// Carry over the output, unless there were errors.\n\t\t\t\t\t\t\t\tArray.from(resFrag.querySelectorAll('.error')).forEach(errEl => {\n\t\t\t\t\t\t\t\t\terrList.push(errEl.textContent);\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tif (errList.length === 0) {\n\t\t\t\t\t\t\t\t\tthis.output.appendChild(resFrag);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\treturn this.error(`error${errList.length > 1 ? 's' : ''} within widget contents (${errList.join('; ')})`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\treturn this.error(`cannot execute widget: ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t// Revert the `$args` variable shadowing.\n\t\t\t\t\t\t\t\tif (typeof argsCache !== 'undefined') {\n\t\t\t\t\t\t\t\t\tState.variables.args = argsCache;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tdelete State.variables.args;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t})(this.payload[0].contents)\n\t\t\t\t});\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`cannot create widget macro \"${widgetName}\": ${ex.message}`);\n\t\t\t}\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tdialog.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Has, L10n, safeActiveElement */\n\nvar Dialog = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Dialog element caches.\n\tlet _$overlay       = null;\n\tlet _$dialog        = null;\n\tlet _$dialogTitle   = null;\n\tlet _$dialogBody    = null;\n\n\t// The last active/focused non-dialog element.\n\tlet _lastActive     = null;\n\n\t// The width of the browser's scrollbars.\n\tlet _scrollbarWidth = 0;\n\n\t// Dialog mutation resize handler.\n\tlet _dialogObserver = null;\n\n\n\t/*******************************************************************************\n\t\tDialog Functions.\n\t*******************************************************************************/\n\n\t/*\n\t\t[DEPRECATED] Adds a click hander to the target element(s) which opens the dialog modal.\n\t*/\n\tfunction dialogAddClickHandler(targets, options, startFn, doneFn, closeFn) {\n\t\treturn jQuery(targets).ariaClick(ev => {\n\t\t\tev.preventDefault();\n\n\t\t\t// Call the start function.\n\t\t\tif (typeof startFn === 'function') {\n\t\t\t\tstartFn(ev);\n\t\t\t}\n\n\t\t\t// Open the dialog.\n\t\t\tdialogOpen(options, closeFn);\n\n\t\t\t// Call the done function.\n\t\t\tif (typeof doneFn === 'function') {\n\t\t\t\tdoneFn(ev);\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction dialogBodyAppend(...args) {\n\t\t_$dialogBody.append(...args);\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogBody() {\n\t\treturn _$dialogBody.get(0);\n\t}\n\n\tfunction dialogClose(ev) {\n\t\t// Trigger a `:dialogclosing` event on the dialog body.\n\t\t_$dialogBody.trigger(':dialogclosing');\n\n\t\t// Largely reverse the actions taken in `dialogOpen()`.\n\t\tjQuery(document)\n\t\t\t.off('.dialog-close');\n\t\tif (_dialogObserver) {\n\t\t\t_dialogObserver.disconnect();\n\t\t\t_dialogObserver = null;\n\t\t}\n\t\telse {\n\t\t\t_$dialogBody\n\t\t\t\t.off('.dialog-resize');\n\t\t}\n\t\tjQuery(window)\n\t\t\t.off('.dialog-resize');\n\t\t_$dialog\n\t\t\t.removeClass('open')\n\t\t\t.css({ left : '', right : '', top : '', bottom : '' });\n\n\t\tjQuery('#ui-bar,#story')\n\t\t\t.find('[tabindex=-2]')\n\t\t\t.removeAttr('aria-hidden')\n\t\t\t.attr('tabindex', 0);\n\t\tjQuery('body>[tabindex=-3]')\n\t\t\t.removeAttr('aria-hidden')\n\t\t\t.removeAttr('tabindex');\n\n\t\t_$overlay\n\t\t\t.removeClass('open');\n\t\tjQuery(document.documentElement)\n\t\t\t.removeAttr('data-dialog');\n\n\t\t// Clear the dialog's content.\n\t\t_$dialogTitle\n\t\t\t.empty();\n\t\t_$dialogBody\n\t\t\t.empty()\n\t\t\t.removeClass();\n\n\t\t// Attempt to restore focus to whichever element had it prior to opening the dialog.\n\t\tif (_lastActive !== null) {\n\t\t\tjQuery(_lastActive).focus();\n\t\t\t_lastActive = null;\n\t\t}\n\n\t\t// Call the given \"on close\" callback function, if any.\n\t\tif (ev && ev.data && typeof ev.data.closeFn === 'function') {\n\t\t\tev.data.closeFn(ev);\n\t\t}\n\n\t\t// Trigger a `:dialogclosed` event on the dialog body.\n\t\t/* legacy */\n\t\t_$dialogBody.trigger(':dialogclose');\n\t\t/* /legacy */\n\t\t_$dialogBody.trigger(':dialogclosed');\n\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogInit() {\n\t\tif (DEBUG) { console.log('[Dialog/dialogInit()]'); }\n\n\t\tif (document.getElementById('ui-dialog')) {\n\t\t\treturn;\n\t\t}\n\n\t\t/*\n\t\t\tCalculate and cache the width of scrollbars.\n\t\t*/\n\t\t_scrollbarWidth = (() => {\n\t\t\tlet scrollbarWidth;\n\n\t\t\ttry {\n\t\t\t\tconst inner = document.createElement('p');\n\t\t\t\tconst outer = document.createElement('div');\n\n\t\t\t\tinner.style.width      = '100%';\n\t\t\t\tinner.style.height     = '200px';\n\t\t\t\touter.style.position   = 'absolute';\n\t\t\t\touter.style.left       = '0px';\n\t\t\t\touter.style.top        = '0px';\n\t\t\t\touter.style.width      = '100px';\n\t\t\t\touter.style.height     = '100px';\n\t\t\t\touter.style.visibility = 'hidden';\n\t\t\t\touter.style.overflow   = 'hidden';\n\n\t\t\t\touter.appendChild(inner);\n\t\t\t\tdocument.body.appendChild(outer);\n\n\t\t\t\tconst w1 = inner.offsetWidth;\n\t\t\t\t/*\n\t\t\t\t\tThe `overflow: scroll` style property value does not work consistently\n\t\t\t\t\twith scrollbars which are styled with `::-webkit-scrollbar`, so we use\n\t\t\t\t\t`overflow: auto` with dimensions guaranteed to force a scrollbar.\n\t\t\t\t*/\n\t\t\t\touter.style.overflow = 'auto';\n\t\t\t\tlet w2 = inner.offsetWidth;\n\n\t\t\t\tif (w1 === w2) {\n\t\t\t\t\tw2 = outer.clientWidth;\n\t\t\t\t}\n\n\t\t\t\tdocument.body.removeChild(outer);\n\n\t\t\t\tscrollbarWidth = w1 - w2;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn scrollbarWidth || 17; // 17px is a reasonable failover\n\t\t})();\n\n\t\t/*\n\t\t\tGenerate the dialog elements.\n\t\t*/\n\t\tconst $elems = jQuery(document.createDocumentFragment())\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  '<div id=\"ui-overlay\" class=\"ui-close\"></div>'\n\t\t\t\t+ '<div id=\"ui-dialog\" tabindex=\"0\" role=\"dialog\" aria-labelledby=\"ui-dialog-title\">'\n\t\t\t\t+     '<div id=\"ui-dialog-titlebar\">'\n\t\t\t\t+         '<h1 id=\"ui-dialog-title\"></h1>'\n\t\t\t\t+         `<button id=\"ui-dialog-close\" class=\"ui-close\" tabindex=\"0\" aria-label=\"${L10n.get('close')}\">\\uE804</button>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div id=\"ui-dialog-body\"></div>'\n\t\t\t\t+ '</div>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t);\n\n\t\t/*\n\t\t\tCache the dialog elements, since they're going to be used often.\n\n\t\t\tNOTE: We rewrap the elements themselves, rather than simply using\n\t\t\tthe results of `find()`, so that we cache uncluttered jQuery-wrappers\n\t\t\t(i.e. `context` refers to the elements and there is no `prevObject`).\n\t\t*/\n\t\t_$overlay     = jQuery($elems.find('#ui-overlay').get(0));\n\t\t_$dialog      = jQuery($elems.find('#ui-dialog').get(0));\n\t\t_$dialogTitle = jQuery($elems.find('#ui-dialog-title').get(0));\n\t\t_$dialogBody  = jQuery($elems.find('#ui-dialog-body').get(0));\n\n\t\t/*\n\t\t\tInsert the dialog elements into the page before the main script.\n\t\t*/\n\t\t$elems.insertBefore('body>script#script-sugarcube');\n\t}\n\n\tfunction dialogIsOpen(classNames) {\n\t\treturn _$dialog.hasClass('open')\n\t\t\t&& (classNames ? classNames.splitOrEmpty(/\\s+/).every(cn => _$dialogBody.hasClass(cn)) : true);\n\t}\n\n\tfunction dialogOpen(options, closeFn) {\n\t\t// Trigger a `:dialogopening` event on the dialog body.\n\t\t_$dialogBody.trigger(':dialogopening');\n\n\t\t// Grab the options we care about.\n\t\tconst { top } = jQuery.extend({ top : 50 }, options);\n\n\t\t// Record the last active/focused non-dialog element.\n\t\tif (!dialogIsOpen()) {\n\t\t\t_lastActive = safeActiveElement();\n\t\t}\n\n\t\t// Add the `data-dialog` attribute to <html> (mostly used to style <body>).\n\t\tjQuery(document.documentElement)\n\t\t\t.attr('data-dialog', 'open');\n\n\t\t// Display the overlay.\n\t\t_$overlay\n\t\t\t.addClass('open');\n\n\t\t/*\n\t\t\tAdd the imagesLoaded handler to the dialog body, if necessary.\n\n\t\t\tNOTE: We use `querySelector()` here as jQuery has no simple way to\n\t\t\tcheck if, and only if, at least one element of the specified type\n\t\t\texists.  The best that jQuery offers is analogous to `querySelectorAll()`,\n\t\t\twhich enumerates all elements of the specified type.\n\t\t*/\n\t\tif (_$dialogBody[0].querySelector('img') !== null) {\n\t\t\t_$dialogBody\n\t\t\t\t.imagesLoaded()\n\t\t\t\t.always(() => _resizeHandler({ data : { top } }));\n\t\t}\n\n\t\t// Add `aria-hidden=true` to all direct non-dialog-children of <body> to\n\t\t// hide the underlying page from screen readers while the dialog is open.\n\t\tjQuery('body>:not(script,#store-area,tw-storydata,#ui-bar,#ui-overlay,#ui-dialog)')\n\t\t\t.attr('tabindex', -3)\n\t\t\t.attr('aria-hidden', true);\n\t\tjQuery('#ui-bar,#story')\n\t\t\t.find('[tabindex]:not([tabindex^=-])')\n\t\t\t.attr('tabindex', -2)\n\t\t\t.attr('aria-hidden', true);\n\n\t\t// Display the dialog.\n\t\t_$dialog\n\t\t\t.css(_calcPosition(top))\n\t\t\t.addClass('open')\n\t\t\t.focus();\n\n\t\t// Add the UI resize handler.\n\t\tjQuery(window)\n\t\t\t.on('resize.dialog-resize', null, { top }, jQuery.throttle(40, _resizeHandler));\n\n\t\t// Add the dialog mutation resize handler.\n\t\tif (Has.mutationObserver) {\n\t\t\t_dialogObserver = new MutationObserver(mutations => {\n\t\t\t\tfor (let i = 0; i < mutations.length; ++i) {\n\t\t\t\t\tif (mutations[i].type === 'childList') {\n\t\t\t\t\t\t_resizeHandler({ data : { top } });\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t_dialogObserver.observe(_$dialogBody[0], {\n\t\t\t\tchildList : true,\n\t\t\t\tsubtree   : true\n\t\t\t});\n\t\t}\n\t\telse {\n\t\t\t_$dialogBody\n\t\t\t\t.on(\n\t\t\t\t\t'DOMNodeInserted.dialog-resize DOMNodeRemoved.dialog-resize',\n\t\t\t\t\tnull,\n\t\t\t\t\t{ top },\n\t\t\t\t\tjQuery.throttle(40, _resizeHandler)\n\t\t\t\t);\n\t\t}\n\n\t\t// Set up the delegated UI close handler.\n\t\tjQuery(document)\n\t\t\t.on('click.dialog-close', '.ui-close', { closeFn }, dialogClose)\n\t\t\t.on('keypress.dialog-close', '.ui-close', function (ev) {\n\t\t\t\t// 13 is Enter/Return, 32 is Space.\n\t\t\t\tif (ev.which === 13 || ev.which === 32) {\n\t\t\t\t\tjQuery(this).trigger('click');\n\t\t\t\t}\n\t\t\t});\n\n\t\t// Trigger a `:dialogopened` event on the dialog body.\n\t\t/* legacy */\n\t\t_$dialogBody.trigger(':dialogopen');\n\t\t/* /legacy */\n\t\t_$dialogBody.trigger(':dialogopened');\n\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogResize(data) {\n\t\treturn _resizeHandler(typeof data === 'object' ? { data } : undefined);\n\t}\n\n\tfunction dialogSetup(title, classNames) {\n\t\t_$dialogBody\n\t\t\t.empty()\n\t\t\t.removeClass();\n\n\t\tif (classNames != null) { // lazy equality for null\n\t\t\t_$dialogBody.addClass(classNames);\n\t\t}\n\n\t\t_$dialogTitle\n\t\t\t.empty()\n\t\t\t.append((title != null ? String(title) : '') || '\\u00A0'); // lazy equality for null\n\n\t\t// TODO: In v3 this should return `Dialog` for chaining.\n\t\treturn _$dialogBody.get(0);\n\t}\n\n\tfunction dialogBodyWiki(...args) {\n\t\t_$dialogBody.wiki(...args);\n\t\treturn Dialog;\n\t}\n\n\n\t/*******************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************/\n\n\tfunction _calcPosition(topPos) {\n\t\tconst top       = topPos != null ? topPos : 50; // lazy equality for null\n\t\tconst $parent   = jQuery(window);\n\t\tconst dialogPos = { left : '', right : '', top : '', bottom : '' };\n\n\t\t// Unset the dialog's positional properties before checking its dimensions.\n\t\t_$dialog.css(dialogPos);\n\n\t\tlet horzSpace = $parent.width() - _$dialog.outerWidth(true) - 1;   // -1 to address a Firefox issue\n\t\tlet vertSpace = $parent.height() - _$dialog.outerHeight(true) - 1; // -1 to address a Firefox issue\n\n\t\tif (horzSpace <= 32 + _scrollbarWidth) {\n\t\t\tvertSpace -= _scrollbarWidth;\n\t\t}\n\n\t\tif (vertSpace <= 32 + _scrollbarWidth) {\n\t\t\thorzSpace -= _scrollbarWidth;\n\t\t}\n\n\t\tif (horzSpace <= 32) {\n\t\t\tdialogPos.left = dialogPos.right = 16;\n\t\t}\n\t\telse {\n\t\t\tdialogPos.left = dialogPos.right = horzSpace / 2 >> 0;\n\t\t}\n\n\t\tif (vertSpace <= 32) {\n\t\t\tdialogPos.top = dialogPos.bottom = 16;\n\t\t}\n\t\telse {\n\t\t\tif (vertSpace / 2 > top) {\n\t\t\t\tdialogPos.top = top;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdialogPos.top = dialogPos.bottom = vertSpace / 2 >> 0;\n\t\t\t}\n\t\t}\n\n\t\tObject.keys(dialogPos).forEach(key => {\n\t\t\tif (dialogPos[key] !== '') {\n\t\t\t\tdialogPos[key] += 'px';\n\t\t\t}\n\t\t});\n\n\t\treturn dialogPos;\n\t}\n\n\tfunction _resizeHandler(ev) {\n\t\tconst top = ev && ev.data && typeof ev.data.top !== 'undefined' ? ev.data.top : 50;\n\n\t\tif (_$dialog.css('display') === 'block') {\n\t\t\t// Stow the dialog.\n\t\t\t_$dialog.css({ display : 'none' });\n\n\t\t\t// Restore the dialog with its new positional properties.\n\t\t\t_$dialog.css(jQuery.extend({ display : '' }, _calcPosition(top)));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tappend : { value : dialogBodyAppend },\n\t\tbody   : { value : dialogBody },\n\t\tclose  : { value : dialogClose },\n\t\tinit   : { value : dialogInit },\n\t\tisOpen : { value : dialogIsOpen },\n\t\topen   : { value : dialogOpen },\n\t\tresize : { value : dialogResize },\n\t\tsetup  : { value : dialogSetup },\n\t\twiki   : { value : dialogBodyWiki },\n\n\t\t// Legacy Functions.\n\t\taddClickHandler : { value : dialogAddClickHandler }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tengine.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Config, DebugView, Dialog, Has, LoadScreen, Save, State, Story, StyleWrapper, UI, UIBar, Util,\n\t       Wikifier, postdisplay, postrender, predisplay, prehistory, prerender, setDisplayTitle\n*/\n\nvar Engine = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Engine state types object (pseudo-enumeration).\n\tconst States = Util.toEnum({\n\t\tIdle      : 'idle',\n\t\tPlaying   : 'playing',\n\t\tRendering : 'rendering'\n\t});\n\n\t// Minimum delay for DOM actions (in milliseconds).\n\tconst minDomActionDelay = 40;\n\n\t// Current state of the engine (default: `Engine.States.Idle`).\n\tlet _state = States.Idle;\n\n\t// Last time `enginePlay()` was called (in milliseconds).\n\tlet _lastPlay = null;\n\n\t// Cache of the debug view for the StoryInit special passage.\n\tlet _storyInitDebugView = null;\n\n\t// Cache of the outline patching <style> element (`StyleWrapper`-wrapped).\n\tlet _outlinePatch = null;\n\n\t// List of objects describing `StoryInterface` elements to update via passages during navigation.\n\tlet _updating = null;\n\n\n\t/*******************************************************************************************************************\n\t\tEngine Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tInitialize the core story elements and perform some bookkeeping.\n\t*/\n\tfunction engineInit() {\n\t\tif (DEBUG) { console.log('[Engine/engineInit()]'); }\n\n\t\t/*\n\t\t\tRemove #init-no-js & #init-lacking from #init-screen.\n\t\t*/\n\t\tjQuery('#init-no-js,#init-lacking').remove();\n\n\t\t/*\n\t\t\tGenerate the core story elements and insert them into the page before the store area.\n\t\t*/\n\t\t(() => {\n\t\t\tconst $elems = jQuery(document.createDocumentFragment());\n\t\t\tconst markup = Story.has('StoryInterface') && Story.get('StoryInterface').text.trim();\n\n\t\t\tif (markup) {\n\t\t\t\t// Remove the UI bar, its styles, and events.\n\t\t\t\tUIBar.destroy();\n\n\t\t\t\t// Remove the core display area styles.\n\t\t\t\tjQuery(document.head).find('#style-core-display').remove();\n\n\t\t\t\t$elems.append(markup);\n\n\t\t\t\tif ($elems.find('#passages').length === 0) {\n\t\t\t\t\tthrow new Error('no element with ID \"passages\" found within \"StoryInterface\" special passage');\n\t\t\t\t}\n\n\t\t\t\tconst updating = [];\n\n\t\t\t\t$elems.find('[data-passage]').each((i, el) => {\n\t\t\t\t\tif (el.id === 'passages') {\n\t\t\t\t\t\tthrow new Error(`\"StoryInterface\" element <${el.nodeName.toLowerCase()} id=\"passages\"> must not contain a \"data-passage\" content attribute`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst passage = el.getAttribute('data-passage').trim();\n\n\t\t\t\t\tif (el.firstElementChild !== null) {\n\t\t\t\t\t\tthrow new Error(`\"StoryInterface\" element <${el.nodeName.toLowerCase()} data-passage=\"${passage}\"> contains child elements`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tupdating.push({\n\t\t\t\t\t\t\tpassage,\n\t\t\t\t\t\t\telement : el\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (updating.length > 0) {\n\t\t\t\t\t_updating = updating;\n\t\t\t\t}\n\n\t\t\t\tConfig.ui.updateStoryElements = false;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$elems.append('<div id=\"story\" role=\"main\"><div id=\"passages\"></div></div>');\n\t\t\t}\n\n\t\t\t// Insert the core UI elements into the page before the main script.\n\t\t\t$elems.insertBefore('body>script#script-sugarcube');\n\t\t})();\n\n\t\t/*\n\t\t\tGenerate and cache the ARIA outlines <style> element (`StyleWrapper`-wrapped)\n\t\t\tand set up the handler to manipulate the outlines.\n\n\t\t\tIDEA: http://www.paciellogroup.com/blog/2012/04/how-to-remove-css-outlines-in-an-accessible-manner/\n\t\t*/\n\t\t_outlinePatch = new StyleWrapper((\n\t\t\t() => jQuery(document.createElement('style'))\n\t\t\t\t.attr({\n\t\t\t\t\tid   : 'style-aria-outlines',\n\t\t\t\t\ttype : 'text/css'\n\t\t\t\t})\n\t\t\t\t.appendTo(document.head)\n\t\t\t\t.get(0) // return the <style> element itself\n\t\t)());\n\t\tlet _lastOutlineEvent;\n\t\tjQuery(document).on(\n\t\t\t'mousedown.aria-outlines keydown.aria-outlines',\n\t\t\tev => {\n\t\t\t\tif (ev.type !== _lastOutlineEvent) {\n\t\t\t\t\t_lastOutlineEvent = ev.type;\n\n\t\t\t\t\tif (ev.type === 'keydown') {\n\t\t\t\t\t\t_showOutlines();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t_hideOutlines();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\t/*\n\t\tStarts the story.\n\t*/\n\tfunction engineStart() {\n\t\tif (DEBUG) { console.log('[Engine/engineStart()]'); }\n\n\t\t/*\n\t\t\tExecute the StoryInit special passage.\n\t\t*/\n\t\tif (Story.has('StoryInit')) {\n\t\t\ttry {\n\t\t\t\tconst debugBuffer = Wikifier.wikifyEval(Story.get('StoryInit').text);\n\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tconst debugView = new DebugView(\n\t\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t\t'special',\n\t\t\t\t\t\t'StoryInit',\n\t\t\t\t\t\t'StoryInit'\n\t\t\t\t\t);\n\t\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\t\tdebugView.append(debugBuffer);\n\t\t\t\t\t_storyInitDebugView = debugView.output;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('StoryInit', ex.message);\n\t\t\t}\n\t\t}\n\n\t\t// Sanity checks.\n\t\tif (Config.passages.start == null) { // lazy equality for null\n\t\t\tthrow new Error('starting passage not selected');\n\t\t}\n\t\tif (!Story.has(Config.passages.start)) {\n\t\t\tthrow new Error(`starting passage (\"${Config.passages.start}\") not found`);\n\t\t}\n\n\t\t// Focus the document element initially.\n\t\tjQuery(document.documentElement).focus();\n\n\t\t/*\n\t\t\tAttempt to restore an active session.  Failing that, attempt to autoload the autosave,\n\t\t\tif requested.  Failing that, display the starting passage.\n\t\t*/\n\t\tif (State.restore()) {\n\t\t\tengineShow();\n\t\t}\n\t\telse {\n\t\t\tlet loadStart = true;\n\n\t\t\tswitch (typeof Config.saves.autoload) {\n\t\t\tcase 'boolean':\n\t\t\t\tif (Config.saves.autoload && Save.autosave.ok() && Save.autosave.has()) {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\t\tloadStart = !Save.autosave.load();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'string':\n\t\t\t\tif (Config.saves.autoload === 'prompt' && Save.autosave.ok() && Save.autosave.has()) {\n\t\t\t\t\tloadStart = false;\n\t\t\t\t\tUI.buildAutoload();\n\t\t\t\t\tDialog.open();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'function':\n\t\t\t\tif (Save.autosave.ok() && Save.autosave.has() && !!Config.saves.autoload()) {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\t\tloadStart = !Save.autosave.load();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (loadStart) {\n\t\t\t\tif (DEBUG) { console.log(`\\tstarting passage: \"${Config.passages.start}\"`); }\n\n\t\t\t\tenginePlay(Config.passages.start);\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t\tRestarts the story.\n\t*/\n\tfunction engineRestart() {\n\t\tif (DEBUG) { console.log('[Engine/engineRestart()]'); }\n\n\t\t/*\n\t\t\tShow the loading screen to hide any unsightly rendering shenanigans during the\n\t\t\tpage reload.\n\t\t*/\n\t\tLoadScreen.show();\n\n\t\t/*\n\t\t\tScroll the window to the top.\n\n\t\t\tThis is required by most browsers for the starting passage or it will remain at\n\t\t\twhatever its current scroll position is after the page reload.  We do it generally,\n\t\t\trather than only for the currently set starting passage, since the starting passage\n\t\t\tmay be dynamically manipulated.\n\t\t*/\n\t\twindow.scroll(0, 0);\n\n\t\t/*\n\t\t\tDelete the active session.\n\t\t*/\n\t\tState.reset();\n\n\t\t/*\n\t\t\tTrigger an ':enginerestart' event.\n\t\t*/\n\t\tjQuery.event.trigger(':enginerestart');\n\n\t\t/*\n\t\t\tReload the page.\n\t\t*/\n\t\twindow.location.reload();\n\t}\n\n\t/*\n\t\tReturns the current state of the engine.\n\t*/\n\tfunction engineState() {\n\t\treturn _state;\n\t}\n\n\t/*\n\t\tReturns whether the engine is idle.\n\t*/\n\tfunction engineIsIdle() {\n\t\treturn _state === States.Idle;\n\t}\n\n\t/*\n\t\tReturns whether the engine is playing.\n\t*/\n\tfunction engineIsPlaying() {\n\t\treturn _state !== States.Idle;\n\t}\n\n\t/*\n\t\tReturns whether the engine is rendering.\n\t*/\n\tfunction engineIsRendering() {\n\t\treturn _state === States.Rendering;\n\t}\n\n\t/*\n\t\tReturns a timestamp representing the last time `Engine.play()` was called.\n\t*/\n\tfunction engineLastPlay() {\n\t\treturn _lastPlay;\n\t}\n\n\t/*\n\t\tActivate the moment at the given index within the state history and show it.\n\t*/\n\tfunction engineGoTo(idx) {\n\t\tconst succeded = State.goTo(idx);\n\n\t\tif (succeded) {\n\t\t\tengineShow();\n\t\t}\n\n\t\treturn succeded;\n\t}\n\n\t/*\n\t\tActivate the moment at the given offset from the active moment within the state history\n\t\tand show it.\n\t*/\n\tfunction engineGo(offset) {\n\t\tconst succeded = State.go(offset);\n\n\t\tif (succeded) {\n\t\t\tengineShow();\n\t\t}\n\n\t\treturn succeded;\n\t}\n\n\t/*\n\t\tGo to the moment which directly precedes the active moment and show it.\n\t*/\n\tfunction engineBackward() {\n\t\treturn engineGo(-1);\n\t}\n\n\t/*\n\t\tGo to the moment which directly follows the active moment and show it.\n\t*/\n\tfunction engineForward() {\n\t\treturn engineGo(1);\n\t}\n\n\t/*\n\t\tRenders and displays the active (present) moment's associated passage without adding\n\t\ta new moment to the history.\n\t*/\n\tfunction engineShow() {\n\t\treturn enginePlay(State.passage, true);\n\t}\n\n\t/*\n\t\tRenders and displays the passage referenced by the given title, optionally without\n\t\tadding a new moment to the history.\n\t*/\n\tfunction enginePlay(title, noHistory) {\n\t\tif (DEBUG) { console.log(`[Engine/enginePlay(title: \"${title}\", noHistory: ${noHistory})]`); }\n\n\t\tlet passageTitle = title;\n\n\t\t// Update the engine state.\n\t\t_state = States.Playing;\n\n\t\t// Reset the temporary state and variables objects.\n\t\tTempState = {}; // eslint-disable-line no-undef\n\t\tState.clearTemporary();\n\n\t\t// Debug view setup.\n\t\tlet passageReadyOutput;\n\t\tlet passageDoneOutput;\n\n\t\t// Execute the navigation override callback.\n\t\tif (typeof Config.navigation.override === 'function') {\n\t\t\ttry {\n\t\t\t\tconst overrideTitle = Config.navigation.override(passageTitle);\n\n\t\t\t\tif (overrideTitle) {\n\t\t\t\t\tpassageTitle = overrideTitle;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\t\t}\n\n\t\t// Retrieve the passage by the given title.\n\t\t//\n\t\t// NOTE: The values of the `title` parameter and `passageTitle` variable\n\t\t// may be empty, strings, or numbers (though using a number as reference\n\t\t// to a numeric title should be discouraged), so after loading the passage,\n\t\t// always refer to `passage.title` and never to the others.\n\t\tconst passage = Story.get(passageTitle);\n\n\t\t// Execute the pre-history events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype : ':passageinit',\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(prehistory).forEach(task => {\n\t\t\tif (typeof prehistory[task] === 'function') {\n\t\t\t\tprehistory[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\t// Create a new entry in the history.\n\t\tif (!noHistory) {\n\t\t\tState.create(passage.title);\n\t\t}\n\n\t\t// Clear the document body's classes.\n\t\tif (document.body.className) {\n\t\t\tdocument.body.className = '';\n\t\t}\n\n\t\t// Update the last play time.\n\t\t//\n\t\t// NOTE: This is mostly for event, task, and special passage code,\n\t\t// though the likelihood of it being needed this early is low.  This\n\t\t// will be updated again later at the end.\n\t\t_lastPlay = Util.now();\n\n\t\t// Execute pre-display tasks and the `PassageReady` special passage.\n\t\tObject.keys(predisplay).forEach(task => {\n\t\t\tif (typeof predisplay[task] === 'function') {\n\t\t\t\tpredisplay[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\tif (Story.has('PassageReady')) {\n\t\t\ttry {\n\t\t\t\tpassageReadyOutput = Wikifier.wikifyEval(Story.get('PassageReady').text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('PassageReady', ex.message);\n\t\t\t}\n\t\t}\n\n\t\t// Update the engine state.\n\t\t_state = States.Rendering;\n\n\t\t// Get the passage's tags as a string, or `null` if there aren't any.\n\t\tconst dataTags = passage.tags.length > 0 ? passage.tags.join(' ') : null;\n\n\t\t// Create and set up the incoming passage element.\n\t\tconst passageEl = document.createElement('div');\n\t\tjQuery(passageEl)\n\t\t\t.attr({\n\t\t\t\tid             : passage.domId,\n\t\t\t\t'data-passage' : passage.title,\n\t\t\t\t'data-tags'    : dataTags\n\t\t\t})\n\t\t\t.addClass(`passage ${passage.className}`);\n\n\t\t// Add the passage's classes and tags to the document body.\n\t\tjQuery(document.body)\n\t\t\t.attr('data-tags', dataTags)\n\t\t\t.addClass(passage.className);\n\n\t\t// Add the passage's tags to the document element.\n\t\tjQuery(document.documentElement)\n\t\t\t.attr('data-tags', dataTags);\n\n\t\t// Execute pre-render events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagestart',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(prerender).forEach(task => {\n\t\t\tif (typeof prerender[task] === 'function') {\n\t\t\t\tprerender[task].call(passage, passageEl, task);\n\t\t\t}\n\t\t});\n\n\t\t// Render the `PassageHeader` passage, if it exists, into the passage element.\n\t\tif (Story.has('PassageHeader')) {\n\t\t\tnew Wikifier(passageEl, Story.get('PassageHeader').processText());\n\t\t}\n\n\t\t// Render the passage into its element.\n\t\tpassageEl.appendChild(passage.render());\n\n\t\t// Render the `PassageFooter` passage, if it exists, into the passage element.\n\t\tif (Story.has('PassageFooter')) {\n\t\t\tnew Wikifier(passageEl, Story.get('PassageFooter').processText());\n\t\t}\n\n\t\t// Execute post-render events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagerender',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(postrender).forEach(task => {\n\t\t\tif (typeof postrender[task] === 'function') {\n\t\t\t\tpostrender[task].call(passage, passageEl, task);\n\t\t\t}\n\t\t});\n\n\t\t// Cache the passage container.\n\t\tconst containerEl = document.getElementById('passages');\n\n\t\t// Empty the passage container.\n\t\tif (containerEl.hasChildNodes()) {\n\t\t\tif (\n\t\t\t\t   typeof Config.passages.transitionOut === 'number'\n\t\t\t\t|| typeof Config.passages.transitionOut === 'string'\n\t\t\t\t&& Config.passages.transitionOut !== ''\n\t\t\t\t&& Has.transitionEndEvent\n\t\t\t) {\n\t\t\t\t[...containerEl.childNodes].forEach(outgoing => {\n\t\t\t\t\tconst $outgoing = jQuery(outgoing);\n\n\t\t\t\t\tif (outgoing.nodeType === Node.ELEMENT_NODE && $outgoing.hasClass('passage')) {\n\t\t\t\t\t\tif ($outgoing.hasClass('passage-out')) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$outgoing\n\t\t\t\t\t\t\t.attr('id', `out-${$outgoing.attr('id')}`)\n\t\t\t\t\t\t\t.addClass('passage-out');\n\n\t\t\t\t\t\tif (typeof Config.passages.transitionOut === 'string') {\n\t\t\t\t\t\t\t$outgoing.on(Has.transitionEndEvent, ev => {\n\t\t\t\t\t\t\t\tif (ev.originalEvent.propertyName === Config.passages.transitionOut) {\n\t\t\t\t\t\t\t\t\t$outgoing.remove();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tsetTimeout(\n\t\t\t\t\t\t\t\t() => $outgoing.remove(),\n\t\t\t\t\t\t\t\tMath.max(minDomActionDelay, Config.passages.transitionOut)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t$outgoing.remove();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery(containerEl).empty();\n\t\t\t}\n\t\t}\n\n\t\t// Append the passage element to the passage container and set up its transition.\n\t\tjQuery(passageEl)\n\t\t\t.addClass('passage-in')\n\t\t\t.appendTo(containerEl);\n\t\tsetTimeout(() => jQuery(passageEl).removeClass('passage-in'), minDomActionDelay);\n\n\t\t// Update the story display title, if necessary.\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\t// NOTE: We don't have an `else` here because that case will be handled later (below).\n\t\t\tif (_updating !== null || !Config.ui.updateStoryElements) {\n\t\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t\t}\n\t\t}\n\t\telse if (Config.passages.displayTitles && passage.title !== Config.passages.start) {\n\t\t\tdocument.title = `${passage.title} | ${Story.title}`;\n\t\t}\n\n\t\t// Scroll the window to the top.\n\t\twindow.scroll(0, 0);\n\n\t\t// Update the engine state.\n\t\t_state = States.Playing;\n\n\t\t// Execute post-display events, tasks, and the `PassageDone` special passage.\n\t\tif (Story.has('PassageDone')) {\n\t\t\ttry {\n\t\t\t\tpassageDoneOutput = Wikifier.wikifyEval(Story.get('PassageDone').text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('PassageDone', ex.message);\n\t\t\t}\n\t\t}\n\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagedisplay',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(postdisplay).forEach(task => {\n\t\t\tif (typeof postdisplay[task] === 'function') {\n\t\t\t\tpostdisplay[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\t// Update the other interface elements, if necessary.\n\t\tif (_updating !== null) {\n\t\t\t_updating.forEach(pair => {\n\t\t\t\tjQuery(pair.element).empty();\n\t\t\t\tnew Wikifier(pair.element, Story.get(pair.passage).processText().trim());\n\t\t\t});\n\t\t}\n\t\telse if (Config.ui.updateStoryElements) {\n\t\t\tUIBar.update();\n\t\t}\n\n\t\t// Add the completed debug views for `StoryInit`, `PassageReady`, and `PassageDone`\n\t\t// to the incoming passage element.\n\t\tif (Config.debug) {\n\t\t\tlet debugView;\n\n\t\t\t// Prepend the `PassageReady` debug view.\n\t\t\tif (passageReadyOutput != null) { // lazy equality for null\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t'special',\n\t\t\t\t\t'PassageReady',\n\t\t\t\t\t'PassageReady'\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\tdebugView.append(passageReadyOutput);\n\t\t\t\tjQuery(passageEl).prepend(debugView.output);\n\t\t\t}\n\n\t\t\t// Append the `PassageDone` debug view.\n\t\t\tif (passageDoneOutput != null) { // lazy equality for null\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t'special',\n\t\t\t\t\t'PassageDone',\n\t\t\t\t\t'PassageDone'\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\tdebugView.append(passageDoneOutput);\n\t\t\t\tjQuery(passageEl).append(debugView.output);\n\t\t\t}\n\n\t\t\t// Prepend the cached `StoryInit` debug view, if we're showing the first moment/turn.\n\t\t\tif (State.turns === 1 && _storyInitDebugView != null) { // lazy equality for null\n\t\t\t\tjQuery(passageEl).prepend(_storyInitDebugView);\n\t\t\t}\n\t\t}\n\n\t\t// Last second post-processing for accessibility and other things.\n\t\t_hideOutlines(); // initially hide outlines\n\t\tjQuery('#story')\n\t\t\t// Add `link-external` to all `href` bearing `<a>` elements which don't have it.\n\t\t\t.find('a[href]:not(.link-external)')\n\t\t\t.addClass('link-external')\n\t\t\t.end()\n\t\t\t// Add `tabindex=0` to all interactive elements which don't have it.\n\t\t\t.find('a,link,button,input,select,textarea')\n\t\t\t.not('[tabindex]')\n\t\t\t.attr('tabindex', 0);\n\n\t\t// Handle autosaves.\n\t\tswitch (typeof Config.saves.autosave) {\n\t\tcase 'boolean':\n\t\t\tif (Config.saves.autosave) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'object':\n\t\t\tif (passage.tags.some(tag => Config.saves.autosave.includes(tag))) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'function':\n\t\t\tif (Config.saves.autosave()) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// Execute post-play events.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passageend',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\n\t\t// Reset the engine state.\n\t\t_state = States.Idle;\n\n\t\t// Update the last play time.\n\t\t_lastPlay = Util.now();\n\n\t\treturn passageEl;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tLegacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Play the given passage, optionally without altering the history.\n\t*/\n\tfunction engineDisplay(title, link, option) {\n\t\tif (DEBUG) { console.log('[Engine/engineDisplay()]'); }\n\n\t\tlet noHistory = false;\n\n\t\t// Process the option parameter.\n\t\tswitch (option) {\n\t\tcase undefined:\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'replace':\n\t\tcase 'back':\n\t\t\tnoHistory = true;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new Error(`Engine.display option parameter called with obsolete value \"${option}\"; please notify the developer`);\n\t\t}\n\n\t\tenginePlay(title, noHistory);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _hideOutlines() {\n\t\t_outlinePatch.set('*:focus{outline:none;}');\n\t}\n\n\tfunction _showOutlines() {\n\t\t_outlinePatch.clear();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tConstants.\n\t\t*/\n\t\tStates            : { value : States },\n\t\tminDomActionDelay : { value : minDomActionDelay },\n\n\t\t/*\n\t\t\tCore Functions.\n\t\t*/\n\t\tinit        : { value : engineInit },\n\t\tstart       : { value : engineStart },\n\t\trestart     : { value : engineRestart },\n\t\tstate       : { get : engineState },\n\t\tisIdle      : { value : engineIsIdle },\n\t\tisPlaying   : { value : engineIsPlaying },\n\t\tisRendering : { value : engineIsRendering },\n\t\tlastPlay    : { get : engineLastPlay },\n\t\tgoTo        : { value : engineGoTo },\n\t\tgo          : { value : engineGo },\n\t\tbackward    : { value : engineBackward },\n\t\tforward     : { value : engineForward },\n\t\tshow        : { value : engineShow },\n\t\tplay        : { value : enginePlay },\n\n\t\t/*\n\t\t\tLegacy Functions.\n\t\t*/\n\t\tdisplay : { value : engineDisplay }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tpassage.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, L10n, Util, Wikifier */\n\nvar Passage = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tlet _tagsToSkip;\n\tlet _twine1Unescape;\n\n\t/*\n\t\tTags which should not be transformed into classes:\n\t\t\tdebug      → special tag\n\t\t\tnobr       → special tag\n\t\t\tpassage    → the default class\n\t\t\tscript     → special tag (only in Twine 1)\n\t\t\tstylesheet → special tag (only in Twine 1)\n\t\t\ttwine.*    → special tag\n\t\t\twidget     → special tag\n\t*/\n\t// For Twine 1\n\tif (TWINE1) {\n\t\t_tagsToSkip = /^(?:debug|nobr|passage|script|stylesheet|widget|twine\\..*)$/i;\n\t}\n\t// For Twine 2\n\telse {\n\t\t_tagsToSkip = /^(?:debug|nobr|passage|widget|twine\\..*)$/i;\n\t}\n\n\t// For Twine 1\n\tif (TWINE1) {\n\t\t/*\n\t\t\tReturns a decoded version of the passed Twine 1 passage store encoded string.\n\t\t*/\n\t\tconst _twine1EscapesRe    = /(?:\\\\n|\\\\t|\\\\s|\\\\|\\r)/g;\n\t\tconst _hasTwine1EscapesRe = new RegExp(_twine1EscapesRe.source); // to drop the global flag\n\t\tconst _twine1EscapesMap   = Object.freeze({\n\t\t\t'\\\\n' : '\\n',\n\t\t\t'\\\\t' : '\\t',\n\t\t\t'\\\\s' : '\\\\',\n\t\t\t'\\\\'  : '\\\\',\n\t\t\t'\\r'  : ''\n\t\t});\n\n\t\t_twine1Unescape = function (str) {\n\t\t\tif (str == null) { // lazy equality for null\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tconst val = String(str);\n\t\t\treturn val && _hasTwine1EscapesRe.test(val)\n\t\t\t\t? val.replace(_twine1EscapesRe, esc => _twine1EscapesMap[esc])\n\t\t\t\t: val;\n\t\t};\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPassage Class.\n\t*******************************************************************************************************************/\n\tclass Passage {\n\t\tconstructor(title, el) {\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// Passage title/ID.\n\t\t\t\ttitle : {\n\t\t\t\t\tvalue : Util.unescape(title)\n\t\t\t\t},\n\n\t\t\t\t// Passage data element (within the story data element; i.e. T1: '[tiddler]', T2: 'tw-passagedata').\n\t\t\t\telement : {\n\t\t\t\t\tvalue : el || null\n\t\t\t\t},\n\n\t\t\t\t// Passage tags array (sorted and unique).\n\t\t\t\ttags : {\n\t\t\t\t\tvalue : Object.freeze(el && el.hasAttribute('tags')\n\t\t\t\t\t\t? el.getAttribute('tags')\n\t\t\t\t\t\t\t.trim()\n\t\t\t\t\t\t\t.splitOrEmpty(/\\s+/)\n\t\t\t\t\t\t\t.sort()\n\t\t\t\t\t\t\t.filter((tag, i, aref) => i === 0 || aref[i - 1] !== tag)\n\t\t\t\t\t\t: [])\n\t\t\t\t},\n\n\t\t\t\t// Passage excerpt.  Used by the `description()` method.\n\t\t\t\t_excerpt : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Properties dependant upon the above set.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// Passage DOM-compatible ID.\n\t\t\t\tdomId : {\n\t\t\t\t\tvalue : `passage-${Util.slugify(this.title)}`\n\t\t\t\t},\n\n\t\t\t\t// Passage classes array (sorted and unique).\n\t\t\t\tclasses : {\n\t\t\t\t\tvalue : Object.freeze(this.tags.length === 0 ? [] : (() =>\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tReturn the sorted list of unique classes.\n\n\t\t\t\t\t\t\tNOTE: The `this.tags` array is already sorted and unique,\n\t\t\t\t\t\t\tso we only need to filter and map here.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tthis.tags\n\t\t\t\t\t\t\t.filter(tag => !_tagsToSkip.test(tag))\n\t\t\t\t\t\t\t.map(tag => Util.slugify(tag))\n\t\t\t\t\t)())\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// Getters.\n\t\tget className() {\n\t\t\treturn this.classes.join(' ');\n\t\t}\n\n\t\t// TODO: (v3) This should be → `get source`.\n\t\tget text() {\n\t\t\tif (this.element == null) { // lazy equality for null\n\t\t\t\tconst passage = Util.escape(this.title);\n\t\t\t\tconst mesg    = `${L10n.get('errorTitle')}: ${L10n.get('errorNonexistentPassage', { passage })}`;\n\t\t\t\treturn `<div class=\"error-view\"><span class=\"error\">${mesg}</span></div>`;\n\t\t\t}\n\n\t\t\t// For Twine 1\n\t\t\tif (TWINE1) {\n\t\t\t\treturn _twine1Unescape(this.element.textContent);\n\t\t\t}\n\t\t\t// For Twine 2\n\t\t\telse { // eslint-disable-line no-else-return\n\t\t\t\treturn this.element.textContent.replace(/\\r/g, '');\n\t\t\t}\n\t\t}\n\n\t\tdescription() {\n\t\t\tconst descriptions = Config.passages.descriptions;\n\n\t\t\tif (descriptions != null) { // lazy equality for null\n\t\t\t\tswitch (typeof descriptions) {\n\t\t\t\tcase 'boolean':\n\t\t\t\t\tif (descriptions) {\n\t\t\t\t\t\treturn this.title;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\tif (descriptions instanceof Map && descriptions.has(this.title)) {\n\t\t\t\t\t\treturn descriptions.get(this.title);\n\t\t\t\t\t}\n\t\t\t\t\telse if (descriptions.hasOwnProperty(this.title)) {\n\t\t\t\t\t\treturn descriptions[this.title];\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'function':\n\t\t\t\t\t{\n\t\t\t\t\t\tconst result = descriptions.call(this);\n\n\t\t\t\t\t\tif (result) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new TypeError('Config.passages.descriptions must be a boolean, object, or function');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Initialize the excerpt cache from the raw passage text, if necessary.\n\t\t\tif (this._excerpt === null) {\n\t\t\t\tthis._excerpt = Passage.getExcerptFromText(this.text);\n\t\t\t}\n\n\t\t\treturn this._excerpt;\n\t\t}\n\n\t\t// TODO: (v3) This should be → `get text`.\n\t\tprocessText() {\n\t\t\tif (this.element == null) { // lazy equality for null\n\t\t\t\treturn this.text;\n\t\t\t}\n\n\t\t\t// Handle image passage transclusion.\n\t\t\tif (this.tags.includes('Twine.image')) {\n\t\t\t\treturn `[img[${this.text}]]`;\n\t\t\t}\n\n\t\t\tlet processed = this.text;\n\n\t\t\t// Handle `Config.passages.onProcess`.\n\t\t\tif (Config.passages.onProcess) {\n\t\t\t\tprocessed = Config.passages.onProcess.call(null, {\n\t\t\t\t\ttitle : this.title,\n\t\t\t\t\ttags  : this.tags,\n\t\t\t\t\ttext  : processed\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Handle `Config.passages.nobr` and the `nobr` tag.\n\t\t\tif (Config.passages.nobr || this.tags.includes('nobr')) {\n\t\t\t\t// Remove all leading & trailing newlines and compact all internal sequences\n\t\t\t\t// of newlines into single spaces.\n\t\t\t\tprocessed = processed.replace(/^\\n+|\\n+$/g, '').replace(/\\n+/g, ' ');\n\t\t\t}\n\n\t\t\treturn processed;\n\t\t}\n\n\t\trender(options) {\n\t\t\t// Wikify the passage into a document fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, this.processText(), options);\n\n\t\t\t// Update the excerpt cache to reflect the rendered text, if we need it for the passage description\n\t\t\tif (Config.passages.descriptions == null) {\n\t\t\t\tthis._excerpt = Passage.getExcerptFromNode(frag);\n\t\t\t}\n\n\t\t\treturn frag;\n\t\t}\n\n\t\tstatic getExcerptFromNode(node, count) {\n\t\t\tif (!node.hasChildNodes()) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tlet excerpt = node.textContent.trim();\n\n\t\t\tif (excerpt !== '') {\n\t\t\t\tconst excerptRe = new RegExp(`(\\\\S+(?:\\\\s+\\\\S+){0,${count > 0 ? count - 1 : 7}})`);\n\t\t\t\texcerpt = excerpt\n\t\t\t\t\t// Compact whitespace.\n\t\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t\t// Attempt to match the excerpt regexp.\n\t\t\t\t\t.match(excerptRe);\n\t\t\t}\n\n\t\t\treturn excerpt ? `${excerpt[1]}\\u2026` : '\\u2026'; // horizontal ellipsis\n\t\t}\n\n\t\tstatic getExcerptFromText(text, count) {\n\t\t\tif (text === '') {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tconst excerptRe = new RegExp(`(\\\\S+(?:\\\\s+\\\\S+){0,${count > 0 ? count - 1 : 7}})`);\n\t\t\tconst excerpt   = text\n\t\t\t\t// Strip macro tags (replace with a space).\n\t\t\t\t.replace(/<<.*?>>/g, ' ')\n\t\t\t\t// Strip html tags (replace with a space).\n\t\t\t\t.replace(/<.*?>/g, ' ')\n\t\t\t\t// The above might have left problematic whitespace, so trim.\n\t\t\t\t.trim()\n\t\t\t\t// Strip table markup.\n\t\t\t\t.replace(/^\\s*\\|.*\\|.*?$/gm, '')\n\t\t\t\t// Strip image markup.\n\t\t\t\t.replace(/\\[[<>]?img\\[[^\\]]*\\]\\]/g, '')\n\t\t\t\t// Clean link markup (remove all but the link text).\n\t\t\t\t.replace(/\\[\\[([^|\\]]*?)(?:(?:\\||->|<-)[^\\]]*)?\\]\\]/g, '$1')\n\t\t\t\t// Clean heading markup.\n\t\t\t\t.replace(/^\\s*!+(.*?)$/gm, '$1')\n\t\t\t\t// Clean bold/italic/underline/highlight styles.\n\t\t\t\t.replace(/'{2}|\\/{2}|_{2}|@{2}/g, '')\n\t\t\t\t// A final trim.\n\t\t\t\t.trim()\n\t\t\t\t// Compact whitespace.\n\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t// Attempt to match the excerpt regexp.\n\t\t\t\t.match(excerptRe);\n\t\t\treturn excerpt ? `${excerpt[1]}\\u2026` : '\\u2026'; // horizontal ellipsis\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Passage;\n})();\n\n/***********************************************************************************************************************\n\n\tsave.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Dialog, Engine, L10n, State, Story, UI, storage */\n\nvar Save = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// The upper bound of the saves slots.\n\tlet _slotsUBound = -1;\n\n\n\t/*******************************************************************************************************************\n\t\tSaves Functions.\n\t*******************************************************************************************************************/\n\tfunction savesInit() {\n\t\tif (DEBUG) { console.log('[Save/savesInit()]'); }\n\n\t\t// Disable save slots and the autosave when Web Storage is unavailable.\n\t\tif (storage.name === 'cookie') {\n\t\t\tsavesObjClear();\n\t\t\tConfig.saves.autoload = undefined;\n\t\t\tConfig.saves.autosave = undefined;\n\t\t\tConfig.saves.slots = 0;\n\t\t\treturn false;\n\t\t}\n\n\t\tlet saves   = savesObjGet();\n\t\tlet updated = false;\n\n\t\t/* legacy */\n\t\t// Convert an ancient saves array into a new saves object.\n\t\tif (Array.isArray(saves)) {\n\t\t\tsaves = {\n\t\t\t\tautosave : null,\n\t\t\t\tslots    : saves\n\t\t\t};\n\t\t\tupdated = true;\n\t\t}\n\t\t/* /legacy */\n\n\t\t// Handle the author changing the number of save slots.\n\t\tif (Config.saves.slots !== saves.slots.length) {\n\t\t\tif (Config.saves.slots < saves.slots.length) {\n\t\t\t\t// Attempt to decrease the number of slots; this will only compact\n\t\t\t\t// the slots array, by removing empty slots, no saves will be deleted.\n\t\t\t\tsaves.slots.reverse();\n\n\t\t\t\tsaves.slots = saves.slots.filter(function (val) {\n\t\t\t\t\tif (val === null && this.count > 0) {\n\t\t\t\t\t\t--this.count;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\t\t\t\t}, { count : saves.slots.length - Config.saves.slots });\n\n\t\t\t\tsaves.slots.reverse();\n\t\t\t}\n\t\t\telse if (Config.saves.slots > saves.slots.length) {\n\t\t\t\t// Attempt to increase the number of slots.\n\t\t\t\t_appendSlots(saves.slots, Config.saves.slots - saves.slots.length);\n\t\t\t}\n\n\t\t\tupdated = true;\n\t\t}\n\n\t\t/* legacy */\n\t\t// Update saves with old/obsolete properties.\n\t\tif (_savesObjUpdate(saves.autosave)) {\n\t\t\tupdated = true;\n\t\t}\n\n\t\tfor (let i = 0; i < saves.slots.length; ++i) {\n\t\t\tif (_savesObjUpdate(saves.slots[i])) {\n\t\t\t\tupdated = true;\n\t\t\t}\n\t\t}\n\n\t\t// Remove save stores which are empty.\n\t\tif (_savesObjIsEmpty(saves)) {\n\t\t\tstorage.delete('saves');\n\t\t\tupdated = false;\n\t\t}\n\t\t/* /legacy */\n\n\t\t// If the saves object was updated, then update the store.\n\t\tif (updated) {\n\t\t\t_savesObjSave(saves);\n\t\t}\n\n\t\t_slotsUBound = saves.slots.length - 1;\n\n\t\treturn true;\n\t}\n\n\tfunction savesObjCreate() {\n\t\treturn {\n\t\t\tautosave : null,\n\t\t\tslots    : _appendSlots([], Config.saves.slots)\n\t\t};\n\t}\n\n\tfunction savesObjGet() {\n\t\tconst saves = storage.get('saves');\n\t\treturn saves === null ? savesObjCreate() : saves;\n\t}\n\n\tfunction savesObjClear() {\n\t\tstorage.delete('saves');\n\t\treturn true;\n\t}\n\n\tfunction savesOk() {\n\t\treturn autosaveOk() || slotsOk();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAutosave Functions.\n\t*******************************************************************************************************************/\n\tfunction autosaveOk() {\n\t\treturn storage.name !== 'cookie' && typeof Config.saves.autosave !== 'undefined';\n\t}\n\n\tfunction autosaveHas() {\n\t\tconst saves = savesObjGet();\n\n\t\tif (saves.autosave === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction autosaveGet() {\n\t\tconst saves = savesObjGet();\n\t\treturn saves.autosave;\n\t}\n\n\tfunction autosaveLoad() {\n\t\tconst saves = savesObjGet();\n\n\t\tif (saves.autosave === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn _unmarshal(saves.autosave);\n\t}\n\n\tfunction autosaveSave(title, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves        = savesObjGet();\n\t\tconst supplemental = {\n\t\t\ttitle : title || Story.get(State.passage).description(),\n\t\t\tdate  : Date.now()\n\t\t};\n\n\t\tif (metadata != null) { // lazy equality for null\n\t\t\tsupplemental.metadata = metadata;\n\t\t}\n\n\t\tsaves.autosave = _marshal(supplemental);\n\n\t\treturn _savesObjSave(saves);\n\t}\n\n\tfunction autosaveDelete() {\n\t\tconst saves = savesObjGet();\n\t\tsaves.autosave = null;\n\t\treturn _savesObjSave(saves);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSlots Functions.\n\t*******************************************************************************************************************/\n\tfunction slotsOk() {\n\t\treturn storage.name !== 'cookie' && _slotsUBound !== -1;\n\t}\n\n\tfunction slotsLength() {\n\t\treturn _slotsUBound + 1;\n\t}\n\n\tfunction slotsCount() {\n\t\tif (!slotsOk()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\t\tlet count = 0;\n\n\t\tfor (let i = 0, iend = saves.slots.length; i < iend; ++i) {\n\t\t\tif (saves.slots[i] !== null) {\n\t\t\t\t++count;\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n\n\tfunction slotsIsEmpty() {\n\t\treturn slotsCount() === 0;\n\t}\n\n\tfunction slotsHas(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length || saves.slots[slot] === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction slotsGet(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn saves.slots[slot];\n\t}\n\n\tfunction slotsLoad(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length || saves.slots[slot] === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn _unmarshal(saves.slots[slot]);\n\t}\n\n\tfunction slotsSave(slot, title, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst supplemental = {\n\t\t\ttitle : title || Story.get(State.passage).description(),\n\t\t\tdate  : Date.now()\n\t\t};\n\n\t\tif (metadata != null) { // lazy equality for null\n\t\t\tsupplemental.metadata = metadata;\n\t\t}\n\n\t\tsaves.slots[slot] = _marshal(supplemental);\n\n\t\treturn _savesObjSave(saves);\n\t}\n\n\tfunction slotsDelete(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tsaves.slots[slot] = null;\n\t\treturn _savesObjSave(saves);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tDisk Import/Export Functions.\n\t*******************************************************************************************************************/\n\tfunction exportToDisk(filename, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tfunction datestamp() {\n\t\t\tconst now = new Date();\n\t\t\tlet MM = now.getMonth() + 1;\n\t\t\tlet DD = now.getDate();\n\t\t\tlet hh = now.getHours();\n\t\t\tlet mm = now.getMinutes();\n\t\t\tlet ss = now.getSeconds();\n\n\t\t\tif (MM < 10) { MM = `0${MM}`; }\n\t\t\tif (DD < 10) { DD = `0${DD}`; }\n\t\t\tif (hh < 10) { hh = `0${hh}`; }\n\t\t\tif (mm < 10) { mm = `0${mm}`; }\n\t\t\tif (ss < 10) { ss = `0${ss}`; }\n\n\t\t\treturn `${now.getFullYear()}${MM}${DD}-${hh}${mm}${ss}`;\n\t\t}\n\n\t\tfunction legalizeName(str) {\n\t\t\t/*\n\t\t\t\tNOTE: The range of illegal characters consists of: C0 controls, double quote,\n\t\t\t\tnumber, dollar, percent, ampersand, single quote, asterisk, plus, comma,\n\t\t\t\tforward slash, colon, semi-colon, less-than, equals, greater-than, question,\n\t\t\t\tbackslash, caret, backquote/grave, pipe/vertical-bar, delete, C1 controls.\n\t\t\t*/\n\t\t\treturn String(str).trim()\n\t\t\t\t.replace(/[\\x00-\\x1f\"#$%&'*+,/:;<=>?\\\\^`|\\x7f-\\x9f]+/g, '') // eslint-disable-line no-control-regex\n\t\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-'); // legacy\n\t\t}\n\n\t\tconst baseName     = filename == null ? Story.domId : legalizeName(filename); // lazy equality for null\n\t\tconst saveName     = `${baseName}-${datestamp()}.save`;\n\t\tconst supplemental = metadata == null ? {} : { metadata }; // lazy equality for null\n\t\tconst saveObj      = LZString.compressToBase64(JSON.stringify(_marshal(supplemental)));\n\t\tsaveAs(new Blob([saveObj], { type : 'text/plain;charset=UTF-8' }), saveName);\n\t}\n\n\tfunction importFromDisk(event) {\n\t\tconst file   = event.target.files[0];\n\t\tconst reader = new FileReader();\n\n\t\t// Add the handler that will capture the file information once the load is finished.\n\t\tjQuery(reader).on('load', ev => {\n\t\t\tconst target = ev.currentTarget;\n\n\t\t\tif (!target.result) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet saveObj;\n\n\t\t\ttry {\n\t\t\t\tsaveObj = JSON.parse(\n\t\t\t\t\t/* legacy */ /\\.json$/i.test(file.name) || /^\\{/.test(target.result)\n\t\t\t\t\t\t? target.result\n\t\t\t\t\t\t: /* /legacy */ LZString.decompressFromBase64(target.result)\n\t\t\t\t);\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op; `_unmarshal()` will handle the error */ }\n\n\t\t\t_unmarshal(saveObj);\n\t\t});\n\n\t\t// Initiate the file load.\n\t\treader.readAsText(file);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSerialization Functions.\n\t*******************************************************************************************************************/\n\tfunction serialize(metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tconst supplemental = metadata == null ? {} : { metadata }; // lazy equality for null\n\t\treturn LZString.compressToBase64(JSON.stringify(_marshal(supplemental)));\n\t}\n\n\tfunction deserialize(base64Str) {\n\t\t/*\n\t\t\tNOTE: We purposefully do not attempt to catch parameter shenanigans\n\t\t\there, instead relying on `_unmarshal()` to do the heavy lifting.\n\t\t*/\n\n\t\tlet saveObj;\n\n\t\ttry {\n\t\t\tsaveObj = JSON.parse(LZString.decompressFromBase64(base64Str));\n\t\t}\n\t\tcatch (ex) { /* no-op; `_unmarshal()` will handle the error */ }\n\n\t\tif (!_unmarshal(saveObj)) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn saveObj.metadata;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _appendSlots(array, num) {\n\t\tfor (let i = 0; i < num; ++i) {\n\t\t\tarray.push(null);\n\t\t}\n\n\t\treturn array;\n\t}\n\n\tfunction _savesObjIsEmpty(saves) {\n\t\tconst slots = saves.slots;\n\t\tlet isSlotsEmpty = true;\n\n\t\tfor (let i = 0, iend = slots.length; i < iend; ++i) {\n\t\t\tif (slots[i] !== null) {\n\t\t\t\tisSlotsEmpty = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn saves.autosave === null && isSlotsEmpty;\n\t}\n\n\tfunction _savesObjSave(saves) {\n\t\tif (_savesObjIsEmpty(saves)) {\n\t\t\tstorage.delete('saves');\n\t\t\treturn true;\n\t\t}\n\n\t\treturn storage.set('saves', saves);\n\t}\n\n\tfunction _savesObjUpdate(saveObj) {\n\t\tif (saveObj == null || typeof saveObj !== 'object') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tlet updated = false;\n\n\t\t/* eslint-disable no-param-reassign */\n\t\tif (\n\t\t\t   !saveObj.hasOwnProperty('state')\n\t\t\t|| !saveObj.state.hasOwnProperty('delta')\n\t\t\t|| !saveObj.state.hasOwnProperty('index')\n\t\t) {\n\t\t\tif (saveObj.hasOwnProperty('data')) {\n\t\t\t\tdelete saveObj.mode;\n\t\t\t\tsaveObj.state = {\n\t\t\t\t\tdelta : State.deltaEncode(saveObj.data)\n\t\t\t\t};\n\t\t\t\tdelete saveObj.data;\n\t\t\t}\n\t\t\telse if (!saveObj.state.hasOwnProperty('delta')) {\n\t\t\t\tdelete saveObj.state.mode;\n\t\t\t\tsaveObj.state.delta = State.deltaEncode(saveObj.state.history);\n\t\t\t\tdelete saveObj.state.history;\n\t\t\t}\n\t\t\telse if (!saveObj.state.hasOwnProperty('index')) {\n\t\t\t\tdelete saveObj.state.mode;\n\t\t\t}\n\n\t\t\tsaveObj.state.index = saveObj.state.delta.length - 1;\n\t\t\tupdated = true;\n\t\t}\n\n\t\tif (saveObj.state.hasOwnProperty('rseed')) {\n\t\t\tsaveObj.state.seed = saveObj.state.rseed;\n\t\t\tdelete saveObj.state.rseed;\n\n\t\t\tsaveObj.state.delta.forEach((_, i, delta) => {\n\t\t\t\tif (delta[i].hasOwnProperty('rcount')) {\n\t\t\t\t\tdelta[i].pull = delta[i].rcount;\n\t\t\t\t\tdelete delta[i].rcount;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tupdated = true;\n\t\t}\n\n\t\tif (\n\t\t\t   saveObj.state.hasOwnProperty('expired') && typeof saveObj.state.expired === 'number'\n\t\t\t||  saveObj.state.hasOwnProperty('unique')\n\t\t\t||  saveObj.state.hasOwnProperty('last')\n\t\t) {\n\t\t\tif (saveObj.state.hasOwnProperty('expired') && typeof saveObj.state.expired === 'number') {\n\t\t\t\tdelete saveObj.state.expired;\n\t\t\t}\n\n\t\t\tif (saveObj.state.hasOwnProperty('unique') || saveObj.state.hasOwnProperty('last')) {\n\t\t\t\tsaveObj.state.expired = [];\n\n\t\t\t\tif (saveObj.state.hasOwnProperty('unique')) {\n\t\t\t\t\tsaveObj.state.expired.push(saveObj.state.unique);\n\t\t\t\t\tdelete saveObj.state.unique;\n\t\t\t\t}\n\n\t\t\t\tif (saveObj.state.hasOwnProperty('last')) {\n\t\t\t\t\tsaveObj.state.expired.push(saveObj.state.last);\n\t\t\t\t\tdelete saveObj.state.last;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tupdated = true;\n\t\t}\n\t\t/* eslint-enable no-param-reassign */\n\n\t\treturn updated;\n\t}\n\n\tfunction _marshal(supplemental) {\n\t\tif (DEBUG) { console.log('[Save/_marshal()]'); }\n\n\t\tif (supplemental != null && typeof supplemental !== 'object') { // lazy equality for null\n\t\t\tthrow new Error('supplemental parameter must be an object');\n\t\t}\n\n\t\tconst saveObj = Object.assign({}, supplemental, {\n\t\t\tid    : Config.saves.id,\n\t\t\tstate : State.marshalForSave()\n\t\t});\n\n\t\tif (Config.saves.version) {\n\t\t\tsaveObj.version = Config.saves.version;\n\t\t}\n\n\t\tif (typeof Config.saves.onSave === 'function') {\n\t\t\tConfig.saves.onSave(saveObj);\n\t\t}\n\n\t\t// Delta encode the state history and delete the non-encoded property.\n\t\tsaveObj.state.delta = State.deltaEncode(saveObj.state.history);\n\t\tdelete saveObj.state.history;\n\n\t\treturn saveObj;\n\t}\n\n\tfunction _unmarshal(saveObj) {\n\t\tif (DEBUG) { console.log('[Save/_unmarshal()]'); }\n\n\t\ttry {\n\t\t\t/* eslint-disable no-param-reassign */\n\t\t\t/* legacy */\n\t\t\t// Update saves with old/obsolete properties.\n\t\t\t_savesObjUpdate(saveObj);\n\t\t\t/* /legacy */\n\n\t\t\tif (!saveObj || !saveObj.hasOwnProperty('id') || !saveObj.hasOwnProperty('state')) {\n\t\t\t\tthrow new Error(L10n.get('errorSaveMissingData'));\n\t\t\t}\n\n\t\t\t// Delta decode the state history and delete the encoded property.\n\t\t\tsaveObj.state.history = State.deltaDecode(saveObj.state.delta);\n\t\t\tdelete saveObj.state.delta;\n\n\t\t\tif (typeof Config.saves.onLoad === 'function') {\n\t\t\t\tConfig.saves.onLoad(saveObj);\n\t\t\t}\n\n\t\t\tif (saveObj.id !== Config.saves.id) {\n\t\t\t\tthrow new Error(L10n.get('errorSaveIdMismatch'));\n\t\t\t}\n\n\t\t\t// Restore the state.\n\t\t\tState.unmarshalForSave(saveObj.state); // may also throw exceptions\n\n\t\t\t// Show the active moment.\n\t\t\tEngine.show();\n\t\t\t/* eslint-enable no-param-reassign */\n\t\t}\n\t\tcatch (ex) {\n\t\t\tUI.alert(`${ex.message.toUpperFirst()}.</p><p>${L10n.get('aborting')}.`);\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tSave Functions.\n\t\t*/\n\t\tinit  : { value : savesInit },\n\t\tget   : { value : savesObjGet },\n\t\tclear : { value : savesObjClear },\n\t\tok    : { value : savesOk },\n\n\t\t/*\n\t\t\tAutosave Functions.\n\t\t*/\n\t\tautosave : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tok     : { value : autosaveOk },\n\t\t\t\thas    : { value : autosaveHas },\n\t\t\t\tget    : { value : autosaveGet },\n\t\t\t\tload   : { value : autosaveLoad },\n\t\t\t\tsave   : { value : autosaveSave },\n\t\t\t\tdelete : { value : autosaveDelete }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tSlots Functions.\n\t\t*/\n\t\tslots : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tok      : { value : slotsOk },\n\t\t\t\tlength  : { get : slotsLength },\n\t\t\t\tisEmpty : { value : slotsIsEmpty },\n\t\t\t\tcount   : { value : slotsCount },\n\t\t\t\thas     : { value : slotsHas },\n\t\t\t\tget     : { value : slotsGet },\n\t\t\t\tload    : { value : slotsLoad },\n\t\t\t\tsave    : { value : slotsSave },\n\t\t\t\tdelete  : { value : slotsDelete }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tDisk Import/Export Functions.\n\t\t*/\n\t\texport : { value : exportToDisk },\n\t\timport : { value : importFromDisk },\n\n\t\t/*\n\t\t\tSerialization Functions.\n\t\t*/\n\t\tserialize   : { value : serialize },\n\t\tdeserialize : { value : deserialize }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tsetting.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util, settings:true, storage */\n\nvar Setting = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Setting control types object (pseudo-enumeration).\n\tconst Types = Util.toEnum({\n\t\tHeader : 0,\n\t\tToggle : 1,\n\t\tList   : 2,\n\t\tRange  : 3\n\t});\n\n\t// Setting definition array.\n\tconst _definitions = [];\n\n\n\t/*******************************************************************************************************************\n\t\tSettings Functions.\n\t*******************************************************************************************************************/\n\tfunction settingsInit() {\n\t\tif (DEBUG) { console.log('[Setting/settingsInit()]'); }\n\n\t\t/* legacy */\n\t\t// Attempt to migrate an existing `options` store to `settings`.\n\t\tif (storage.has('options')) {\n\t\t\tconst old = storage.get('options');\n\n\t\t\tif (old !== null) {\n\t\t\t\twindow.SugarCube.settings = settings = Object.assign(settingsCreate(), old);\n\t\t\t}\n\n\t\t\tsettingsSave();\n\t\t\tstorage.delete('options');\n\t\t}\n\t\t/* /legacy */\n\n\t\t// Load existing settings.\n\t\tsettingsLoad();\n\n\t\t// Execute `onInit` callbacks.\n\t\t_definitions.forEach(def => {\n\t\t\tif (def.hasOwnProperty('onInit')) {\n\t\t\t\tconst thisArg = {\n\t\t\t\t\tname    : def.name,\n\t\t\t\t\tvalue   : settings[def.name],\n\t\t\t\t\tdefault : def.default\n\t\t\t\t};\n\n\t\t\t\tif (def.hasOwnProperty('list')) {\n\t\t\t\t\tthisArg.list = def.list;\n\t\t\t\t}\n\n\t\t\t\tdef.onInit.call(thisArg);\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction settingsCreate() {\n\t\treturn Object.create(null);\n\t}\n\n\tfunction settingsSave() {\n\t\tconst savedSettings = settingsCreate();\n\n\t\tif (Object.keys(settings).length > 0) {\n\t\t\t_definitions\n\t\t\t\t.filter(def => def.type !== Types.Header && settings[def.name] !== def.default)\n\t\t\t\t.forEach(def => savedSettings[def.name] = settings[def.name]);\n\t\t}\n\n\t\tif (Object.keys(savedSettings).length === 0) {\n\t\t\tstorage.delete('settings');\n\t\t\treturn true;\n\t\t}\n\n\t\treturn storage.set('settings', savedSettings);\n\t}\n\n\tfunction settingsLoad() {\n\t\tconst defaultSettings = settingsCreate();\n\t\tconst loadedSettings  = storage.get('settings') || settingsCreate();\n\n\t\t// Load the defaults.\n\t\t_definitions\n\t\t\t.filter(def => def.type !== Types.Header)\n\t\t\t.forEach(def => defaultSettings[def.name] = def.default);\n\n\t\t// Assign to the `settings` object while overwriting the defaults with the loaded settings.\n\t\twindow.SugarCube.settings = settings = Object.assign(defaultSettings, loadedSettings);\n\t}\n\n\tfunction settingsClear() {\n\t\twindow.SugarCube.settings = settings = settingsCreate();\n\t\tstorage.delete('settings');\n\t\treturn true;\n\t}\n\n\tfunction settingsReset(name) {\n\t\tif (arguments.length === 0) {\n\t\t\tsettingsClear();\n\t\t\tsettingsLoad();\n\t\t}\n\t\telse {\n\t\t\tif (name == null || !definitionsHas(name)) { // lazy equality for null\n\t\t\t\tthrow new Error(`nonexistent setting \"${name}\"`);\n\t\t\t}\n\n\t\t\tconst def = definitionsGet(name);\n\n\t\t\tif (def.type !== Types.Header) {\n\t\t\t\tsettings[name] = def.default;\n\t\t\t}\n\t\t}\n\n\t\treturn settingsSave();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tDefinitions Functions.\n\t*******************************************************************************************************************/\n\tfunction definitionsForEach(callback, thisArg) {\n\t\t_definitions.forEach(callback, thisArg);\n\t}\n\n\tfunction definitionsAdd(type, name, def) {\n\t\tif (arguments.length < 3) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('type'); }\n\t\t\tif (arguments.length < 2) { errors.push('name'); }\n\t\t\tif (arguments.length < 3) { errors.push('definition'); }\n\t\t\tthrow new Error(`missing parameters, no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tif (typeof def !== 'object') {\n\t\t\tthrow new TypeError('definition parameter must be an object');\n\t\t}\n\n\t\tif (definitionsHas(name)) {\n\t\t\tthrow new Error(`cannot clobber existing setting \"${name}\"`);\n\t\t}\n\n\t\t/*\n\t\t\tDefinition object properties and types:\n\t\t\t\ttype      →  (all)   → Setting.Types\n\t\t\t\tname      →  (all)   → string\n\t\t\t\tlabel     →  (all)   → string\n\t\t\t\tdesc      →  (all)   → string\n\t\t\t\tdefault\n\t\t\t\t\t(if defined)\n \t\t\t\t\t\t  →  Toggle  → boolean\n\t\t\t\t\t\t  →  List    → Array\n\t\t\t\t\t\t  →  Range   → number\n\t\t\t\t\t(if undefined)\n\t\t\t\t\t\t  →  Toggle  → false\n\t\t\t\t\t\t  →  List    → list[0]\n\t\t\t\t\t\t  →  Range   → max\n\t\t\t\tlist      →  List    → Array\n\t\t\t\tmin       →  Range   → number\n\t\t\t\tmax       →  Range   → number\n\t\t\t\tstep      →  Range   → number\n\t\t\t\tonInit    →  (all)   → function\n\t\t\t\tonChange  →  (all)   → function\n\t\t*/\n\t\tconst definition = {\n\t\t\ttype,\n\t\t\tname,\n\t\t\tlabel : typeof def.label === 'string' ? def.label.trim() : ''\n\t\t};\n\n\t\tif (typeof def.desc === 'string') {\n\t\t\tconst desc = def.desc.trim();\n\n\t\t\tif (desc !== '') {\n\t\t\t\tdefinition.desc = desc;\n\t\t\t}\n\t\t}\n\n\t\tswitch (type) {\n\t\tcase Types.Header:\n\t\t\tbreak;\n\n\t\tcase Types.Toggle:\n\t\t\tdefinition.default = !!def.default;\n\t\t\tbreak;\n\n\t\tcase Types.List:\n\t\t\tif (!def.hasOwnProperty('list')) {\n\t\t\t\tthrow new Error('no list specified');\n\t\t\t}\n\t\t\telse if (!Array.isArray(def.list)) {\n\t\t\t\tthrow new TypeError('list must be an array');\n\t\t\t}\n\t\t\telse if (def.list.length === 0) {\n\t\t\t\tthrow new Error('list must not be empty');\n\t\t\t}\n\n\t\t\tdefinition.list = Object.freeze(def.list);\n\n\t\t\tif (def.default == null) { // lazy equality for null\n\t\t\t\tdefinition.default = def.list[0];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst defaultIndex = def.list.indexOf(def.default);\n\n\t\t\t\tif (defaultIndex === -1) {\n\t\t\t\t\tthrow new Error('list does not contain default');\n\t\t\t\t}\n\n\t\t\t\tdefinition.default = def.list[defaultIndex];\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase Types.Range:\n\t\t\tif (!def.hasOwnProperty('min')) {\n\t\t\t\tthrow new Error('no min specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.min !== 'number'\n\t\t\t\t|| Number.isNaN(def.min)\n\t\t\t\t|| !Number.isFinite(def.min)\n\t\t\t) {\n\t\t\t\tthrow new TypeError('min must be a finite number');\n\t\t\t}\n\n\t\t\tif (!def.hasOwnProperty('max')) {\n\t\t\t\tthrow new Error('no max specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.max !== 'number'\n\t\t\t\t|| Number.isNaN(def.max)\n\t\t\t\t|| !Number.isFinite(def.max)\n\t\t\t) {\n\t\t\t\tthrow new TypeError('max must be a finite number');\n\t\t\t}\n\n\t\t\tif (!def.hasOwnProperty('step')) {\n\t\t\t\tthrow new Error('no step specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.step !== 'number'\n\t\t\t\t|| Number.isNaN(def.step)\n\t\t\t\t|| !Number.isFinite(def.step)\n\t\t\t\t|| def.step <= 0\n\t\t\t) {\n\t\t\t\tthrow new TypeError('step must be a finite number greater than zero');\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Determine how many fractional digits we need to be concerned with based on the step value.\n\t\t\t\tconst fracDigits = (() => {\n\t\t\t\t\tconst str = String(def.step);\n\t\t\t\t\tconst pos = str.lastIndexOf('.');\n\t\t\t\t\treturn pos === -1 ? 0 : str.length - pos - 1;\n\t\t\t\t})();\n\n\t\t\t\t// Set up a function to validate a given value against the step value.\n\t\t\t\tfunction stepValidate(value) {\n\t\t\t\t\tif (fracDigits > 0) {\n\t\t\t\t\t\tconst ma = Number(`${def.min}e${fracDigits}`);\n\t\t\t\t\t\tconst sa = Number(`${def.step}e${fracDigits}`);\n\t\t\t\t\t\tconst va = Number(`${value}e${fracDigits}`) - ma;\n\t\t\t\t\t\treturn Number(`${va - va % sa + ma}e-${fracDigits}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst va = value - def.min;\n\t\t\t\t\treturn va - va % def.step + def.min;\n\t\t\t\t}\n\n\t\t\t\t// Sanity check the max value against the step value.\n\t\t\t\tif (stepValidate(def.max) !== def.max) {\n\t\t\t\t\tthrow new RangeError(`max (${def.max}) is not a multiple of the step (${def.step}) plus the min (${def.min})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdefinition.max = def.max;\n\t\t\tdefinition.min = def.min;\n\t\t\tdefinition.step = def.step;\n\n\t\t\tif (def.default == null) { // lazy equality for null\n\t\t\t\tdefinition.default = def.max;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (\n\t\t\t\t\t   typeof def.default !== 'number'\n\t\t\t\t\t|| Number.isNaN(def.default)\n\t\t\t\t\t|| !Number.isFinite(def.default)\n\t\t\t\t) {\n\t\t\t\t\tthrow new TypeError('default must be a finite number');\n\t\t\t\t}\n\t\t\t\telse if (def.default < def.min) {\n\t\t\t\t\tthrow new RangeError(`default (${def.default}) is less than min (${def.min})`);\n\t\t\t\t}\n\t\t\t\telse if (def.default > def.max) {\n\t\t\t\t\tthrow new RangeError(`default (${def.default}) is greater than max (${def.max})`);\n\t\t\t\t}\n\n\t\t\t\tdefinition.default = def.default;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new Error(`unknown Setting type: ${type}`);\n\t\t}\n\n\t\tif (typeof def.onInit === 'function') {\n\t\t\tdefinition.onInit = Object.freeze(def.onInit);\n\t\t}\n\n\t\tif (typeof def.onChange === 'function') {\n\t\t\tdefinition.onChange = Object.freeze(def.onChange);\n\t\t}\n\n\t\t_definitions.push(Object.freeze(definition));\n\t}\n\n\tfunction definitionsAddHeader(name, desc) {\n\t\tdefinitionsAdd(Types.Header, name, { desc });\n\t}\n\n\tfunction definitionsAddToggle(...args) {\n\t\tdefinitionsAdd(Types.Toggle, ...args);\n\t}\n\n\tfunction definitionsAddList(...args) {\n\t\tdefinitionsAdd(Types.List, ...args);\n\t}\n\n\tfunction definitionsAddRange(...args) {\n\t\tdefinitionsAdd(Types.Range, ...args);\n\t}\n\n\tfunction definitionsIsEmpty() {\n\t\treturn _definitions.length === 0;\n\t}\n\n\tfunction definitionsHas(name) {\n\t\treturn _definitions.some(definition => definition.name === name);\n\t}\n\n\tfunction definitionsGet(name) {\n\t\treturn _definitions.find(definition => definition.name === name);\n\t}\n\n\tfunction definitionsDelete(name) {\n\t\tif (definitionsHas(name)) {\n\t\t\tdelete settings[name];\n\t\t}\n\n\t\tfor (let i = 0; i < _definitions.length; ++i) {\n\t\t\tif (_definitions[i].name === name) {\n\t\t\t\t_definitions.splice(i, 1);\n\t\t\t\tdefinitionsDelete(name);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tEnumerations.\n\t\t*/\n\t\tTypes : { value : Types },\n\n\t\t/*\n\t\t\tSettings Functions.\n\t\t*/\n\t\tinit   : { value : settingsInit },\n\t\tcreate : { value : settingsCreate },\n\t\tsave   : { value : settingsSave },\n\t\tload   : { value : settingsLoad },\n\t\tclear  : { value : settingsClear },\n\t\treset  : { value : settingsReset },\n\n\t\t/*\n\t\t\tDefinitions Functions.\n\t\t*/\n\t\tforEach   : { value : definitionsForEach },\n\t\tadd       : { value : definitionsAdd },\n\t\taddHeader : { value : definitionsAddHeader },\n\t\taddToggle : { value : definitionsAddToggle },\n\t\taddList   : { value : definitionsAddList },\n\t\taddRange  : { value : definitionsAddRange },\n\t\tisEmpty   : { value : definitionsIsEmpty },\n\t\thas       : { value : definitionsHas },\n\t\tget       : { value : definitionsGet },\n\t\tdelete    : { value : definitionsDelete }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tstory.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Alert, Config, Passage, Scripting, StyleWrapper, Util, Wikifier */\n\nvar Story = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Map of normal passages.\n\tconst _passages = {};\n\n\t// List of script passages.\n\tconst _scripts = [];\n\n\t// List of style passages.\n\tconst _styles = [];\n\n\t// List of widget passages.\n\tconst _widgets = [];\n\n\t// Story title.\n\tlet _title = '';\n\n\t// Story IFID.\n\tlet _ifId = '';\n\n\t// DOM-compatible ID.\n\tlet _domId = '';\n\n\n\t/*******************************************************************************************************************\n\t\tStory Functions.\n\t*******************************************************************************************************************/\n\tfunction storyLoad() {\n\t\tif (DEBUG) { console.log('[Story/storyLoad()]'); }\n\n\t\tconst validationCodeTags = [\n\t\t\t'widget'\n\t\t];\n\t\tconst validationNoCodeTagPassages = [\n\t\t\t'PassageDone',\n\t\t\t'PassageFooter',\n\t\t\t'PassageHeader',\n\t\t\t'PassageReady',\n\t\t\t'StoryAuthor',\n\t\t\t'StoryBanner',\n\t\t\t'StoryCaption',\n\t\t\t'StoryInit',\n\t\t\t'StoryMenu',\n\t\t\t'StoryShare',\n\t\t\t'StorySubtitle'\n\t\t];\n\n\t\tfunction validateStartingPassage(passage) {\n\t\t\tif (passage.tags.includesAny(validationCodeTags)) {\n\t\t\t\tthrow new Error(`starting passage \"${passage.title}\" contains illegal tags; invalid: \"${passage.tags.filter(tag => validationCodeTags.includes(tag)).sort().join('\", \"')}\"`);\n\t\t\t}\n\t\t}\n\n\t\tfunction validateSpecialPassages(passage) {\n\t\t\tif (validationNoCodeTagPassages.includes(passage.title) && passage.tags.includesAny(validationCodeTags)) {\n\t\t\t\tthrow new Error(`special passage \"${passage.title}\" contains illegal tags; invalid: \"${passage.tags.filter(tag => validationCodeTags.includes(tag)).sort().join('\", \"')}\"`);\n\t\t\t}\n\t\t}\n\n\t\t// For Twine 1.\n\t\tif (TWINE1) {\n\t\t\t/*\n\t\t\t\tAdditional Twine 1 validation setup.\n\t\t\t*/\n\t\t\tvalidationCodeTags.unshift('script', 'stylesheet');\n\t\t\tvalidationNoCodeTagPassages.push('StoryTitle');\n\n\t\t\tfunction validateTwine1CodePassages(passage) {\n\t\t\t\tconst codeTags  = [...validationCodeTags];\n\t\t\t\tconst foundTags = [];\n\n\t\t\t\tpassage.tags.forEach(tag => {\n\t\t\t\t\tif (codeTags.includes(tag)) {\n\t\t\t\t\t\tfoundTags.push(...codeTags.delete(tag));\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (foundTags.length > 1) {\n\t\t\t\t\tthrow new Error(`code passage \"${passage.title}\" contains multiple code tags; invalid: \"${foundTags.sort().join('\", \"')}\"`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet the default starting passage.\n\t\t\t*/\n\t\t\tConfig.passages.start = (() => {\n\t\t\t\t/*\n\t\t\t\t\tHandle the Twine 1.4+ Test Play From Here feature.\n\n\t\t\t\t\tWARNING: Do not remove the `String()` wrapper from or change the quote\n\t\t\t\t\tstyle of the `\"START_AT\"` replacement target.  The former is there to\n\t\t\t\t\tkeep UglifyJS from pruning the code into oblivion—i.e. minifying the\n\t\t\t\t\tcode into something broken.  The latter is there because the Twine 1\n\t\t\t\t\tpattern that matches it depends upon the double quotes.\n\n\t\t\t\t*/\n\t\t\t\tconst testPlay = String(\"START_AT\"); // eslint-disable-line quotes\n\n\t\t\t\tif (testPlay !== '') {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tTest play; starting passage: \"${testPlay}\"`); }\n\n\t\t\t\t\tConfig.debug = true;\n\t\t\t\t\treturn testPlay;\n\t\t\t\t}\n\n\t\t\t\t// In the absence of a `testPlay` value, return 'Start'.\n\t\t\t\treturn 'Start';\n\t\t\t})();\n\n\t\t\t/*\n\t\t\t\tProcess the passages, excluding any tagged 'Twine.private' or 'annotation'.\n\t\t\t*/\n\t\t\tjQuery('#store-area')\n\t\t\t\t.children(':not([tags~=\"Twine.private\"],[tags~=\"annotation\"])')\n\t\t\t\t.each(function () {\n\t\t\t\t\tconst $this   = jQuery(this);\n\t\t\t\t\tconst passage = new Passage($this.attr('tiddler'), this);\n\n\t\t\t\t\t// Special cases.\n\t\t\t\t\tif (passage.title === Config.passages.start) {\n\t\t\t\t\t\tvalidateStartingPassage(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('stylesheet')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_styles.push(passage);\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('script')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_scripts.push(passage);\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('widget')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_widgets.push(passage);\n\t\t\t\t\t}\n\n\t\t\t\t\t// All other passages.\n\t\t\t\t\telse {\n\t\t\t\t\t\tvalidateSpecialPassages(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tSet the story title or throw an exception.\n\t\t\t*/\n\t\t\tif (_passages.hasOwnProperty('StoryTitle')) {\n\t\t\t\tconst buf = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(buf, _passages.StoryTitle.processText().trim());\n\t\t\t\t_storySetTitle(buf.textContent);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('cannot find the \"StoryTitle\" special passage');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet the default saves ID (must be done after the call to `_storySetTitle()`).\n\t\t\t*/\n\t\t\tConfig.saves.id = Story.domId;\n\t\t}\n\n\t\t// For Twine 2.\n\t\telse {\n\t\t\tconst $storydata = jQuery('tw-storydata');\n\t\t\tconst startNode  = $storydata.attr('startnode') || '';\n\n\t\t\t/*\n\t\t\t\tSet the default starting passage.\n\t\t\t*/\n\t\t\tConfig.passages.start = null; // no default in Twine 2\n\n\t\t\t/*\n\t\t\t\tProcess story options.\n\n\t\t\t\tNOTE: Currently, the only option of interest is 'debug', so we\n\t\t\t\tsimply use a regular expression to check for it.\n\t\t\t*/\n\t\t\tConfig.debug = /\\bdebug\\b/.test($storydata.attr('options'));\n\n\t\t\t/*\n\t\t\t\tProcess stylesheet passages.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('style') // alternatively: '[type=\"text/twine-css\"]' or '#twine-user-stylesheet'\n\t\t\t\t.each(function (i) {\n\t\t\t\t\t_styles.push(new Passage(`tw-user-style-${i}`, this));\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tProcess script passages.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('script') // alternatively: '[type=\"text/twine-javascript\"]' or '#twine-user-script'\n\t\t\t\t.each(function (i) {\n\t\t\t\t\t_scripts.push(new Passage(`tw-user-script-${i}`, this));\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tProcess normal passages, excluding any tagged 'Twine.private' or 'annotation'.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('tw-passagedata:not([tags~=\"Twine.private\"],[tags~=\"annotation\"])')\n\t\t\t\t.each(function () {\n\t\t\t\t\tconst $this   = jQuery(this);\n\t\t\t\t\tconst pid     = $this.attr('pid') || '';\n\t\t\t\t\tconst passage = new Passage($this.attr('name'), this);\n\n\t\t\t\t\t// Special cases.\n\t\t\t\t\tif (pid === startNode && startNode !== '') {\n\t\t\t\t\t\tConfig.passages.start = passage.title;\n\t\t\t\t\t\tvalidateStartingPassage(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('widget')) {\n\t\t\t\t\t\t_widgets.push(passage);\n\t\t\t\t\t}\n\n\t\t\t\t\t// All other passages.\n\t\t\t\t\telse {\n\t\t\t\t\t\tvalidateSpecialPassages(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tGet the story IFID.\n\t\t\t*/\n\t\t\t_ifId = $storydata.attr('ifid');\n\n\t\t\t/*\n\t\t\t\tSet the story title.\n\n\t\t\t\tFIXME: Maybe `$storydata.attr('name')` should be used instead of `'{{STORY_NAME}}'`?\n\t\t\t*/\n\t\t\t// _storySetTitle($storydata.attr('name'));\n\t\t\t_storySetTitle('{{STORY_NAME}}');\n\n\t\t\t/*\n\t\t\t\tSet the default saves ID (must be done after the call to `_storySetTitle()`).\n\t\t\t*/\n\t\t\tConfig.saves.id = Story.domId;\n\t\t}\n\t}\n\n\tfunction storyInit() {\n\t\tif (DEBUG) { console.log('[Story/storyInit()]'); }\n\n\t\t/*\n\t\t\tAdd the story styles.\n\t\t*/\n\t\t(() => {\n\t\t\tconst storyStyle = document.createElement('style');\n\n\t\t\t(new StyleWrapper(storyStyle))\n\t\t\t\t.add(_styles.map(style => style.text.trim()).join('\\n'));\n\n\t\t\tjQuery(storyStyle)\n\t\t\t\t.appendTo(document.head)\n\t\t\t\t.attr({\n\t\t\t\t\tid   : 'style-story',\n\t\t\t\t\ttype : 'text/css'\n\t\t\t\t});\n\t\t})();\n\n\t\t/*\n\t\t\tEvaluate the story scripts.\n\t\t*/\n\t\tfor (let i = 0; i < _scripts.length; ++i) {\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(_scripts[i].text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error(_scripts[i].title, typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t\tProcess the story widgets.\n\t\t*/\n\t\tfor (let i = 0; i < _widgets.length; ++i) {\n\t\t\ttry {\n\t\t\t\tWikifier.wikifyEval(_widgets[i].processText());\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error(_widgets[i].title, typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction _storySetTitle(rawTitle) {\n\t\tif (rawTitle == null) { // lazy equality for null\n\t\t\tthrow new Error('story title must not be null or undefined');\n\t\t}\n\n\t\tconst title = Util.unescape(String(rawTitle)).trim();\n\n\t\tif (title === '') { // lazy equality for null\n\t\t\tthrow new Error('story title must not be empty or consist solely of whitespace');\n\t\t}\n\n\t\tdocument.title = _title = title;\n\n\t\t// TODO: In v3 the `_domId` should be created from a combination of the\n\t\t// `_title` slug and the IFID, if available, to avoid collisions between\n\t\t// stories whose titles generate identical slugs.\n\t\t_domId = Util.slugify(_title);\n\n\t\t// [v2] Protect the `_domId` against being an empty string.\n\t\t//\n\t\t// If `_domId` is empty, attempt a failover.\n\t\tif (_domId === '') {\n\t\t\t// If `_ifId` is not empty, then use it.\n\t\t\tif (_ifId !== '') {\n\t\t\t\t_domId = _ifId;\n\t\t\t}\n\n\t\t\t// Elsewise generate a string from the `_title`'s code points (in hexadecimal).\n\t\t\telse {\n\t\t\t\tfor (let i = 0, len = _title.length; i < len; ++i) {\n\t\t\t\t\tconst { char, start, end } = Util.charAndPosAt(_title, i);\n\t\t\t\t\t_domId += char.codePointAt(0).toString(16);\n\t\t\t\t\ti += end - start;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction storyTitle() {\n\t\treturn _title;\n\t}\n\n\tfunction storyDomId() {\n\t\treturn _domId;\n\t}\n\n\tfunction storyIfId() {\n\t\treturn _ifId;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPassage Functions.\n\t*******************************************************************************************************************/\n\tfunction passagesAdd(passage) {\n\t\tif (!(passage instanceof Passage)) {\n\t\t\tthrow new TypeError('Story.add passage parameter must be an instance of Passage');\n\t\t}\n\n\t\tconst title = passage.title;\n\n\t\tif (!_passages.hasOwnProperty(title)) {\n\t\t\t_passages[title] = passage;\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tfunction passagesHas(title) {\n\t\tlet type = typeof title;\n\n\t\tswitch (type) {\n\t\t// Valid types.\n\t\tcase 'number':\n\t\tcase 'string':\n\t\t\treturn _passages.hasOwnProperty(String(title));\n\n\t\t// Invalid types.  We do the extra processing just to make a nicer error.\n\t\tcase 'undefined':\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\ttype = title === null ? 'null' : 'an object';\n\t\t\tbreak;\n\n\t\tdefault: // 'bigint', 'boolean', 'function', 'symbol'\n\t\t\ttype = `a ${type}`;\n\t\t\tbreak;\n\t\t}\n\n\t\tthrow new TypeError(`Story.has title parameter cannot be ${type}`);\n\t}\n\n\tfunction passagesGet(title) {\n\t\tlet type = typeof title;\n\n\t\tswitch (type) {\n\t\t// Valid types.\n\t\tcase 'number':\n\t\tcase 'string':\n\t\t/* eslint-disable indent */\n\t\t\t{\n\t\t\t\tconst id = String(title);\n\t\t\t\treturn _passages.hasOwnProperty(id) ? _passages[id] : new Passage(id || '(unknown)');\n\t\t\t}\n\t\t/* eslint-enable indent */\n\n\t\t// Invalid types.  We do the extra processing just to make a nicer error.\n\t\tcase 'undefined':\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\ttype = title === null ? 'null' : 'an object';\n\t\t\tbreak;\n\n\t\tdefault: // 'bigint', 'boolean', 'function', 'symbol'\n\t\t\ttype = `a ${type}`;\n\t\t\tbreak;\n\t\t}\n\n\t\tthrow new TypeError(`Story.get title parameter cannot be ${type}`);\n\t}\n\n\tfunction passagesGetAllRegular() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Object.assign({}, _passages));\n\t}\n\n\tfunction passagesGetAllScript() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_scripts));\n\t}\n\n\tfunction passagesGetAllStylesheet() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_styles));\n\t}\n\n\tfunction passagesGetAllWidget() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_widgets));\n\t}\n\n\tfunction passagesLookup(key, value  /* legacy */, sortKey = 'title'/* /legacy */) {\n\t\tconst results = [];\n\n\t\tObject.keys(_passages).forEach(name => {\n\t\t\tconst passage = _passages[name];\n\n\t\t\t// Objects (sans `null`).\n\t\t\tif (typeof passage[key] === 'object' && passage[key] !== null) {\n\t\t\t\t// The only object type currently supported is `Array`, since the\n\t\t\t\t// non-method `Passage` object properties currently yield only either\n\t\t\t\t// primitives or arrays.\n\t\t\t\tif (passage[key] instanceof Array && passage[key].some(m => Util.sameValueZero(m, value))) {\n\t\t\t\t\tresults.push(passage);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// All other types (incl. `null`).\n\t\t\telse if (Util.sameValueZero(passage[key], value)) {\n\t\t\t\tresults.push(passage);\n\t\t\t}\n\t\t});\n\n\t\t// For v3.\n\t\t// /* eslint-disable no-nested-ternary */\n\t\t// // QUESTION: Do we really need to sort the list?\n\t\t// results.sort((a, b) => a.title === b.title ? 0 : a.title < b.title ? -1 : +1);\n\t\t// /* eslint-enable no-nested-ternary */\n\n\t\t/* legacy */\n\t\t/* eslint-disable eqeqeq, no-nested-ternary, max-len */\n\t\tresults.sort((a, b) => a[sortKey] == b[sortKey] ? 0 : a[sortKey] < b[sortKey] ? -1 : +1); // lazy equality for null\n\t\t/* eslint-enable eqeqeq, no-nested-ternary, max-len */\n\t\t/* /legacy */\n\n\t\treturn results;\n\t}\n\n\tfunction passagesLookupWith(predicate /* legacy */, sortKey = 'title'/* /legacy */) {\n\t\tif (typeof predicate !== 'function') {\n\t\t\tthrow new TypeError('Story.lookupWith predicate parameter must be a function');\n\t\t}\n\n\t\tconst results = [];\n\n\t\tObject.keys(_passages).forEach(name => {\n\t\t\tconst passage = _passages[name];\n\n\t\t\tif (predicate(passage)) {\n\t\t\t\tresults.push(passage);\n\t\t\t}\n\t\t});\n\n\t\t// For v3.\n\t\t// /* eslint-disable no-nested-ternary */\n\t\t// // QUESTION: Do we really need to sort the list?\n\t\t// results.sort((a, b) => a.title === b.title ? 0 : a.title < b.title ? -1 : +1);\n\t\t// /* eslint-enable no-nested-ternary */\n\n\t\t/* legacy */\n\t\t/* eslint-disable eqeqeq, no-nested-ternary, max-len */\n\t\tresults.sort((a, b) => a[sortKey] == b[sortKey] ? 0 : a[sortKey] < b[sortKey] ? -1 : +1); // lazy equality for null\n\t\t/* eslint-enable eqeqeq, no-nested-ternary, max-len */\n\t\t/* /legacy */\n\n\t\treturn results;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Story Functions.\n\t\tload  : { value : storyLoad },\n\t\tinit  : { value : storyInit },\n\t\ttitle : { get : storyTitle },\n\t\tdomId : { get : storyDomId },\n\t\tifId  : { get : storyIfId },\n\n\t\t// Passage Functions.\n\t\tadd              : { value : passagesAdd },\n\t\thas              : { value : passagesHas },\n\t\tget              : { value : passagesGet },\n\t\tgetAllRegular    : { value : passagesGetAllRegular },\n\t\tgetAllScript     : { value : passagesGetAllScript },\n\t\tgetAllStylesheet : { value : passagesGetAllStylesheet },\n\t\tgetAllWidget     : { value : passagesGetAllWidget },\n\t\tlookup           : { value : passagesLookup },\n\t\tlookupWith       : { value : passagesLookupWith }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tui.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Dialog, Engine, Has, L10n, Save, Setting, State, Story, Util, Wikifier, Config, errorPrologRegExp,\n\t       settings\n*/\n\nvar UI = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUI Functions, Core.\n\t*******************************************************************************************************************/\n\tfunction uiAssembleLinkList(passage, listEl) {\n\t\tlet list = listEl;\n\n\t\t// Cache the values of `Config.debug` and `Config.cleanupWikifierOutput`,\n\t\t// then disable them during this method's run.\n\t\tconst debugState = Config.debug;\n\t\tconst cleanState = Config.cleanupWikifierOutput;\n\t\tConfig.debug = false;\n\t\tConfig.cleanupWikifierOutput = false;\n\n\t\ttry {\n\t\t\tif (list == null) { // lazy equality for null\n\t\t\t\tlist = document.createElement('ul');\n\t\t\t}\n\n\t\t\t// Wikify the content of the given source passage into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, Story.get(passage).processText().trim());\n\n\t\t\t// Gather the text of any error elements within the fragment…\n\t\t\tconst errors = [...frag.querySelectorAll('.error')]\n\t\t\t\t.map(errEl => errEl.textContent.replace(errorPrologRegExp, ''));\n\n\t\t\t// …and throw an exception, if there were any errors.\n\t\t\tif (errors.length > 0) {\n\t\t\t\tthrow new Error(errors.join('; '));\n\t\t\t}\n\n\t\t\twhile (frag.hasChildNodes()) {\n\t\t\t\tconst node = frag.firstChild;\n\n\t\t\t\t// Create list items for <a>-element nodes.\n\t\t\t\tif (node.nodeType === Node.ELEMENT_NODE && node.nodeName.toUpperCase() === 'A') {\n\t\t\t\t\tconst li = document.createElement('li');\n\t\t\t\t\tlist.appendChild(li);\n\t\t\t\t\tli.appendChild(node);\n\t\t\t\t}\n\n\t\t\t\t// Discard non-<a>-element nodes.\n\t\t\t\telse {\n\t\t\t\t\tfrag.removeChild(node);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\t// Restore the `Config` settings to their original values.\n\t\t\tConfig.cleanupWikifierOutput = cleanState;\n\t\t\tConfig.debug = debugState;\n\t\t}\n\n\t\treturn list;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUI Functions, Built-ins.\n\t*******************************************************************************************************************/\n\tfunction uiOpenAlert(message, /* options, closeFn */ ...args) {\n\t\tjQuery(Dialog.setup('Alert', 'alert'))\n\t\t\t.append(\n\t\t\t\t  `<p>${message}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"alert-ok\" class=\"ui-close\">${L10n.get(['alertOk', 'ok'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t);\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenJumpto(/* options, closeFn */ ...args) {\n\t\tuiBuildJumpto();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenRestart(/* options, closeFn */ ...args) {\n\t\tuiBuildRestart();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenSaves(/* options, closeFn */ ...args) {\n\t\tuiBuildSaves();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenSettings(/* options, closeFn */ ...args) {\n\t\tuiBuildSettings();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenShare(/* options, closeFn */ ...args) {\n\t\tuiBuildShare();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiBuildAutoload() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildAutoload()]'); }\n\n\t\tjQuery(Dialog.setup(L10n.get('autoloadTitle'), 'autoload'))\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  `<p>${L10n.get('autoloadPrompt')}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"autoload-ok\" class=\"ui-close\">${L10n.get(['autoloadOk', 'ok'])}</button></li>`\n\t\t\t\t+ `<li><button id=\"autoload-cancel\" class=\"ui-close\">${L10n.get(['autoloadCancel', 'cancel'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t);\n\n\t\t// Add an additional delegated click handler for the `.ui-close` elements to handle autoloading.\n\t\tjQuery(document).one('click.autoload', '.ui-close', ev => {\n\t\t\tconst isAutoloadOk = ev.target.id === 'autoload-ok';\n\t\t\tjQuery(document).one(':dialogclosed', () => {\n\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\tif (!isAutoloadOk || !Save.autosave.load()) {\n\t\t\t\t\tEngine.play(Config.passages.start);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildJumpto() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildJumpto()]'); }\n\n\t\tconst list = document.createElement('ul');\n\n\t\tjQuery(Dialog.setup(L10n.get('jumptoTitle'), 'jumpto list'))\n\t\t\t.append(list);\n\n\t\tconst expired = State.expired.length;\n\n\t\tfor (let i = State.size - 1; i >= 0; --i) {\n\t\t\tif (i === State.activeIndex) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst passage = Story.get(State.history[i].title);\n\n\t\t\tif (passage && passage.tags.includes('bookmark')) {\n\t\t\t\tjQuery(document.createElement('li'))\n\t\t\t\t\t.append(\n\t\t\t\t\t\tjQuery(document.createElement('a'))\n\t\t\t\t\t\t\t.ariaClick({ one : true }, (function (idx) {\n\t\t\t\t\t\t\t\treturn () => jQuery(document).one(':dialogclosed', () => Engine.goTo(idx));\n\t\t\t\t\t\t\t})(i))\n\t\t\t\t\t\t\t.addClass('ui-close')\n\t\t\t\t\t\t\t.text(`${L10n.get('jumptoTurn')} ${expired + i + 1}: ${passage.description()}`)\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo(list);\n\t\t\t}\n\t\t}\n\n\t\tif (!list.hasChildNodes()) {\n\t\t\tjQuery(list).append(`<li><a><em>${L10n.get('jumptoUnavailable')}</em></a></li>`);\n\t\t}\n\t}\n\n\tfunction uiBuildRestart() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildRestart()]'); }\n\n\t\tjQuery(Dialog.setup(L10n.get('restartTitle'), 'restart'))\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  `<p>${L10n.get('restartPrompt')}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"restart-ok\">${L10n.get(['restartOk', 'ok'])}</button></li>`\n\t\t\t\t+ `<li><button id=\"restart-cancel\" class=\"ui-close\">${L10n.get(['restartCancel', 'cancel'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t)\n\t\t\t.find('#restart-ok')\n\t\t\t/*\n\t\t\t\tInstead of adding '.ui-close' to '#restart-ok' (to receive the use of the default\n\t\t\t\tdelegated dialog close handler), we set up a special case close handler here.  We\n\t\t\t\tdo this to ensure that the invocation of `Engine.restart()` happens after the dialog\n\t\t\t\thas fully closed.  If we did not, then a race condition could occur, causing display\n\t\t\t\tshenanigans.\n\t\t\t*/\n\t\t\t.ariaClick({ one : true }, () => {\n\t\t\t\tjQuery(document).one(':dialogclosed', () => Engine.restart());\n\t\t\t\tDialog.close();\n\t\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildSaves() {\n\t\tfunction createActionItem(bId, bClass, bText, bAction) {\n\t\t\tconst $btn = jQuery(document.createElement('button'))\n\t\t\t\t.attr('id', `saves-${bId}`)\n\t\t\t\t.html(bText);\n\n\t\t\tif (bClass) {\n\t\t\t\t$btn.addClass(bClass);\n\t\t\t}\n\n\t\t\tif (bAction) {\n\t\t\t\t$btn.ariaClick(bAction);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$btn.ariaDisabled(true);\n\t\t\t}\n\n\t\t\treturn jQuery(document.createElement('li'))\n\t\t\t\t.append($btn);\n\t\t}\n\n\t\tfunction createSaveList() {\n\t\t\tfunction createButton(bId, bClass, bText, bSlot, bAction) {\n\t\t\t\tconst $btn = jQuery(document.createElement('button'))\n\t\t\t\t\t.attr('id', `saves-${bId}-${bSlot}`)\n\t\t\t\t\t.addClass(bId)\n\t\t\t\t\t.html(bText);\n\n\t\t\t\tif (bClass) {\n\t\t\t\t\t$btn.addClass(bClass);\n\t\t\t\t}\n\n\t\t\t\tif (bAction) {\n\t\t\t\t\tif (bSlot === 'auto') {\n\t\t\t\t\t\t$btn.ariaClick({\n\t\t\t\t\t\t\tlabel : `${bText} ${L10n.get('savesLabelAuto')}`\n\t\t\t\t\t\t}, () => bAction());\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t$btn.ariaClick({\n\t\t\t\t\t\t\tlabel : `${bText} ${L10n.get('savesLabelSlot')} ${bSlot + 1}`\n\t\t\t\t\t\t}, () => bAction(bSlot));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$btn.ariaDisabled(true);\n\t\t\t\t}\n\n\t\t\t\treturn $btn;\n\t\t\t}\n\n\t\t\tconst saves  = Save.get();\n\t\t\tconst $tbody = jQuery(document.createElement('tbody'));\n\n\t\t\tif (Save.autosave.ok()) {\n\t\t\t\tconst $tdSlot = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdLoad = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDesc = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDele = jQuery(document.createElement('td'));\n\n\t\t\t\t// Add the slot ID.\n\t\t\t\tjQuery(document.createElement('b'))\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttitle        : L10n.get('savesLabelAuto'),\n\t\t\t\t\t\t'aria-label' : L10n.get('savesLabelAuto')\n\t\t\t\t\t})\n\t\t\t\t\t.text('A') // '\\u25C6' Black Diamond\n\t\t\t\t\t.appendTo($tdSlot);\n\n\t\t\t\tif (saves.autosave) {\n\t\t\t\t\t// Add the load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('load', 'ui-close', L10n.get('savesLabelLoad'), 'auto', () => {\n\t\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.autosave.load());\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description (title and datestamp).\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.text(saves.autosave.title)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.addClass('datestamp')\n\t\t\t\t\t\t.html(\n\t\t\t\t\t\t\tsaves.autosave.date\n\t\t\t\t\t\t\t\t? `${new Date(saves.autosave.date).toLocaleString()}`\n\t\t\t\t\t\t\t\t: `<em>${L10n.get('savesUnknownDate')}</em>`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\n\t\t\t\t\t// Add the delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), 'auto', () => {\n\t\t\t\t\t\t\tSave.autosave.delete();\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Add the disabled load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('load', null, L10n.get('savesLabelLoad'), 'auto')\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description.\n\t\t\t\t\t$tdDesc.addClass('empty').text('\\u2022\\u00a0\\u00a0\\u2022\\u00a0\\u00a0\\u2022');\n\n\t\t\t\t\t// Add the disabled delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), 'auto')\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t.append($tdSlot)\n\t\t\t\t\t.append($tdLoad)\n\t\t\t\t\t.append($tdDesc)\n\t\t\t\t\t.append($tdDele)\n\t\t\t\t\t.appendTo($tbody);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = saves.slots.length; i < iend; ++i) {\n\t\t\t\tconst $tdSlot = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdLoad = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDesc = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDele = jQuery(document.createElement('td'));\n\n\t\t\t\t// Add the slot ID.\n\t\t\t\t$tdSlot.append(document.createTextNode(i + 1));\n\n\t\t\t\tif (saves.slots[i]) {\n\t\t\t\t\t// Add the load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('save', 'ui-close', L10n.get('savesLabelSave'), i, Save.slots.save),\n\t\t\t\t\t\tcreateButton('load', 'ui-close', L10n.get('savesLabelLoad'), i, slot => {\n\t\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.slots.load(slot));\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description (title and datestamp).\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.text(saves.slots[i].title)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.addClass('datestamp')\n\t\t\t\t\t\t.html(\n\t\t\t\t\t\t\tsaves.slots[i].date\n\t\t\t\t\t\t\t\t? `${new Date(saves.slots[i].date).toLocaleString()}`\n\t\t\t\t\t\t\t\t: `<em>${L10n.get('savesUnknownDate')}</em>`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\n\t\t\t\t\t// Add the delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), i, slot => {\n\t\t\t\t\t\t\tSave.slots.delete(slot);\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Add the save button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('save', 'ui-close', L10n.get('savesLabelSave'), i, Save.slots.save)\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description.\n\t\t\t\t\t$tdDesc.addClass('empty').text('\\u2022\\u00a0\\u00a0\\u2022\\u00a0\\u00a0\\u2022');\n\n\t\t\t\t\t// Add the disabled delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), i)\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t.append($tdSlot)\n\t\t\t\t\t.append($tdLoad)\n\t\t\t\t\t.append($tdDesc)\n\t\t\t\t\t.append($tdDele)\n\t\t\t\t\t.appendTo($tbody);\n\t\t\t}\n\n\t\t\treturn jQuery(document.createElement('table'))\n\t\t\t\t.attr('id', 'saves-list')\n\t\t\t\t.append($tbody);\n\t\t}\n\n\t\tif (DEBUG) { console.log('[UI/uiBuildSaves()]'); }\n\n\t\tconst $dialogBody = jQuery(Dialog.setup(L10n.get('savesTitle'), 'saves'));\n\t\tconst savesOk     = Save.ok();\n\n\t\t// Add saves list.\n\t\tif (savesOk) {\n\t\t\t$dialogBody.append(createSaveList());\n\t\t}\n\n\t\t// Add button bar items (export, import, and clear).\n\t\tif (savesOk || Has.fileAPI) {\n\t\t\tconst $btnBar = jQuery(document.createElement('ul'))\n\t\t\t\t.addClass('buttons')\n\t\t\t\t.appendTo($dialogBody);\n\n\t\t\tif (Has.fileAPI) {\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'export',\n\t\t\t\t\t'ui-close',\n\t\t\t\t\tL10n.get('savesLabelExport'),\n\t\t\t\t\t() => Save.export()\n\t\t\t\t));\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'import',\n\t\t\t\t\tnull,\n\t\t\t\t\tL10n.get('savesLabelImport'),\n\t\t\t\t\t() => $dialogBody.find('#saves-import-file').trigger('click')\n\t\t\t\t));\n\n\t\t\t\t// Add the hidden `input[type=file]` element which will be triggered by the `#saves-import` button.\n\t\t\t\tjQuery(document.createElement('input'))\n\t\t\t\t\t.css({\n\t\t\t\t\t\tdisplay    : 'block',\n\t\t\t\t\t\tvisibility : 'hidden',\n\t\t\t\t\t\tposition   : 'fixed',\n\t\t\t\t\t\tleft       : '-9999px',\n\t\t\t\t\t\ttop        : '-9999px',\n\t\t\t\t\t\twidth      : '1px',\n\t\t\t\t\t\theight     : '1px'\n\t\t\t\t\t})\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttype          : 'file',\n\t\t\t\t\t\tid            : 'saves-import-file',\n\t\t\t\t\t\ttabindex      : -1,\n\t\t\t\t\t\t'aria-hidden' : true\n\t\t\t\t\t})\n\t\t\t\t\t.on('change', ev => {\n\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.import(ev));\n\t\t\t\t\t\tDialog.close();\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo($dialogBody);\n\t\t\t}\n\n\t\t\tif (savesOk) {\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'clear',\n\t\t\t\t\tnull,\n\t\t\t\t\tL10n.get('savesLabelClear'),\n\t\t\t\t\tSave.autosave.has() || !Save.slots.isEmpty()\n\t\t\t\t\t\t? () => {\n\t\t\t\t\t\t\tSave.clear();\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t: null\n\t\t\t\t));\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tuiOpenAlert(L10n.get('savesIncapable'));\n\t\treturn false;\n\t}\n\n\tfunction uiBuildSettings() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildSettings()]'); }\n\n\t\tconst $dialogBody = jQuery(Dialog.setup(L10n.get('settingsTitle'), 'settings'));\n\n\t\tSetting.forEach(control => {\n\t\t\tif (control.type === Setting.Types.Header) {\n\t\t\t\tconst name     = control.name;\n\t\t\t\tconst id       = Util.slugify(name);\n\t\t\t\tconst $header  = jQuery(document.createElement('div'));\n\t\t\t\tconst $heading = jQuery(document.createElement('h2'));\n\n\t\t\t\t$header\n\t\t\t\t\t.attr('id', `header-body-${id}`)\n\t\t\t\t\t.append($heading)\n\t\t\t\t\t.appendTo($dialogBody);\n\t\t\t\t$heading\n\t\t\t\t\t.attr('id', `header-heading-${id}`)\n\t\t\t\t\t.wiki(name);\n\n\t\t\t\t// Set up the description, if any.\n\t\t\t\tif (control.desc) {\n\t\t\t\t\tjQuery(document.createElement('p'))\n\t\t\t\t\t\t.attr('id', `header-desc-${id}`)\n\t\t\t\t\t\t.wiki(control.desc)\n\t\t\t\t\t\t.appendTo($header);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst name        = control.name;\n\t\t\tconst id          = Util.slugify(name);\n\t\t\tconst $setting    = jQuery(document.createElement('div'));\n\t\t\tconst $label      = jQuery(document.createElement('label'));\n\t\t\tconst $controlBox = jQuery(document.createElement('div'));\n\t\t\tlet $control;\n\n\t\t\t// Set up the label+control wrapper.\n\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t.append($label)\n\t\t\t\t.append($controlBox)\n\t\t\t\t.appendTo($setting);\n\n\t\t\t// Set up the description, if any.\n\t\t\tif (control.desc) {\n\t\t\t\tjQuery(document.createElement('p'))\n\t\t\t\t\t.attr('id', `setting-desc-${id}`)\n\t\t\t\t\t.wiki(control.desc)\n\t\t\t\t\t.appendTo($setting);\n\t\t\t}\n\n\t\t\t// Set up the label.\n\t\t\t$label\n\t\t\t\t.attr({\n\t\t\t\t\tid  : `setting-label-${id}`,\n\t\t\t\t\tfor : `setting-control-${id}` // must be in sync with $control's ID (see below)\n\t\t\t\t})\n\t\t\t\t.wiki(control.label);\n\n\t\t\t// Set up the control.\n\t\t\tif (settings[name] == null) { // lazy equality for null\n\t\t\t\tsettings[name] = control.default;\n\t\t\t}\n\n\t\t\tswitch (control.type) {\n\t\t\tcase Setting.Types.Toggle:\n\t\t\t\t$control = jQuery(document.createElement('button'));\n\n\t\t\t\tif (settings[name]) {\n\t\t\t\t\t$control\n\t\t\t\t\t\t.addClass('enabled')\n\t\t\t\t\t\t.text(L10n.get('settingsOn'));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$control\n\t\t\t\t\t\t.text(L10n.get('settingsOff'));\n\t\t\t\t}\n\n\t\t\t\t$control.ariaClick(function () {\n\t\t\t\t\tif (settings[name]) {\n\t\t\t\t\t\tjQuery(this)\n\t\t\t\t\t\t\t.removeClass('enabled')\n\t\t\t\t\t\t\t.text(L10n.get('settingsOff'));\n\t\t\t\t\t\tsettings[name] = false;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tjQuery(this)\n\t\t\t\t\t\t\t.addClass('enabled')\n\t\t\t\t\t\t\t.text(L10n.get('settingsOn'));\n\t\t\t\t\t\tsettings[name] = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tSetting.save();\n\n\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\tdefault : control.default\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase Setting.Types.List:\n\t\t\t\t$control = jQuery(document.createElement('select'));\n\n\t\t\t\tfor (let i = 0, iend = control.list.length; i < iend; ++i) {\n\t\t\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t\t\t.val(i)\n\t\t\t\t\t\t.text(control.list[i])\n\t\t\t\t\t\t.appendTo($control);\n\t\t\t\t}\n\n\t\t\t\t$control\n\t\t\t\t\t.val(control.list.indexOf(settings[name]))\n\t\t\t\t\t.attr('tabindex', 0)\n\t\t\t\t\t.on('change', function () {\n\t\t\t\t\t\tsettings[name] = control.list[Number(this.value)];\n\t\t\t\t\t\tSetting.save();\n\n\t\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\t\tdefault : control.default,\n\t\t\t\t\t\t\t\tlist    : control.list\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase Setting.Types.Range:\n\t\t\t\t$control = jQuery(document.createElement('input'));\n\n\t\t\t\t// NOTE: Setting the value with `<jQuery>.val()` can cause odd behavior\n\t\t\t\t// in Edge if it's called before the type is set, so we use the `value`\n\t\t\t\t// content attribute here to dodge the entire issue.\n\t\t\t\t$control\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttype     : 'range',\n\t\t\t\t\t\tmin      : control.min,\n\t\t\t\t\t\tmax      : control.max,\n\t\t\t\t\t\tstep     : control.step,\n\t\t\t\t\t\tvalue    : settings[name],\n\t\t\t\t\t\ttabindex : 0\n\t\t\t\t\t})\n\t\t\t\t\t.on('change input', function () {\n\t\t\t\t\t\tsettings[name] = Number(this.value);\n\t\t\t\t\t\tSetting.save();\n\n\t\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\t\tdefault : control.default,\n\t\t\t\t\t\t\t\tmin     : control.min,\n\t\t\t\t\t\t\t\tmax     : control.max,\n\t\t\t\t\t\t\t\tstep    : control.step\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.on('keypress', ev => {\n\t\t\t\t\t\tif (ev.which === 13) {\n\t\t\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t\t\t$control.trigger('change');\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$control\n\t\t\t\t.attr('id', `setting-control-${id}`)\n\t\t\t\t.appendTo($controlBox);\n\n\t\t\t$setting\n\t\t\t\t.attr('id', `setting-body-${id}`)\n\t\t\t\t.appendTo($dialogBody);\n\t\t});\n\n\t\t// Add the button bar.\n\t\t$dialogBody\n\t\t\t.append(\n\t\t\t\t  '<ul class=\"buttons\">'\n\t\t\t\t+     `<li><button id=\"settings-ok\" class=\"ui-close\">${L10n.get(['settingsOk', 'ok'])}</button></li>`\n\t\t\t\t+     `<li><button id=\"settings-reset\">${L10n.get('settingsReset')}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t)\n\t\t\t.find('#settings-reset')\n\t\t\t/*\n\t\t\t\tInstead of adding '.ui-close' to '#settings-reset' (to receive the use of the default\n\t\t\t\tdelegated dialog close handler), we set up a special case close handler here.  We\n\t\t\t\tdo this to ensure that the invocation of `window.location.reload()` happens after the\n\t\t\t\tdialog has fully closed.  If we did not, then a race condition could occur, causing\n\t\t\t\tdisplay shenanigans.\n\t\t\t*/\n\t\t\t.ariaClick({ one : true }, () => {\n\t\t\t\tjQuery(document).one(':dialogclosed', () => {\n\t\t\t\t\tSetting.reset();\n\t\t\t\t\twindow.location.reload();\n\t\t\t\t});\n\t\t\t\tDialog.close();\n\t\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildShare() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildShare()]'); }\n\n\t\ttry {\n\t\t\tjQuery(Dialog.setup(L10n.get('shareTitle'), 'share list'))\n\t\t\t\t.append(uiAssembleLinkList('StoryShare'));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tconsole.error(ex);\n\t\t\tAlert.error('StoryShare', ex.message);\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tUI Functions, Core.\n\t\t*/\n\t\tassembleLinkList : { value : uiAssembleLinkList },\n\n\t\t/*\n\t\t\tUI Functions, Built-ins.\n\t\t*/\n\t\talert         : { value : uiOpenAlert },\n\t\tjumpto        : { value : uiOpenJumpto },\n\t\trestart       : { value : uiOpenRestart },\n\t\tsaves         : { value : uiOpenSaves },\n\t\tsettings      : { value : uiOpenSettings },\n\t\tshare         : { value : uiOpenShare },\n\t\tbuildAutoload : { value : uiBuildAutoload },\n\t\tbuildJumpto   : { value : uiBuildJumpto },\n\t\tbuildRestart  : { value : uiBuildRestart },\n\t\tbuildSaves    : { value : uiBuildSaves },\n\t\tbuildSettings : { value : uiBuildSettings },\n\t\tbuildShare    : { value : uiBuildShare },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\t// `UIBar` methods.\n\t\t/* global UIBar */\n\t\tstow                     : { value : () => UIBar.stow() },\n\t\tunstow                   : { value : () => UIBar.unstow() },\n\t\tsetStoryElements         : { value : () => UIBar.update() },\n\t\t// `Dialog` methods.\n\t\tisOpen                   : { value : (...args) => Dialog.isOpen(...args) },\n\t\tbody                     : { value : () => Dialog.body() },\n\t\tsetup                    : { value : (...args) => Dialog.setup(...args) },\n\t\taddClickHandler          : { value : (...args) => Dialog.addClickHandler(...args) },\n\t\topen                     : { value : (...args) => Dialog.open(...args) },\n\t\tclose                    : { value : (...args) => Dialog.close(...args) },\n\t\tresize                   : { value : () => Dialog.resize() },\n\t\t// Deprecated method names.\n\t\tbuildDialogAutoload      : { value : uiBuildAutoload },\n\t\tbuildDialogJumpto        : { value : uiBuildJumpto },\n\t\tbuildDialogRestart       : { value : uiBuildRestart },\n\t\tbuildDialogSaves         : { value : uiBuildSaves },\n\t\tbuildDialogSettings      : { value : uiBuildSettings },\n\t\tbuildDialogShare         : { value : uiBuildShare },\n\t\tbuildLinkListFromPassage : { value : uiAssembleLinkList }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tuibar.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Dialog, Engine, L10n, Setting, State, Story, UI, Config, setDisplayTitle, setPageElement\n*/\n\nvar UIBar = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// UI bar element cache.\n\tlet _$uiBar = null;\n\n\n\t/*******************************************************************************\n\t\tUI Bar Functions.\n\t*******************************************************************************/\n\n\tfunction uiBarDestroy() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarDestroy()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Hide the UI bar.\n\t\t_$uiBar.hide();\n\n\t\t// Remove its namespaced events.\n\t\tjQuery(document).off('.ui-bar');\n\n\t\t// Remove its styles.\n\t\tjQuery(document.head).find('#style-ui-bar').remove();\n\n\t\t// Remove it from the DOM.\n\t\t_$uiBar.remove();\n\n\t\t// Drop the reference to the element.\n\t\t_$uiBar = null;\n\t}\n\n\tfunction uiBarHide() {\n\t\tif (_$uiBar) {\n\t\t\t_$uiBar.hide();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarInit() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarInit()]'); }\n\n\t\tif (document.getElementById('ui-bar')) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Generate the UI bar elements.\n\t\tconst $elems = (() => {\n\t\t\tconst toggleLabel   = L10n.get('uiBarToggle');\n\t\t\tconst backwardLabel = L10n.get('uiBarBackward');\n\t\t\tconst jumptoLabel   = L10n.get('uiBarJumpto');\n\t\t\tconst forwardLabel  = L10n.get('uiBarForward');\n\n\t\t\treturn jQuery(document.createDocumentFragment())\n\t\t\t\t.append(\n\t\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t\t  '<div id=\"ui-bar\">'\n\t\t\t\t\t+     '<div id=\"ui-bar-tray\">'\n\t\t\t\t\t+         `<button id=\"ui-bar-toggle\" tabindex=\"0\" title=\"${toggleLabel}\" aria-label=\"${toggleLabel}\"></button>`\n\t\t\t\t\t+         '<div id=\"ui-bar-history\">'\n\t\t\t\t\t+             `<button id=\"history-backward\" tabindex=\"0\" title=\"${backwardLabel}\" aria-label=\"${backwardLabel}\">\\uE821</button>`\n\t\t\t\t\t+             `<button id=\"history-jumpto\" tabindex=\"0\" title=\"${jumptoLabel}\" aria-label=\"${jumptoLabel}\">\\uE839</button>`\n\t\t\t\t\t+             `<button id=\"history-forward\" tabindex=\"0\" title=\"${forwardLabel}\" aria-label=\"${forwardLabel}\">\\uE822</button>`\n\t\t\t\t\t+         '</div>'\n\t\t\t\t\t+     '</div>'\n\t\t\t\t\t+     '<div id=\"ui-bar-body\">'\n\t\t\t\t\t+         '<header id=\"title\" role=\"banner\">'\n\t\t\t\t\t+             '<div id=\"story-banner\"></div>'\n\t\t\t\t\t+             '<h1 id=\"story-title\"></h1>'\n\t\t\t\t\t+             '<div id=\"story-subtitle\"></div>'\n\t\t\t\t\t+             '<div id=\"story-title-separator\"></div>'\n\t\t\t\t\t+             '<p id=\"story-author\"></p>'\n\t\t\t\t\t+         '</header>'\n\t\t\t\t\t+         '<div id=\"story-caption\"></div>'\n\t\t\t\t\t+         '<nav id=\"menu\" role=\"navigation\">'\n\t\t\t\t\t+             '<ul id=\"menu-story\"></ul>'\n\t\t\t\t\t+             '<ul id=\"menu-core\">'\n\t\t\t\t\t+                 `<li id=\"menu-item-saves\"><a tabindex=\"0\">${L10n.get('savesTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-settings\"><a tabindex=\"0\">${L10n.get('settingsTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-restart\"><a tabindex=\"0\">${L10n.get('restartTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-share\"><a tabindex=\"0\">${L10n.get('shareTitle')}</a></li>`\n\t\t\t\t\t+             '</ul>'\n\t\t\t\t\t+         '</nav>'\n\t\t\t\t\t+     '</div>'\n\t\t\t\t\t+ '</div>'\n\t\t\t\t\t/* eslint-enable max-len */\n\t\t\t\t);\n\t\t})();\n\n\t\t/*\n\t\t\tCache the UI bar element, since its going to be used often.\n\n\t\t\tNOTE: We rewrap the element itself, rather than simply using the result\n\t\t\tof `find()`, so that we cache an uncluttered jQuery-wrapper (i.e. `context`\n\t\t\trefers to the element and there is no `prevObject`).\n\t\t*/\n\t\t_$uiBar = jQuery($elems.find('#ui-bar').get(0));\n\n\t\t// Insert the UI bar elements into the page before the main script.\n\t\t$elems.insertBefore('body>script#script-sugarcube');\n\n\t\t// Set up the UI bar's global event handlers.\n\t\tjQuery(document)\n\t\t\t// Set up a handler for the history-backward/-forward buttons.\n\t\t\t.on(':historyupdate.ui-bar', (($backward, $forward) => () => {\n\t\t\t\t$backward.ariaDisabled(State.length < 2);\n\t\t\t\t$forward.ariaDisabled(State.length === State.size);\n\t\t\t})(jQuery('#history-backward'), jQuery('#history-forward')));\n\t}\n\n\tfunction uiBarIsHidden() {\n\t\treturn _$uiBar && _$uiBar.css('display') === 'none';\n\t}\n\n\tfunction uiBarIsStowed() {\n\t\treturn _$uiBar && _$uiBar.hasClass('stowed');\n\t}\n\n\tfunction uiBarShow() {\n\t\tif (_$uiBar) {\n\t\t\t_$uiBar.show();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarStart() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarStart()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Set up the #ui-bar's initial state.\n\t\tif (\n\t\t\ttypeof Config.ui.stowBarInitially === 'boolean'\n\t\t\t\t? Config.ui.stowBarInitially\n\t\t\t\t: jQuery(window).width() <= Config.ui.stowBarInitially\n\t\t) {\n\t\t\tuiBarStow(true);\n\t\t}\n\n\t\t// Set up the #ui-bar-toggle and #ui-bar-history widgets.\n\t\tjQuery('#ui-bar-toggle')\n\t\t\t.ariaClick({\n\t\t\t\tlabel : L10n.get('uiBarToggle')\n\t\t\t}, () => _$uiBar.toggleClass('stowed'));\n\n\t\tif (Config.history.controls) {\n\t\t\tjQuery('#history-backward')\n\t\t\t\t.ariaDisabled(State.length < 2)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tlabel : L10n.get('uiBarBackward')\n\t\t\t\t}, () => Engine.backward());\n\n\t\t\tif (Story.lookup('tags', 'bookmark').length > 0) {\n\t\t\t\tjQuery('#history-jumpto')\n\t\t\t\t\t.ariaClick({\n\t\t\t\t\t\tlabel : L10n.get('uiBarJumpto')\n\t\t\t\t\t}, () => UI.jumpto());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery('#history-jumpto').remove();\n\t\t\t}\n\n\t\t\tjQuery('#history-forward')\n\t\t\t\t.ariaDisabled(State.length === State.size)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tlabel : L10n.get('uiBarForward')\n\t\t\t\t}, () => Engine.forward());\n\t\t}\n\t\telse {\n\t\t\tjQuery('#ui-bar-history').remove();\n\t\t}\n\n\t\t// Set up the story display title.\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t}\n\t\telse {\n\t\t\tif (TWINE1) { // for Twine 1\n\t\t\t\tsetPageElement('story-title', 'StoryTitle', Story.title);\n\t\t\t}\n\t\t\telse { // for Twine 2\n\t\t\t\tjQuery('#story-title').text(Story.title);\n\t\t\t}\n\t\t}\n\n\t\t// Set up the dynamic page elements.\n\t\tif (!Story.has('StoryCaption')) {\n\t\t\tjQuery('#story-caption').remove();\n\t\t}\n\n\t\tif (!Story.has('StoryMenu')) {\n\t\t\tjQuery('#menu-story').remove();\n\t\t}\n\n\t\tif (!Config.ui.updateStoryElements) {\n\t\t\t// We only need to set the story elements here if `Config.ui.updateStoryElements`\n\t\t\t// is falsy, since otherwise they will be set by `Engine.play()`.\n\t\t\tuiBarUpdate();\n\t\t}\n\n\t\t// Set up the Saves menu item.\n\t\tjQuery('#menu-item-saves a')\n\t\t\t.ariaClick(ev => {\n\t\t\t\tev.preventDefault();\n\t\t\t\tUI.buildSaves();\n\t\t\t\tDialog.open();\n\t\t\t})\n\t\t\t.text(L10n.get('savesTitle'));\n\n\t\t// Set up the Settings menu item.\n\t\tif (!Setting.isEmpty()) {\n\t\t\tjQuery('#menu-item-settings a')\n\t\t\t\t.ariaClick(ev => {\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\tUI.buildSettings();\n\t\t\t\t\tDialog.open();\n\t\t\t\t})\n\t\t\t\t.text(L10n.get('settingsTitle'));\n\t\t}\n\t\telse {\n\t\t\tjQuery('#menu-item-settings').remove();\n\t\t}\n\n\t\t// Set up the Restart menu item.\n\t\tjQuery('#menu-item-restart a')\n\t\t\t.ariaClick(ev => {\n\t\t\t\tev.preventDefault();\n\t\t\t\tUI.buildRestart();\n\t\t\t\tDialog.open();\n\t\t\t})\n\t\t\t.text(L10n.get('restartTitle'));\n\n\t\t// Set up the Share menu item.\n\t\tif (Story.has('StoryShare')) {\n\t\t\tjQuery('#menu-item-share a')\n\t\t\t\t.ariaClick(ev => {\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\tUI.buildShare();\n\t\t\t\t\tDialog.open();\n\t\t\t\t})\n\t\t\t\t.text(L10n.get('shareTitle'));\n\t\t}\n\t\telse {\n\t\t\tjQuery('#menu-item-share').remove();\n\t\t}\n\t}\n\n\tfunction uiBarStow(noAnimation) {\n\t\tif (_$uiBar && !_$uiBar.hasClass('stowed')) {\n\t\t\tlet $story;\n\n\t\t\tif (noAnimation) {\n\t\t\t\t$story = jQuery('#story');\n\t\t\t\t$story.addClass('no-transition');\n\t\t\t\t_$uiBar.addClass('no-transition');\n\t\t\t}\n\n\t\t\t_$uiBar.addClass('stowed');\n\n\t\t\tif (noAnimation) {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t$story.removeClass('no-transition');\n\t\t\t\t\t_$uiBar.removeClass('no-transition');\n\t\t\t\t}, Engine.minDomActionDelay);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarUnstow(noAnimation) {\n\t\tif (_$uiBar && _$uiBar.hasClass('stowed')) {\n\t\t\tlet $story;\n\n\t\t\tif (noAnimation) {\n\t\t\t\t$story = jQuery('#story');\n\t\t\t\t$story.addClass('no-transition');\n\t\t\t\t_$uiBar.addClass('no-transition');\n\t\t\t}\n\n\t\t\t_$uiBar.removeClass('stowed');\n\n\t\t\tif (noAnimation) {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t$story.removeClass('no-transition');\n\t\t\t\t\t_$uiBar.removeClass('no-transition');\n\t\t\t\t}, Engine.minDomActionDelay);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarUpdate() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarUpdate()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Set up the (non-navigation) dynamic page elements.\n\t\tsetPageElement('story-banner', 'StoryBanner');\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t}\n\t\tsetPageElement('story-subtitle', 'StorySubtitle');\n\t\tsetPageElement('story-author', 'StoryAuthor');\n\t\tsetPageElement('story-caption', 'StoryCaption');\n\n\t\t// Set up the #menu-story items.\n\t\tconst menuStory = document.getElementById('menu-story');\n\n\t\tif (menuStory !== null) {\n\t\t\tjQuery(menuStory).empty();\n\n\t\t\tif (Story.has('StoryMenu')) {\n\t\t\t\ttry {\n\t\t\t\t\tUI.assembleLinkList('StoryMenu', menuStory);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\tconsole.error(ex);\n\t\t\t\t\tAlert.error('StoryMenu', ex.message);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tdestroy  : { value : uiBarDestroy },\n\t\thide     : { value : uiBarHide },\n\t\tinit     : { value : uiBarInit },\n\t\tisHidden : { value : uiBarIsHidden },\n\t\tisStowed : { value : uiBarIsStowed },\n\t\tshow     : { value : uiBarShow },\n\t\tstart    : { value : uiBarStart },\n\t\tstow     : { value : uiBarStow },\n\t\tunstow   : { value : uiBarUnstow },\n\t\tupdate   : { value : uiBarUpdate },\n\n\t\t// Legacy Functions.\n\t\tsetStoryElements : { value : uiBarUpdate }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tdebugbar.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal DebugView, Engine, L10n, Patterns, State, Util, session\n*/\n\nvar DebugBar = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tconst _variableRe   = new RegExp(`^${Patterns.variable}$`);\n\tconst _numericKeyRe = /^\\d+$/;\n\tconst _watchList    = [];\n\tlet _$debugBar   = null;\n\tlet _$watchBody  = null;\n\tlet _$watchList  = null;\n\tlet _$turnSelect = null;\n\tlet _stowed      = true;\n\n\n\t/*******************************************************************************************************************\n\t\tDebug Bar Functions.\n\t*******************************************************************************************************************/\n\tfunction debugBarInit() {\n\t\tif (DEBUG) { console.log('[DebugBar/debugBarInit()]'); }\n\n\t\t/*\n\t\t\tGenerate the debug bar elements and append them to the `<body>`.\n\t\t*/\n\t\tconst barToggleLabel   = L10n.get('debugBarToggle');\n\t\tconst watchAddLabel    = L10n.get('debugBarAddWatch');\n\t\tconst watchAllLabel    = L10n.get('debugBarWatchAll');\n\t\tconst watchNoneLabel   = L10n.get('debugBarWatchNone');\n\t\tconst watchToggleLabel = L10n.get('debugBarWatchToggle');\n\t\tconst viewsToggleLabel = L10n.get('debugBarViewsToggle');\n\n\t\tjQuery(document.createDocumentFragment())\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  '<div id=\"debug-bar\">'\n\t\t\t\t+     '<div id=\"debug-bar-watch\">'\n\t\t\t\t+         `<div>${L10n.get('debugBarNoWatches')}</div>>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div>'\n\t\t\t\t+         `<button id=\"debug-bar-watch-toggle\" tabindex=\"0\" title=\"${watchToggleLabel}\" aria-label=\"${watchToggleLabel}\">${L10n.get('debugBarLabelWatch')}</button>`\n\t\t\t\t+         `<label id=\"debug-bar-watch-label\" for=\"debug-bar-watch-input\">${L10n.get('debugBarLabelAdd')}</label>`\n\t\t\t\t+         '<input id=\"debug-bar-watch-input\" name=\"debug-bar-watch-input\" type=\"text\" list=\"debug-bar-watch-list\" tabindex=\"0\">'\n\t\t\t\t+         '<datalist id=\"debug-bar-watch-list\" aria-hidden=\"true\" hidden=\"hidden\"></datalist>'\n\t\t\t\t+         `<button id=\"debug-bar-watch-add\" tabindex=\"0\" title=\"${watchAddLabel}\" aria-label=\"${watchAddLabel}\"></button>`\n\t\t\t\t+         `<button id=\"debug-bar-watch-all\" tabindex=\"0\" title=\"${watchAllLabel}\" aria-label=\"${watchAllLabel}\"></button>`\n\t\t\t\t+         `<button id=\"debug-bar-watch-none\" tabindex=\"0\" title=\"${watchNoneLabel}\" aria-label=\"${watchNoneLabel}\"></button>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div>'\n\t\t\t\t+         `<button id=\"debug-bar-views-toggle\" tabindex=\"0\" title=\"${viewsToggleLabel}\" aria-label=\"${viewsToggleLabel}\">${L10n.get('debugBarLabelViews')}</button>`\n\t\t\t\t+         `<label id=\"debug-bar-turn-label\" for=\"debug-bar-turn-select\">${L10n.get('debugBarLabelTurn')}</label>`\n\t\t\t\t+         '<select id=\"debug-bar-turn-select\" tabindex=\"0\"></select>'\n\t\t\t\t+     '</div>'\n\t\t\t\t+     `<button id=\"debug-bar-toggle\" tabindex=\"0\" title=\"${barToggleLabel}\" aria-label=\"${barToggleLabel}\"></button>`\n\t\t\t\t+ '</div>'\n\t\t\t\t+ '<div id=\"debug-bar-hint\"></div>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t)\n\t\t\t.appendTo('body');\n\n\t\t/*\n\t\t\tCache various oft used elements.\n\n\t\t\tNOTE: We rewrap the elements themselves, rather than simply using\n\t\t\tthe results of `find()`, so that we cache uncluttered jQuery-wrappers\n\t\t\t(i.e. `context` refers to the elements and there is no `prevObject`).\n\t\t*/\n\t\t_$debugBar   = jQuery('#debug-bar');\n\t\t_$watchBody  = jQuery(_$debugBar.find('#debug-bar-watch').get(0));\n\t\t_$watchList  = jQuery(_$debugBar.find('#debug-bar-watch-list').get(0));\n\t\t_$turnSelect = jQuery(_$debugBar.find('#debug-bar-turn-select').get(0));\n\n\t\tconst $barToggle   = jQuery(_$debugBar.find('#debug-bar-toggle').get(0));\n\t\tconst $watchToggle = jQuery(_$debugBar.find('#debug-bar-watch-toggle').get(0));\n\t\tconst $watchInput  = jQuery(_$debugBar.find('#debug-bar-watch-input').get(0));\n\t\tconst $watchAdd    = jQuery(_$debugBar.find('#debug-bar-watch-add').get(0));\n\t\tconst $watchAll    = jQuery(_$debugBar.find('#debug-bar-watch-all').get(0));\n\t\tconst $watchNone   = jQuery(_$debugBar.find('#debug-bar-watch-none').get(0));\n\t\tconst $viewsToggle = jQuery(_$debugBar.find('#debug-bar-views-toggle').get(0));\n\n\t\t/*\n\t\t\tSet up the debug bar's local event handlers.\n\t\t*/\n\t\t$barToggle\n\t\t\t.ariaClick(debugBarToggle);\n\t\t$watchToggle\n\t\t\t.ariaClick(debugBarWatchToggle);\n\t\t$watchInput\n\t\t\t.on(':addwatch', function () {\n\t\t\t\tdebugBarWatchAdd(this.value.trim());\n\t\t\t\tthis.value = '';\n\t\t\t})\n\t\t\t.on('keypress', ev => {\n\t\t\t\tif (ev.which === 13) { // 13 is Return/Enter\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t$watchInput.trigger(':addwatch');\n\t\t\t\t}\n\t\t\t});\n\t\t$watchAdd\n\t\t\t.ariaClick(() => $watchInput.trigger(':addwatch'));\n\t\t$watchAll\n\t\t\t.ariaClick(debugBarWatchAddAll);\n\t\t$watchNone\n\t\t\t.ariaClick(debugBarWatchClear);\n\t\t_$turnSelect\n\t\t\t.on('change', function () {\n\t\t\t\tEngine.goTo(Number(this.value));\n\t\t\t});\n\t\t$viewsToggle\n\t\t\t.ariaClick(() => {\n\t\t\t\tDebugView.toggle();\n\t\t\t\t_updateSession();\n\t\t\t});\n\n\t\t/*\n\t\t\tSet up the debug bar's global event handlers.\n\t\t*/\n\t\tjQuery(document)\n\t\t\t// Set up a handler for the history select.\n\t\t\t.on(':historyupdate.debug-bar', _updateTurnSelect)\n\t\t\t// Set up a handler for the variables watch.\n\t\t\t.on(':passageend.debug-bar', () => {\n\t\t\t\t_updateWatchBody();\n\t\t\t\t_updateWatchList();\n\t\t\t})\n\t\t\t// Set up a handler for engine resets to clear the active debug session.\n\t\t\t.on(':enginerestart.debug-bar', _clearSession);\n\n\t\t/*\n\t\t\tInitially enable debug views if there's no active debug session.\n\t\t*/\n\t\tif (!_hasSession()) {\n\t\t\tDebugView.enable();\n\t\t}\n\t}\n\n\tfunction debugBarStart() {\n\t\tif (DEBUG) { console.log('[DebugBar/debugBarStart()]'); }\n\n\t\t// Attempt to restore an existing session.\n\t\t_restoreSession();\n\n\t\t// Update the UI.\n\t\t_updateBar();\n\t\t_updateTurnSelect();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t}\n\n\tfunction debugBarIsStowed() {\n\t\treturn _stowed;\n\t}\n\n\tfunction debugBarStow() {\n\t\t_debugBarStowNoUpdate();\n\t\t_stowed = true;\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarUnstow() {\n\t\t_debugBarUnstowNoUpdate();\n\t\t_stowed = false;\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarToggle() {\n\t\tif (_stowed) {\n\t\t\tdebugBarUnstow();\n\t\t}\n\t\telse {\n\t\t\tdebugBarStow();\n\t\t}\n\t}\n\n\tfunction debugBarWatchAdd(varName) {\n\t\tif (!_variableRe.test(varName)) {\n\t\t\treturn;\n\t\t}\n\n\t\t_watchList.pushUnique(varName);\n\t\t_watchList.sort();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchAddAll() {\n\t\tObject.keys(State.variables).map(name => _watchList.pushUnique(`$${name}`));\n\t\tObject.keys(State.temporary).map(name => _watchList.pushUnique(`_${name}`));\n\n\t\t_watchList.sort();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchClear() {\n\t\tfor (let i = _watchList.length - 1; i >= 0; --i) {\n\t\t\t_watchList.pop();\n\t\t}\n\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchDelete(varName) {\n\t\t_watchList.delete(varName);\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchDisable() {\n\t\t_debugBarWatchDisableNoUpdate();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchEnable() {\n\t\t_debugBarWatchEnableNoUpdate();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchIsEnabled() {\n\t\treturn !_$watchBody.attr('hidden');\n\t}\n\n\tfunction debugBarWatchToggle() {\n\t\tif (_$watchBody.attr('hidden')) {\n\t\t\tdebugBarWatchEnable();\n\t\t}\n\t\telse {\n\t\t\tdebugBarWatchDisable();\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _debugBarStowNoUpdate() {\n\t\t_$debugBar.css('right', `-${_$debugBar.outerWidth()}px`);\n\t}\n\n\tfunction _debugBarUnstowNoUpdate() {\n\t\t_$debugBar.css('right', 0);\n\t}\n\n\tfunction _debugBarWatchDisableNoUpdate() {\n\t\t_$watchBody.attr({\n\t\t\t'aria-hidden' : true,\n\t\t\thidden        : 'hidden'\n\t\t});\n\t}\n\n\tfunction _debugBarWatchEnableNoUpdate() {\n\t\t_$watchBody.removeAttr('aria-hidden hidden');\n\t}\n\n\tfunction _clearSession() {\n\t\tsession.delete('debugState');\n\t}\n\n\tfunction _hasSession() {\n\t\treturn session.has('debugState');\n\t}\n\n\tfunction _restoreSession() {\n\t\tif (!_hasSession()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst debugState = session.get('debugState');\n\n\t\t_stowed = debugState.stowed;\n\n\t\t_watchList.push(...debugState.watchList);\n\n\t\tif (debugState.watchEnabled) {\n\t\t\t_debugBarWatchEnableNoUpdate();\n\t\t}\n\t\telse {\n\t\t\t_debugBarWatchDisableNoUpdate();\n\t\t}\n\n\t\tif (debugState.viewsEnabled) {\n\t\t\tDebugView.enable();\n\t\t}\n\t\telse {\n\t\t\tDebugView.disable();\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction _updateSession() {\n\t\tsession.set('debugState', {\n\t\t\tstowed       : _stowed,\n\t\t\twatchList    : _watchList,\n\t\t\twatchEnabled : debugBarWatchIsEnabled(),\n\t\t\tviewsEnabled : DebugView.isEnabled()\n\t\t});\n\t}\n\n\tfunction _updateBar() {\n\t\tif (_stowed) {\n\t\t\tdebugBarStow();\n\t\t}\n\t\telse {\n\t\t\tdebugBarUnstow();\n\t\t}\n\t}\n\n\tfunction _updateWatchBody() {\n\t\tif (_watchList.length === 0) {\n\t\t\t_$watchBody\n\t\t\t\t.empty()\n\t\t\t\t.append(`<div>${L10n.get('debugBarNoWatches')}</div>`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst delLabel = L10n.get('debugBarDeleteWatch');\n\t\tconst $table   = jQuery(document.createElement('table'));\n\t\tconst $tbody   = jQuery(document.createElement('tbody'));\n\n\t\tfor (let i = 0, len = _watchList.length; i < len; ++i) {\n\t\t\tconst varName = _watchList[i];\n\t\t\tconst varKey  = varName.slice(1);\n\t\t\tconst store   = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\tconst $row    = jQuery(document.createElement('tr'));\n\t\t\tconst $delBtn = jQuery(document.createElement('button'));\n\t\t\tconst $code   = jQuery(document.createElement('code'));\n\n\t\t\t$delBtn\n\t\t\t\t.addClass('watch-delete')\n\t\t\t\t.attr('data-name', varName)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tone   : true,\n\t\t\t\t\tlabel : delLabel\n\t\t\t\t}, () => debugBarWatchDelete(varName));\n\t\t\t$code\n\t\t\t\t.text(_toWatchString(store[varKey]));\n\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.append($delBtn)\n\t\t\t\t.appendTo($row);\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.text(varName)\n\t\t\t\t.appendTo($row);\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.append($code)\n\t\t\t\t.appendTo($row);\n\t\t\t$row\n\t\t\t\t.appendTo($tbody);\n\t\t}\n\n\t\t$table\n\t\t\t.append($tbody);\n\t\t_$watchBody\n\t\t\t.empty()\n\t\t\t.append($table);\n\t}\n\n\tfunction _updateWatchList() {\n\t\tconst svn = Object.keys(State.variables);\n\t\tconst tvn = Object.keys(State.temporary);\n\n\t\tif (svn.length === 0 && tvn.length === 0) {\n\t\t\t_$watchList.empty();\n\t\t\treturn;\n\t\t}\n\n\t\tconst names   = [...svn.map(name => `$${name}`), ...tvn.map(name => `_${name}`)].sort();\n\t\tconst options = document.createDocumentFragment();\n\n\t\tnames.delete(_watchList);\n\n\t\tfor (let i = 0, len = names.length; i < len; ++i) {\n\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t.val(names[i])\n\t\t\t\t.appendTo(options);\n\t\t}\n\n\t\t_$watchList\n\t\t\t.empty()\n\t\t\t.append(options);\n\t}\n\n\tfunction _updateTurnSelect() {\n\t\tconst histLen = State.size;\n\t\tconst expLen  = State.expired.length;\n\t\tconst options = document.createDocumentFragment();\n\n\t\tfor (let i = 0; i < histLen; ++i) {\n\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t.val(i)\n\t\t\t\t.text(`${expLen + i + 1}. ${Util.escape(State.history[i].title)}`)\n\t\t\t\t.appendTo(options);\n\t\t}\n\n\t\t_$turnSelect\n\t\t\t.empty()\n\t\t\t.ariaDisabled(histLen < 2)\n\t\t\t.append(options)\n\t\t\t.val(State.activeIndex);\n\t}\n\n\tfunction _toWatchString(value) {\n\t\t/*\n\t\t\tHandle the `null` primitive.\n\t\t*/\n\t\tif (value === null) {\n\t\t\treturn 'null';\n\t\t}\n\n\t\t/*\n\t\t\tHandle the rest of the primitives and functions.\n\t\t*/\n\t\tswitch (typeof value) {\n\t\tcase 'number':\n\t\t\tif (Number.isNaN(value)) {\n\t\t\t\treturn 'NaN';\n\t\t\t}\n\t\t\telse if (!Number.isFinite(value)) {\n\t\t\t\treturn 'Infinity';\n\t\t\t}\n\t\t\t/* falls through */\n\t\tcase 'boolean':\n\t\tcase 'symbol':\n\t\tcase 'undefined':\n\t\t\treturn String(value);\n\n\t\tcase 'string':\n\t\t\treturn JSON.stringify(value);\n\n\t\t// case 'symbol':\n\t\t// \treturn `Symbol\\u202F\"${String(value).slice(7, -1)}\"`;\n\n\t\tcase 'function':\n\t\t\t// return JSON.stringify(value.toString());\n\t\t\treturn 'Function';\n\t\t}\n\n\t\tconst objType = Util.toStringTag(value);\n\n\t\t// /*\n\t\t// \tHandle instances of the primitive exemplar objects (`Boolean`, `Number`, `String`).\n\t\t// */\n\t\t// if (objType === 'Boolean') {\n\t\t// \treturn `Boolean\\u202F{${String(value)}}`;\n\t\t// }\n\t\t// if (objType === 'Number') {\n\t\t// \treturn `Number\\u202F{${String(value)}}`;\n\t\t// }\n\t\t// if (objType === 'String') {\n\t\t// \treturn `String\\u202F{\"${String(value)}\"}`;\n\t\t// }\n\n\t\t/*\n\t\t\tHandle `Date` objects.\n\t\t*/\n\t\tif (objType === 'Date') {\n\t\t\t// return `Date\\u202F${value.toISOString()}`;\n\t\t\treturn `Date\\u202F{${value.toLocaleString()}}`;\n\t\t}\n\n\t\t/*\n\t\t\tHandle `RegExp` objects.\n\t\t*/\n\t\tif (objType === 'RegExp') {\n\t\t\treturn `RegExp\\u202F${value.toString()}`;\n\t\t}\n\n\t\tconst result = [];\n\n\t\t/*\n\t\t\tHandle `Array` & `Set` objects.\n\t\t*/\n\t\tif (value instanceof Array || value instanceof Set) {\n\t\t\tconst list = value instanceof Array ? value : Array.from(value);\n\n\t\t\t// own numeric properties\n\t\t\t// NOTE: Do not use `<Array>.forEach()` here as it skips undefined members.\n\t\t\tfor (let i = 0, len = list.length; i < len; ++i) {\n\t\t\t\tresult.push(list.hasOwnProperty(i) ? _toWatchString(list[i]) : '<empty>');\n\t\t\t}\n\n\t\t\t// own enumerable non-numeric expando properties\n\t\t\tObject.keys(list)\n\t\t\t\t.filter(key => !_numericKeyRe.test(key))\n\t\t\t\t.forEach(key => result.push(`${_toWatchString(key)}: ${_toWatchString(list[key])}`));\n\n\t\t\treturn `${objType}(${list.length})\\u202F[${result.join(', ')}]`;\n\t\t}\n\n\t\t/*\n\t\t\tHandle `Map` objects.\n\t\t*/\n\t\tif (value instanceof Map) {\n\t\t\tvalue.forEach((val, key) => result.push(`${_toWatchString(key)} \\u2192 ${_toWatchString(val)}`));\n\n\t\t\treturn `${objType}(${value.size})\\u202F{${result.join(', ')}}`;\n\t\t}\n\n\t\t/*\n\t\t\tGeneral object handling.\n\t\t*/\n\t\t// own enumerable properties\n\t\tObject.keys(value)\n\t\t\t.forEach(key => result.push(`${_toWatchString(key)}: ${_toWatchString(value[key])}`));\n\n\t\treturn `${objType}\\u202F{${result.join(', ')}}`;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tDebug Bar Functions.\n\t\t*/\n\t\tinit     : { value : debugBarInit },\n\t\tisStowed : { value : debugBarIsStowed },\n\t\tstart    : { value : debugBarStart },\n\t\tstow     : { value : debugBarStow },\n\t\ttoggle   : { value : debugBarToggle },\n\t\tunstow   : { value : debugBarUnstow },\n\n\t\t/*\n\t\t\tWatch Functions.\n\t\t*/\n\t\twatch : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd       : { value : debugBarWatchAdd },\n\t\t\t\tall       : { value : debugBarWatchAddAll },\n\t\t\t\tclear     : { value : debugBarWatchClear },\n\t\t\t\tdelete    : { value : debugBarWatchDelete },\n\t\t\t\tdisable   : { value : debugBarWatchDisable },\n\t\t\t\tenable    : { value : debugBarWatchEnable },\n\t\t\t\tisEnabled : { value : debugBarWatchIsEnabled },\n\t\t\t\ttoggle    : { value : debugBarWatchToggle }\n\t\t\t}))\n\t\t}\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tloadscreen.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Engine */\n\nvar LoadScreen = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Locks collection.\n\tconst _locks = new Set();\n\n\t// Auto-incrementing lock ID.\n\tlet _autoId = 0;\n\n\n\t/*******************************************************************************************************************\n\t\tLoadScreen Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tInitialize management of the loading screen.\n\t*/\n\tfunction loadScreenInit() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenInit()]'); }\n\n\t\t// Add a `readystatechange` listener for hiding/showing the loading screen.\n\t\tjQuery(document).on('readystatechange.SugarCube', () => {\n\t\t\tif (DEBUG) { console.log(`[LoadScreen/<readystatechange>] document.readyState: \"${document.readyState}\"; locks(${_locks.size}):`, _locks); }\n\n\t\t\tif (_locks.size > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// The value of `document.readyState` may be: 'loading' -> 'interactive' -> 'complete'.\n\t\t\t// Though, to reach this point, it must already be in, at least, the 'interactive' state.\n\t\t\tif (document.readyState === 'complete') {\n\t\t\t\tif (jQuery(document.documentElement).attr('data-init') === 'loading') {\n\t\t\t\t\tif (Config.loadDelay > 0) {\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tif (_locks.size === 0) {\n\t\t\t\t\t\t\t\tloadScreenHide();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, Math.max(Engine.minDomActionDelay, Config.loadDelay));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tloadScreenHide();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloadScreenShow();\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\tClear the loading screen.\n\t*/\n\tfunction loadScreenClear() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenClear()]'); }\n\n\t\t// Remove the event listener.\n\t\tjQuery(document).off('readystatechange.SugarCube');\n\n\t\t// Clear all locks.\n\t\t_locks.clear();\n\n\t\t// Hide the loading screen.\n\t\tloadScreenHide();\n\t}\n\n\t/*\n\t\tHide the loading screen.\n\t*/\n\tfunction loadScreenHide() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenHide()]'); }\n\n\t\tjQuery(document.documentElement).removeAttr('data-init');\n\t}\n\n\t/*\n\t\tShow the loading screen.\n\t*/\n\tfunction loadScreenShow() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenShow()]'); }\n\n\t\tjQuery(document.documentElement).attr('data-init', 'loading');\n\t}\n\n\t/*\n\t\tReturns a new lock ID after locking and showing the loading screen.\n\t*/\n\tfunction loadScreenLock() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenLock()]'); }\n\n\t\t++_autoId;\n\t\t_locks.add(_autoId);\n\n\t\tif (DEBUG) { console.log(`\\tacquired loading screen lock; id: ${_autoId}`); }\n\n\t\tloadScreenShow();\n\t\treturn _autoId;\n\t}\n\n\t/*\n\t\tRemove the lock associated with the given lock ID and, if no locks remain,\n\t\ttrigger a `readystatechange` event.\n\t*/\n\tfunction loadScreenUnlock(id) {\n\t\tif (DEBUG) { console.log(`[LoadScreen/loadScreenUnlock(id: ${id})]`); }\n\n\t\tif (id == null) { // lazy equality for null\n\t\t\tthrow new Error('LoadScreen.unlock called with a null or undefined ID');\n\t\t}\n\n\t\tif (_locks.has(id)) {\n\t\t\t_locks.delete(id);\n\n\t\t\tif (DEBUG) { console.log(`\\treleased loading screen lock; id: ${id}`); }\n\t\t}\n\n\t\tif (_locks.size === 0) {\n\t\t\tjQuery(document).trigger('readystatechange');\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : loadScreenInit },\n\t\tclear  : { value : loadScreenClear },\n\t\thide   : { value : loadScreenHide },\n\t\tshow   : { value : loadScreenShow },\n\t\tlock   : { value : loadScreenLock },\n\t\tunlock : { value : loadScreenUnlock }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tsugarcube.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Browser, Config, Dialog, Engine, Fullscreen, Has, LoadScreen, SimpleStore, L10n, Macro, Passage,\n\t       Save, Scripting, Setting, SimpleAudio, State, Story, UI, UIBar, DebugBar, Util, Visibility, Wikifier\n*/\n/* eslint-disable no-var */\n\n/*\n\tVersion object.\n*/\nvar version = Object.freeze({\n\ttitle      : 'SugarCube',\n\tmajor      : 2,\n\tminor      : 31,\n\tpatch      : 1,\n\tprerelease : null,\n\tbuild      : 21,\n\tdate       : new Date(\"2020-04-15T12:06:24.618Z\"),\n\t/* legacy */\n\textensions : {},\n\t/* /legacy */\n\n\ttoString() {\n\t\t'use strict';\n\n\t\tconst prerelease = this.prerelease ? `-${this.prerelease}` : '';\n\t\treturn `${this.major}.${this.minor}.${this.patch}${prerelease}+${this.build}`;\n\t},\n\n\tshort() {\n\t\t'use strict';\n\n\t\tconst prerelease = this.prerelease ? `-${this.prerelease}` : '';\n\t\treturn `${this.title} (v${this.major}.${this.minor}.${this.patch}${prerelease})`;\n\t},\n\n\tlong() {\n\t\t'use strict';\n\n\t\treturn `${this.title} v${this.toString()} (${this.date.toUTCString()})`;\n\t}\n});\n\n/* eslint-disable no-unused-vars */\n/*\n\tInternal variables.\n*/\n// Temporary state object.\nvar TempState = {};\n\n// Legacy macros object.\nvar macros = {};\n\n// Post-display task callbacks object.\nvar postdisplay = {};\n\n// Post-render task callbacks object.\nvar postrender = {};\n\n// Pre-display task callbacks object.\nvar predisplay = {};\n\n// Pre-history task callbacks object.\nvar prehistory = {};\n\n// Pre-render task callbacks object.\nvar prerender = {};\n\n// Session storage manager object.\nvar session = null;\n\n// Settings object.\nvar settings = {};\n\n// Setup object.\nvar setup = {};\n\n// Persistant storage manager object.\nvar storage = null;\n\n/*\n\tLegacy aliases.\n*/\nvar browser       = Browser;\nvar config        = Config;\nvar has           = Has;\nvar History       = State;\nvar state         = State;\nvar tale          = Story;\nvar TempVariables = State.temporary;\n/* eslint-enable no-unused-vars */\n\n/*\n\tGlobal `SugarCube` object.  Allows scripts to detect if they're running in SugarCube by\n\ttesting for the object (e.g. `\"SugarCube\" in window`) and contains exported identifiers\n\tfor debugging purposes.\n*/\nwindow.SugarCube = {};\n\n/*\n\tMain function, entry point for the story.\n*/\njQuery(() => {\n\t'use strict';\n\n\tif (DEBUG) { console.log('[SugarCube/main()] Document loaded; beginning startup.'); }\n\n\t/*\n\t\tWARNING!\n\n\t\tThe ordering of the code within this function is critically important,\n\t\tso be careful when mucking around with it.\n\t*/\n\ttry {\n\t\t// Acquire an initial lock for and initialize the loading screen.\n\t\tconst lockId = LoadScreen.lock();\n\t\tLoadScreen.init();\n\n\t\t// Normalize the document.\n\t\tif (document.normalize) {\n\t\t\tdocument.normalize();\n\t\t}\n\n\t\t// Load the story data (must be done before most anything else).\n\t\tStory.load();\n\n\t\t// Instantiate the storage and session objects.\n\t\t// NOTE: `SimpleStore.create(storageId, persistent)`\n\t\tstorage = SimpleStore.create(Story.domId, true);\n\t\tsession = SimpleStore.create(Story.domId, false);\n\n\t\t// Initialize the user interface (must be done before story initialization, specifically before scripts).\n\t\tDialog.init();\n\t\tUIBar.init();\n\t\tEngine.init();\n\n\t\t// Initialize the story (largely load the user styles, scripts, and widgets).\n\t\tStory.init();\n\n\t\t// Initialize the localization (must be done after story initialization).\n\t\tL10n.init();\n\n\t\t// Alert when the browser is degrading required capabilities (must be done after localization initialization).\n\t\tif (!session.has('rcWarn') && storage.name === 'cookie') {\n\t\t\t/* eslint-disable no-alert */\n\t\t\tsession.set('rcWarn', 1);\n\t\t\twindow.alert(L10n.get('warningNoWebStorage'));\n\t\t\t/* eslint-enable no-alert */\n\t\t}\n\n\t\t// Initialize the saves (must be done after story initialization, but before engine start).\n\t\tSave.init();\n\n\t\t// Initialize the settings.\n\t\tSetting.init();\n\n\t\t// Initialize the macros.\n\t\tMacro.init();\n\n\t\t// Start the engine (should be done as late as possible, but before interface startup).\n\t\tEngine.start();\n\n\t\t// Initialize the debug bar interface (should be done as late as possible, but before interface startup).\n\t\tif (Config.debug) {\n\t\t\tDebugBar.init();\n\t\t}\n\n\t\t// Set a recurring timer to start the interfaces (necessary due to DOM readiness issues in some browsers).\n\t\tconst $window    = $(window);\n\t\tconst vprCheckId = setInterval(() => {\n\t\t\t// If `$window.width()` returns a zero value, bail out and wait.\n\t\t\tif (!$window.width()) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Clear the recurring timer.\n\t\t\tclearInterval(vprCheckId);\n\n\t\t\t// Start the UI bar interface.\n\t\t\tUIBar.start();\n\n\t\t\t// Start the debug bar interface.\n\t\t\tif (Config.debug) {\n\t\t\t\tDebugBar.start();\n\t\t\t}\n\n\t\t\t// Trigger the `:storyready` global synthetic event.\n\t\t\tjQuery.event.trigger({ type : ':storyready' });\n\n\t\t\t// Release the loading screen lock after a short delay.\n\t\t\tsetTimeout(() => LoadScreen.unlock(lockId), Engine.minDomActionDelay * 2);\n\t\t}, Engine.minDomActionDelay);\n\n\t\t// Finally, export identifiers for debugging purposes.\n\t\tObject.defineProperty(window, 'SugarCube', {\n\t\t\t// WARNING: We need to assign new values at points, so seal it, do not freeze it.\n\t\t\tvalue : Object.seal(Object.assign(Object.create(null), {\n\t\t\t\tBrowser,\n\t\t\t\tConfig,\n\t\t\t\tDialog,\n\t\t\t\tEngine,\n\t\t\t\tFullscreen,\n\t\t\t\tHas,\n\t\t\t\tL10n,\n\t\t\t\tMacro,\n\t\t\t\tPassage,\n\t\t\t\tSave,\n\t\t\t\tScripting,\n\t\t\t\tSetting,\n\t\t\t\tSimpleAudio,\n\t\t\t\tState,\n\t\t\t\tStory,\n\t\t\t\tUI,\n\t\t\t\tUIBar,\n\t\t\t\tDebugBar,\n\t\t\t\tUtil,\n\t\t\t\tVisibility,\n\t\t\t\tWikifier,\n\t\t\t\tsession,\n\t\t\t\tsettings,\n\t\t\t\tsetup,\n\t\t\t\tstorage,\n\t\t\t\tversion\n\t\t\t}))\n\t\t});\n\n\t\tif (DEBUG) { console.log('[SugarCube/main()] Startup complete; story ready.'); }\n\t}\n\tcatch (ex) {\n\t\tconsole.error(ex);\n\t\tLoadScreen.clear();\n\t\treturn Alert.fatal(null, ex.message, ex);\n\t}\n});\n\n})(window, window.document, jQuery);\n}\n\t</script>\n</body>\n</html>\n"});
\ No newline at end of file
+window.storyFormat({"name":"SugarCube","version":"2.31.1","description":"A full featured, highly customizable story format.  See its <a href=\"http://www.motoslave.net/sugarcube/2/#documentation\" target=\"_blank\">documentation</a>.","author":"Thomas Michael Edwards","image":"icon.svg","url":"http://www.motoslave.net/sugarcube/","license":"BSD-2-Clause","proofing":false,"source":"<!DOCTYPE html>\n<html data-init=\"no-js\">\n<head>\n<meta charset=\"UTF-8\" />\n<title>{{STORY_NAME}}</title>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n<!--\n\nSugarCube (v2.31.1): A free (gratis and libre) story format.\n\nCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n-->\n<script id=\"script-libraries\" type=\"text/javascript\">\nif(document.head&&document.addEventListener&&document.querySelector&&Object.create&&Object.freeze&&JSON){document.documentElement.setAttribute(\"data-init\", \"loading\");\n/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js */\nif(\"document\" in self){if(!(\"classList\" in document.createElement(\"_\"))){(function(j){\"use strict\";if(!(\"Element\" in j)){return}var a=\"classList\",f=\"prototype\",m=j.Element[f],b=Object,k=String[f].trim||function(){return this.replace(/^\\s+|\\s+$/g,\"\")},c=Array[f].indexOf||function(q){var p=0,o=this.length;for(;p<o;p++){if(p in this&&this[p]===q){return p}}return -1},n=function(o,p){this.name=o;this.code=DOMException[o];this.message=p},g=function(p,o){if(o===\"\"){throw new n(\"SYNTAX_ERR\",\"An invalid or illegal string was specified\")}if(/\\s/.test(o)){throw new n(\"INVALID_CHARACTER_ERR\",\"String contains an invalid character\")}return c.call(p,o)},d=function(s){var r=k.call(s.getAttribute(\"class\")||\"\"),q=r?r.split(/\\s+/):[],p=0,o=q.length;for(;p<o;p++){this.push(q[p])}this._updateClassName=function(){s.setAttribute(\"class\",this.toString())}},e=d[f]=[],i=function(){return new d(this)};n[f]=Error[f];e.item=function(o){return this[o]||null};e.contains=function(o){o+=\"\";return g(this,o)!==-1};e.add=function(){var s=arguments,r=0,p=s.length,q,o=false;do{q=s[r]+\"\";if(g(this,q)===-1){this.push(q);o=true}}while(++r<p);if(o){this._updateClassName()}};e.remove=function(){var t=arguments,s=0,p=t.length,r,o=false,q;do{r=t[s]+\"\";q=g(this,r);while(q!==-1){this.splice(q,1);o=true;q=g(this,r)}}while(++s<p);if(o){this._updateClassName()}};e.toggle=function(p,q){p+=\"\";var o=this.contains(p),r=o?q!==true&&\"remove\":q!==false&&\"add\";if(r){this[r](p)}if(q===true||q===false){return q}else{return !o}};e.toString=function(){return this.join(\" \")};if(b.defineProperty){var l={get:i,enumerable:true,configurable:true};try{b.defineProperty(m,a,l)}catch(h){if(h.number===-2146823252){l.enumerable=false;b.defineProperty(m,a,l)}}}else{if(b[f].__defineGetter__){m.__defineGetter__(a,i)}}}(self))}else{(function(){var b=document.createElement(\"_\");b.classList.add(\"c1\",\"c2\");if(!b.classList.contains(\"c2\")){var c=function(e){var d=DOMTokenList.prototype[e];DOMTokenList.prototype[e]=function(h){var g,f=arguments.length;for(g=0;g<f;g++){h=arguments[g];d.call(this,h)}}};c(\"add\");c(\"remove\")}b.classList.toggle(\"c3\",false);if(b.classList.contains(\"c3\")){var a=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(d,e){if(1 in arguments&&!this.contains(d)===!e){return e}else{return a.call(this,d)}}}b=null}())}};\n/*!\n * https://github.com/es-shims/es5-shim\n * @license es5-shim Copyright 2009-2015 by contributors, MIT License\n * see https://github.com/es-shims/es5-shim/blob/v4.5.13/LICENSE\n */\n(function(t,r){\"use strict\";if(typeof define===\"function\"&&define.amd){define(r)}else if(typeof exports===\"object\"){module.exports=r()}else{t.returnExports=r()}})(this,function(){var t=Array;var r=t.prototype;var e=Object;var n=e.prototype;var i=Function;var a=i.prototype;var o=String;var f=o.prototype;var u=Number;var l=u.prototype;var s=r.slice;var c=r.splice;var v=r.push;var h=r.unshift;var p=r.concat;var y=r.join;var d=a.call;var g=a.apply;var w=Math.max;var b=Math.min;var T=n.toString;var m=typeof Symbol===\"function\"&&typeof Symbol.toStringTag===\"symbol\";var D;var S=Function.prototype.toString,x=/^\\s*class /,O=function isES6ClassFn(t){try{var r=S.call(t);var e=r.replace(/\\/\\/.*\\n/g,\"\");var n=e.replace(/\\/\\*[.\\s\\S]*\\*\\//g,\"\");var i=n.replace(/\\n/gm,\" \").replace(/ {2}/g,\" \");return x.test(i)}catch(a){return false}},E=function tryFunctionObject(t){try{if(O(t)){return false}S.call(t);return true}catch(r){return false}},j=\"[object Function]\",I=\"[object GeneratorFunction]\",D=function isCallable(t){if(!t){return false}if(typeof t!==\"function\"&&typeof t!==\"object\"){return false}if(m){return E(t)}if(O(t)){return false}var r=T.call(t);return r===j||r===I};var M;var U=RegExp.prototype.exec,$=function tryRegexExec(t){try{U.call(t);return true}catch(r){return false}},F=\"[object RegExp]\";M=function isRegex(t){if(typeof t!==\"object\"){return false}return m?$(t):T.call(t)===F};var N;var C=String.prototype.valueOf,k=function tryStringObject(t){try{C.call(t);return true}catch(r){return false}},A=\"[object String]\";N=function isString(t){if(typeof t===\"string\"){return true}if(typeof t!==\"object\"){return false}return m?k(t):T.call(t)===A};var R=e.defineProperty&&function(){try{var t={};e.defineProperty(t,\"x\",{enumerable:false,value:t});for(var r in t){return false}return t.x===t}catch(n){return false}}();var P=function(t){var r;if(R){r=function(t,r,n,i){if(!i&&r in t){return}e.defineProperty(t,r,{configurable:true,enumerable:false,writable:true,value:n})}}else{r=function(t,r,e,n){if(!n&&r in t){return}t[r]=e}}return function defineProperties(e,n,i){for(var a in n){if(t.call(n,a)){r(e,a,n[a],i)}}}}(n.hasOwnProperty);var J=function isPrimitive(t){var r=typeof t;return t===null||r!==\"object\"&&r!==\"function\"};var Y=u.isNaN||function isActualNaN(t){return t!==t};var z={ToInteger:function ToInteger(t){var r=+t;if(Y(r)){r=0}else if(r!==0&&r!==1/0&&r!==-(1/0)){r=(r>0||-1)*Math.floor(Math.abs(r))}return r},ToPrimitive:function ToPrimitive(t){var r,e,n;if(J(t)){return t}e=t.valueOf;if(D(e)){r=e.call(t);if(J(r)){return r}}n=t.toString;if(D(n)){r=n.call(t);if(J(r)){return r}}throw new TypeError},ToObject:function(t){if(t==null){throw new TypeError(\"can't convert \"+t+\" to object\")}return e(t)},ToUint32:function ToUint32(t){return t>>>0}};var Z=function Empty(){};P(a,{bind:function bind(t){var r=this;if(!D(r)){throw new TypeError(\"Function.prototype.bind called on incompatible \"+r)}var n=s.call(arguments,1);var a;var o=function(){if(this instanceof a){var i=g.call(r,this,p.call(n,s.call(arguments)));if(e(i)===i){return i}return this}else{return g.call(r,t,p.call(n,s.call(arguments)))}};var f=w(0,r.length-n.length);var u=[];for(var l=0;l<f;l++){v.call(u,\"$\"+l)}a=i(\"binder\",\"return function (\"+y.call(u,\",\")+\"){ return binder.apply(this, arguments); }\")(o);if(r.prototype){Z.prototype=r.prototype;a.prototype=new Z;Z.prototype=null}return a}});var G=d.bind(n.hasOwnProperty);var H=d.bind(n.toString);var W=d.bind(s);var B=g.bind(s);if(typeof document===\"object\"&&document&&document.documentElement){try{W(document.documentElement.childNodes)}catch(X){var L=W;var q=B;W=function arraySliceIE(t){var r=[];var e=t.length;while(e-- >0){r[e]=t[e]}return q(r,L(arguments,1))};B=function arraySliceApplyIE(t,r){return q(W(t),r)}}}var K=d.bind(f.slice);var Q=d.bind(f.split);var V=d.bind(f.indexOf);var _=d.bind(v);var tt=d.bind(n.propertyIsEnumerable);var rt=d.bind(r.sort);var et=t.isArray||function isArray(t){return H(t)===\"[object Array]\"};var nt=[].unshift(0)!==1;P(r,{unshift:function(){h.apply(this,arguments);return this.length}},nt);P(t,{isArray:et});var it=e(\"a\");var at=it[0]!==\"a\"||!(0 in it);var ot=function properlyBoxed(t){var r=true;var e=true;var n=false;if(t){try{t.call(\"foo\",function(t,e,n){if(typeof n!==\"object\"){r=false}});t.call([1],function(){\"use strict\";e=typeof this===\"string\"},\"x\")}catch(i){n=true}}return!!t&&!n&&r&&e};P(r,{forEach:function forEach(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=-1;var i=z.ToUint32(e.length);var a;if(arguments.length>1){a=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.forEach callback must be a function\")}while(++n<i){if(n in e){if(typeof a===\"undefined\"){t(e[n],n,r)}else{t.call(a,e[n],n,r)}}}}},!ot(r.forEach));P(r,{map:function map(r){var e=z.ToObject(this);var n=at&&N(this)?Q(this,\"\"):e;var i=z.ToUint32(n.length);var a=t(i);var o;if(arguments.length>1){o=arguments[1]}if(!D(r)){throw new TypeError(\"Array.prototype.map callback must be a function\")}for(var f=0;f<i;f++){if(f in n){if(typeof o===\"undefined\"){a[f]=r(n[f],f,e)}else{a[f]=r.call(o,n[f],f,e)}}}return a}},!ot(r.map));P(r,{filter:function filter(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i=[];var a;var o;if(arguments.length>1){o=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.filter callback must be a function\")}for(var f=0;f<n;f++){if(f in e){a=e[f];if(typeof o===\"undefined\"?t(a,f,r):t.call(o,a,f,r)){_(i,a)}}}return i}},!ot(r.filter));P(r,{every:function every(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i;if(arguments.length>1){i=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.every callback must be a function\")}for(var a=0;a<n;a++){if(a in e&&!(typeof i===\"undefined\"?t(e[a],a,r):t.call(i,e[a],a,r))){return false}}return true}},!ot(r.every));P(r,{some:function some(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i;if(arguments.length>1){i=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.some callback must be a function\")}for(var a=0;a<n;a++){if(a in e&&(typeof i===\"undefined\"?t(e[a],a,r):t.call(i,e[a],a,r))){return true}}return false}},!ot(r.some));var ft=false;if(r.reduce){ft=typeof r.reduce.call(\"es5\",function(t,r,e,n){return n})===\"object\"}P(r,{reduce:function reduce(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);if(!D(t)){throw new TypeError(\"Array.prototype.reduce callback must be a function\")}if(n===0&&arguments.length===1){throw new TypeError(\"reduce of empty array with no initial value\")}var i=0;var a;if(arguments.length>=2){a=arguments[1]}else{do{if(i in e){a=e[i++];break}if(++i>=n){throw new TypeError(\"reduce of empty array with no initial value\")}}while(true)}for(;i<n;i++){if(i in e){a=t(a,e[i],i,r)}}return a}},!ft);var ut=false;if(r.reduceRight){ut=typeof r.reduceRight.call(\"es5\",function(t,r,e,n){return n})===\"object\"}P(r,{reduceRight:function reduceRight(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);if(!D(t)){throw new TypeError(\"Array.prototype.reduceRight callback must be a function\")}if(n===0&&arguments.length===1){throw new TypeError(\"reduceRight of empty array with no initial value\")}var i;var a=n-1;if(arguments.length>=2){i=arguments[1]}else{do{if(a in e){i=e[a--];break}if(--a<0){throw new TypeError(\"reduceRight of empty array with no initial value\")}}while(true)}if(a<0){return i}do{if(a in e){i=t(i,e[a],a,r)}}while(a--);return i}},!ut);var lt=r.indexOf&&[0,1].indexOf(1,2)!==-1;P(r,{indexOf:function indexOf(t){var r=at&&N(this)?Q(this,\"\"):z.ToObject(this);var e=z.ToUint32(r.length);if(e===0){return-1}var n=0;if(arguments.length>1){n=z.ToInteger(arguments[1])}n=n>=0?n:w(0,e+n);for(;n<e;n++){if(n in r&&r[n]===t){return n}}return-1}},lt);var st=r.lastIndexOf&&[0,1].lastIndexOf(0,-3)!==-1;P(r,{lastIndexOf:function lastIndexOf(t){var r=at&&N(this)?Q(this,\"\"):z.ToObject(this);var e=z.ToUint32(r.length);if(e===0){return-1}var n=e-1;if(arguments.length>1){n=b(n,z.ToInteger(arguments[1]))}n=n>=0?n:e-Math.abs(n);for(;n>=0;n--){if(n in r&&t===r[n]){return n}}return-1}},st);var ct=function(){var t=[1,2];var r=t.splice();return t.length===2&&et(r)&&r.length===0}();P(r,{splice:function splice(t,r){if(arguments.length===0){return[]}else{return c.apply(this,arguments)}}},!ct);var vt=function(){var t={};r.splice.call(t,0,0,1);return t.length===1}();P(r,{splice:function splice(t,r){if(arguments.length===0){return[]}var e=arguments;this.length=w(z.ToInteger(this.length),0);if(arguments.length>0&&typeof r!==\"number\"){e=W(arguments);if(e.length<2){_(e,this.length-t)}else{e[1]=z.ToInteger(r)}}return c.apply(this,e)}},!vt);var ht=function(){var r=new t(1e5);r[8]=\"x\";r.splice(1,1);return r.indexOf(\"x\")===7}();var pt=function(){var t=256;var r=[];r[t]=\"a\";r.splice(t+1,0,\"b\");return r[t]===\"a\"}();P(r,{splice:function splice(t,r){var e=z.ToObject(this);var n=[];var i=z.ToUint32(e.length);var a=z.ToInteger(t);var f=a<0?w(i+a,0):b(a,i);var u=b(w(z.ToInteger(r),0),i-f);var l=0;var s;while(l<u){s=o(f+l);if(G(e,s)){n[l]=e[s]}l+=1}var c=W(arguments,2);var v=c.length;var h;if(v<u){l=f;var p=i-u;while(l<p){s=o(l+u);h=o(l+v);if(G(e,s)){e[h]=e[s]}else{delete e[h]}l+=1}l=i;var y=i-u+v;while(l>y){delete e[l-1];l-=1}}else if(v>u){l=i-u;while(l>f){s=o(l+u-1);h=o(l+v-1);if(G(e,s)){e[h]=e[s]}else{delete e[h]}l-=1}}l=f;for(var d=0;d<c.length;++d){e[l]=c[d];l+=1}e.length=i-u+v;return n}},!ht||!pt);var yt=r.join;var dt;try{dt=Array.prototype.join.call(\"123\",\",\")!==\"1,2,3\"}catch(X){dt=true}if(dt){P(r,{join:function join(t){var r=typeof t===\"undefined\"?\",\":t;return yt.call(N(this)?Q(this,\"\"):this,r)}},dt)}var gt=[1,2].join(undefined)!==\"1,2\";if(gt){P(r,{join:function join(t){var r=typeof t===\"undefined\"?\",\":t;return yt.call(this,r)}},gt)}var wt=function push(t){var r=z.ToObject(this);var e=z.ToUint32(r.length);var n=0;while(n<arguments.length){r[e+n]=arguments[n];n+=1}r.length=e+n;return e+n};var bt=function(){var t={};var r=Array.prototype.push.call(t,undefined);return r!==1||t.length!==1||typeof t[0]!==\"undefined\"||!G(t,0)}();P(r,{push:function push(t){if(et(this)){return v.apply(this,arguments)}return wt.apply(this,arguments)}},bt);var Tt=function(){var t=[];var r=t.push(undefined);return r!==1||t.length!==1||typeof t[0]!==\"undefined\"||!G(t,0)}();P(r,{push:wt},Tt);P(r,{slice:function(t,r){var e=N(this)?Q(this,\"\"):this;return B(e,arguments)}},at);var mt=function(){try{[1,2].sort(null)}catch(t){try{[1,2].sort({})}catch(r){return false}}return true}();var Dt=function(){try{[1,2].sort(/a/);return false}catch(t){}return true}();var St=function(){try{[1,2].sort(undefined);return true}catch(t){}return false}();P(r,{sort:function sort(t){if(typeof t===\"undefined\"){return rt(this)}if(!D(t)){throw new TypeError(\"Array.prototype.sort callback must be a function\")}return rt(this,t)}},mt||!St||!Dt);var xt=!tt({toString:null},\"toString\");var Ot=tt(function(){},\"prototype\");var Et=!G(\"x\",\"0\");var jt=function(t){var r=t.constructor;return r&&r.prototype===t};var It={$applicationCache:true,$console:true,$external:true,$frame:true,$frameElement:true,$frames:true,$innerHeight:true,$innerWidth:true,$onmozfullscreenchange:true,$onmozfullscreenerror:true,$outerHeight:true,$outerWidth:true,$pageXOffset:true,$pageYOffset:true,$parent:true,$scrollLeft:true,$scrollTop:true,$scrollX:true,$scrollY:true,$self:true,$webkitIndexedDB:true,$webkitStorageInfo:true,$window:true,$width:true,$height:true,$top:true,$localStorage:true};var Mt=function(){if(typeof window===\"undefined\"){return false}for(var t in window){try{if(!It[\"$\"+t]&&G(window,t)&&window[t]!==null&&typeof window[t]===\"object\"){jt(window[t])}}catch(r){return true}}return false}();var Ut=function(t){if(typeof window===\"undefined\"||!Mt){return jt(t)}try{return jt(t)}catch(r){return false}};var $t=[\"toString\",\"toLocaleString\",\"valueOf\",\"hasOwnProperty\",\"isPrototypeOf\",\"propertyIsEnumerable\",\"constructor\"];var Ft=$t.length;var Nt=function isArguments(t){return H(t)===\"[object Arguments]\"};var Ct=function isArguments(t){return t!==null&&typeof t===\"object\"&&typeof t.length===\"number\"&&t.length>=0&&!et(t)&&D(t.callee)};var kt=Nt(arguments)?Nt:Ct;P(e,{keys:function keys(t){var r=D(t);var e=kt(t);var n=t!==null&&typeof t===\"object\";var i=n&&N(t);if(!n&&!r&&!e){throw new TypeError(\"Object.keys called on a non-object\")}var a=[];var f=Ot&&r;if(i&&Et||e){for(var u=0;u<t.length;++u){_(a,o(u))}}if(!e){for(var l in t){if(!(f&&l===\"prototype\")&&G(t,l)){_(a,o(l))}}}if(xt){var s=Ut(t);for(var c=0;c<Ft;c++){var v=$t[c];if(!(s&&v===\"constructor\")&&G(t,v)){_(a,v)}}}return a}});var At=e.keys&&function(){return e.keys(arguments).length===2}(1,2);var Rt=e.keys&&function(){var t=e.keys(arguments);return arguments.length!==1||t.length!==1||t[0]!==1}(1);var Pt=e.keys;P(e,{keys:function keys(t){if(kt(t)){return Pt(W(t))}else{return Pt(t)}}},!At||Rt);var Jt=new Date(-0xc782b5b342b24).getUTCMonth()!==0;var Yt=new Date(-0x55d318d56a724);var zt=new Date(14496624e5);var Zt=Yt.toUTCString()!==\"Mon, 01 Jan -45875 11:59:59 GMT\";var Gt;var Ht;var Wt=Yt.getTimezoneOffset();if(Wt<-720){Gt=Yt.toDateString()!==\"Tue Jan 02 -45875\";Ht=!/^Thu Dec 10 2015 \\d\\d:\\d\\d:\\d\\d GMT[-+]\\d\\d\\d\\d(?: |$)/.test(String(zt))}else{Gt=Yt.toDateString()!==\"Mon Jan 01 -45875\";Ht=!/^Wed Dec 09 2015 \\d\\d:\\d\\d:\\d\\d GMT[-+]\\d\\d\\d\\d(?: |$)/.test(String(zt))}var Bt=d.bind(Date.prototype.getFullYear);var Xt=d.bind(Date.prototype.getMonth);var Lt=d.bind(Date.prototype.getDate);var qt=d.bind(Date.prototype.getUTCFullYear);var Kt=d.bind(Date.prototype.getUTCMonth);var Qt=d.bind(Date.prototype.getUTCDate);var Vt=d.bind(Date.prototype.getUTCDay);var _t=d.bind(Date.prototype.getUTCHours);var tr=d.bind(Date.prototype.getUTCMinutes);var rr=d.bind(Date.prototype.getUTCSeconds);var er=d.bind(Date.prototype.getUTCMilliseconds);var nr=[\"Sun\",\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\"];var ir=[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"];var ar=function daysInMonth(t,r){return Lt(new Date(r,t,0))};P(Date.prototype,{getFullYear:function getFullYear(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);if(t<0&&Xt(this)>11){return t+1}return t},getMonth:function getMonth(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);var r=Xt(this);if(t<0&&r>11){return 0}return r},getDate:function getDate(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);var r=Xt(this);var e=Lt(this);if(t<0&&r>11){if(r===12){return e}var n=ar(0,t+1);return n-e+1}return e},getUTCFullYear:function getUTCFullYear(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);if(t<0&&Kt(this)>11){return t+1}return t},getUTCMonth:function getUTCMonth(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);var r=Kt(this);if(t<0&&r>11){return 0}return r},getUTCDate:function getUTCDate(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);var r=Kt(this);var e=Qt(this);if(t<0&&r>11){if(r===12){return e}var n=ar(0,t+1);return n-e+1}return e}},Jt);P(Date.prototype,{toUTCString:function toUTCString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Vt(this);var r=Qt(this);var e=Kt(this);var n=qt(this);var i=_t(this);var a=tr(this);var o=rr(this);return nr[t]+\", \"+(r<10?\"0\"+r:r)+\" \"+ir[e]+\" \"+n+\" \"+(i<10?\"0\"+i:i)+\":\"+(a<10?\"0\"+a:a)+\":\"+(o<10?\"0\"+o:o)+\" GMT\"}},Jt||Zt);P(Date.prototype,{toDateString:function toDateString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=this.getDay();var r=this.getDate();var e=this.getMonth();var n=this.getFullYear();return nr[t]+\" \"+ir[e]+\" \"+(r<10?\"0\"+r:r)+\" \"+n}},Jt||Gt);if(Jt||Ht){Date.prototype.toString=function toString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=this.getDay();var r=this.getDate();var e=this.getMonth();var n=this.getFullYear();var i=this.getHours();var a=this.getMinutes();var o=this.getSeconds();var f=this.getTimezoneOffset();var u=Math.floor(Math.abs(f)/60);var l=Math.floor(Math.abs(f)%60);return nr[t]+\" \"+ir[e]+\" \"+(r<10?\"0\"+r:r)+\" \"+n+\" \"+(i<10?\"0\"+i:i)+\":\"+(a<10?\"0\"+a:a)+\":\"+(o<10?\"0\"+o:o)+\" GMT\"+(f>0?\"-\":\"+\")+(u<10?\"0\"+u:u)+(l<10?\"0\"+l:l)};if(R){e.defineProperty(Date.prototype,\"toString\",{configurable:true,enumerable:false,writable:true})}}var or=-621987552e5;var fr=\"-000001\";var ur=Date.prototype.toISOString&&new Date(or).toISOString().indexOf(fr)===-1;var lr=Date.prototype.toISOString&&new Date(-1).toISOString()!==\"1969-12-31T23:59:59.999Z\";var sr=d.bind(Date.prototype.getTime);P(Date.prototype,{toISOString:function toISOString(){if(!isFinite(this)||!isFinite(sr(this))){throw new RangeError(\"Date.prototype.toISOString called on non-finite value.\")}var t=qt(this);var r=Kt(this);t+=Math.floor(r/12);r=(r%12+12)%12;var e=[r+1,Qt(this),_t(this),tr(this),rr(this)];t=(t<0?\"-\":t>9999?\"+\":\"\")+K(\"00000\"+Math.abs(t),0<=t&&t<=9999?-4:-6);for(var n=0;n<e.length;++n){e[n]=K(\"00\"+e[n],-2)}return t+\"-\"+W(e,0,2).join(\"-\")+\"T\"+W(e,2).join(\":\")+\".\"+K(\"000\"+er(this),-3)+\"Z\"}},ur||lr);var cr=function(){try{return Date.prototype.toJSON&&new Date(NaN).toJSON()===null&&new Date(or).toJSON().indexOf(fr)!==-1&&Date.prototype.toJSON.call({toISOString:function(){return true}})}catch(t){return false}}();if(!cr){Date.prototype.toJSON=function toJSON(t){var r=e(this);var n=z.ToPrimitive(r);if(typeof n===\"number\"&&!isFinite(n)){return null}var i=r.toISOString;if(!D(i)){throw new TypeError(\"toISOString property is not callable\")}return i.call(r)}}var vr=Date.parse(\"+033658-09-27T01:46:40.000Z\")===1e15;var hr=!isNaN(Date.parse(\"2012-04-04T24:00:00.500Z\"))||!isNaN(Date.parse(\"2012-11-31T23:59:59.000Z\"))||!isNaN(Date.parse(\"2012-12-31T23:59:60.000Z\"));var pr=isNaN(Date.parse(\"2000-01-01T00:00:00.000Z\"));if(pr||hr||!vr){var yr=Math.pow(2,31)-1;var dr=Y(new Date(1970,0,1,0,0,0,yr+1).getTime());Date=function(t){var r=function Date(e,n,i,a,f,u,l){var s=arguments.length;var c;if(this instanceof t){var v=u;var h=l;if(dr&&s>=7&&l>yr){var p=Math.floor(l/yr)*yr;var y=Math.floor(p/1e3);v+=y;h-=y*1e3}c=s===1&&o(e)===e?new t(r.parse(e)):s>=7?new t(e,n,i,a,f,v,h):s>=6?new t(e,n,i,a,f,v):s>=5?new t(e,n,i,a,f):s>=4?new t(e,n,i,a):s>=3?new t(e,n,i):s>=2?new t(e,n):s>=1?new t(e instanceof t?+e:e):new t}else{c=t.apply(this,arguments)}if(!J(c)){P(c,{constructor:r},true)}return c};var e=new RegExp(\"^\"+\"(\\\\d{4}|[+-]\\\\d{6})\"+\"(?:-(\\\\d{2})\"+\"(?:-(\\\\d{2})\"+\"(?:\"+\"T(\\\\d{2})\"+\":(\\\\d{2})\"+\"(?:\"+\":(\\\\d{2})\"+\"(?:(\\\\.\\\\d{1,}))?\"+\")?\"+\"(\"+\"Z|\"+\"(?:\"+\"([-+])\"+\"(\\\\d{2})\"+\":(\\\\d{2})\"+\")\"+\")?)?)?)?\"+\"$\");var n=[0,31,59,90,120,151,181,212,243,273,304,334,365];var i=function dayFromMonth(t,r){var e=r>1?1:0;return n[r]+Math.floor((t-1969+e)/4)-Math.floor((t-1901+e)/100)+Math.floor((t-1601+e)/400)+365*(t-1970)};var a=function toUTC(r){var e=0;var n=r;if(dr&&n>yr){var i=Math.floor(n/yr)*yr;var a=Math.floor(i/1e3);e+=a;n-=a*1e3}return u(new t(1970,0,1,0,0,e,n))};for(var f in t){if(G(t,f)){r[f]=t[f]}}P(r,{now:t.now,UTC:t.UTC},true);r.prototype=t.prototype;P(r.prototype,{constructor:r},true);var l=function parse(r){var n=e.exec(r);if(n){var o=u(n[1]),f=u(n[2]||1)-1,l=u(n[3]||1)-1,s=u(n[4]||0),c=u(n[5]||0),v=u(n[6]||0),h=Math.floor(u(n[7]||0)*1e3),p=Boolean(n[4]&&!n[8]),y=n[9]===\"-\"?1:-1,d=u(n[10]||0),g=u(n[11]||0),w;var b=c>0||v>0||h>0;if(s<(b?24:25)&&c<60&&v<60&&h<1e3&&f>-1&&f<12&&d<24&&g<60&&l>-1&&l<i(o,f+1)-i(o,f)){w=((i(o,f)+l)*24+s+d*y)*60;w=((w+c+g*y)*60+v)*1e3+h;if(p){w=a(w)}if(-864e13<=w&&w<=864e13){return w}}return NaN}return t.parse.apply(this,arguments)};P(r,{parse:l});return r}(Date)}if(!Date.now){Date.now=function now(){return(new Date).getTime()}}var gr=l.toFixed&&(8e-5.toFixed(3)!==\"0.000\"||.9.toFixed(0)!==\"1\"||1.255.toFixed(2)!==\"1.25\"||(1000000000000000128).toFixed(0)!==\"1000000000000000128\");var wr={base:1e7,size:6,data:[0,0,0,0,0,0],multiply:function multiply(t,r){var e=-1;var n=r;while(++e<wr.size){n+=t*wr.data[e];wr.data[e]=n%wr.base;n=Math.floor(n/wr.base)}},divide:function divide(t){var r=wr.size;var e=0;while(--r>=0){e+=wr.data[r];wr.data[r]=Math.floor(e/t);e=e%t*wr.base}},numToString:function numToString(){var t=wr.size;var r=\"\";while(--t>=0){if(r!==\"\"||t===0||wr.data[t]!==0){var e=o(wr.data[t]);if(r===\"\"){r=e}else{r+=K(\"0000000\",0,7-e.length)+e}}}return r},pow:function pow(t,r,e){return r===0?e:r%2===1?pow(t,r-1,e*t):pow(t*t,r/2,e)},log:function log(t){var r=0;var e=t;while(e>=4096){r+=12;e/=4096}while(e>=2){r+=1;e/=2}return r}};var br=function toFixed(t){var r,e,n,i,a,f,l,s;r=u(t);r=Y(r)?0:Math.floor(r);if(r<0||r>20){throw new RangeError(\"Number.toFixed called with invalid number of decimals\")}e=u(this);if(Y(e)){return\"NaN\"}if(e<=-1e21||e>=1e21){return o(e)}n=\"\";if(e<0){n=\"-\";e=-e}i=\"0\";if(e>1e-21){a=wr.log(e*wr.pow(2,69,1))-69;f=a<0?e*wr.pow(2,-a,1):e/wr.pow(2,a,1);f*=4503599627370496;a=52-a;if(a>0){wr.multiply(0,f);l=r;while(l>=7){wr.multiply(1e7,0);l-=7}wr.multiply(wr.pow(10,l,1),0);l=a-1;while(l>=23){wr.divide(1<<23);l-=23}wr.divide(1<<l);wr.multiply(1,1);wr.divide(2);i=wr.numToString()}else{wr.multiply(0,f);wr.multiply(1<<-a,0);i=wr.numToString()+K(\"0.00000000000000000000\",2,2+r)}}if(r>0){s=i.length;if(s<=r){i=n+K(\"0.0000000000000000000\",0,r-s+2)+i}else{i=n+K(i,0,s-r)+\".\"+K(i,s-r)}}else{i=n+i}return i};P(l,{toFixed:br},gr);var Tr=function(){try{return 1..toPrecision(undefined)===\"1\"}catch(t){return true}}();var mr=l.toPrecision;P(l,{toPrecision:function toPrecision(t){return typeof t===\"undefined\"?mr.call(this):mr.call(this,t)}},Tr);if(\"ab\".split(/(?:ab)*/).length!==2||\".\".split(/(.?)(.?)/).length!==4||\"tesst\".split(/(s)*/)[1]===\"t\"||\"test\".split(/(?:)/,-1).length!==4||\"\".split(/.?/).length||\".\".split(/()()/).length>1){(function(){var t=typeof/()??/.exec(\"\")[1]===\"undefined\";var r=Math.pow(2,32)-1;f.split=function(e,n){var i=String(this);if(typeof e===\"undefined\"&&n===0){return[]}if(!M(e)){return Q(this,e,n)}var a=[];var o=(e.ignoreCase?\"i\":\"\")+(e.multiline?\"m\":\"\")+(e.unicode?\"u\":\"\")+(e.sticky?\"y\":\"\"),f=0,u,l,s,c;var h=new RegExp(e.source,o+\"g\");if(!t){u=new RegExp(\"^\"+h.source+\"$(?!\\\\s)\",o)}var p=typeof n===\"undefined\"?r:z.ToUint32(n);l=h.exec(i);while(l){s=l.index+l[0].length;if(s>f){_(a,K(i,f,l.index));if(!t&&l.length>1){l[0].replace(u,function(){for(var t=1;t<arguments.length-2;t++){if(typeof arguments[t]===\"undefined\"){l[t]=void 0}}})}if(l.length>1&&l.index<i.length){v.apply(a,W(l,1))}c=l[0].length;f=s;if(a.length>=p){break}}if(h.lastIndex===l.index){h.lastIndex++}l=h.exec(i)}if(f===i.length){if(c||!h.test(\"\")){_(a,\"\")}}else{_(a,K(i,f))}return a.length>p?W(a,0,p):a}})()}else if(\"0\".split(void 0,0).length){f.split=function split(t,r){if(typeof t===\"undefined\"&&r===0){return[]}return Q(this,t,r)}}var Dr=f.replace;var Sr=function(){var t=[];\"x\".replace(/x(.)?/g,function(r,e){_(t,e)});return t.length===1&&typeof t[0]===\"undefined\"}();if(!Sr){f.replace=function replace(t,r){var e=D(r);var n=M(t)&&/\\)[*?]/.test(t.source);if(!e||!n){return Dr.call(this,t,r)}else{var i=function(e){var n=arguments.length;var i=t.lastIndex;t.lastIndex=0;var a=t.exec(e)||[];t.lastIndex=i;_(a,arguments[n-2],arguments[n-1]);return r.apply(this,a)};return Dr.call(this,t,i)}}}var xr=f.substr;var Or=\"\".substr&&\"0b\".substr(-1)!==\"b\";P(f,{substr:function substr(t,r){var e=t;if(t<0){e=w(this.length+t,0)}return xr.call(this,e,r)}},Or);var Er=\"\\t\\n\\x0B\\f\\r \\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\"+\"\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\"+\"\\u2029\\ufeff\";var jr=\"\\u200b\";var Ir=\"[\"+Er+\"]\";var Mr=new RegExp(\"^\"+Ir+Ir+\"*\");var Ur=new RegExp(Ir+Ir+\"*$\");var $r=f.trim&&(Er.trim()||!jr.trim());P(f,{trim:function trim(){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}return o(this).replace(Mr,\"\").replace(Ur,\"\")}},$r);var Fr=d.bind(String.prototype.trim);var Nr=f.lastIndexOf&&\"abc\\u3042\\u3044\".lastIndexOf(\"\\u3042\\u3044\",2)!==-1;P(f,{lastIndexOf:function lastIndexOf(t){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}var r=o(this);var e=o(t);var n=arguments.length>1?u(arguments[1]):NaN;var i=Y(n)?Infinity:z.ToInteger(n);var a=b(w(i,0),r.length);var f=e.length;var l=a+f;while(l>0){l=w(0,l-f);var s=V(K(r,l,a+f),e);if(s!==-1){return l+s}}return-1}},Nr);var Cr=f.lastIndexOf;P(f,{lastIndexOf:function lastIndexOf(t){return Cr.apply(this,arguments)}},f.lastIndexOf.length!==1);if(parseInt(Er+\"08\")!==8||parseInt(Er+\"0x16\")!==22){parseInt=function(t){var r=/^[-+]?0[xX]/;return function parseInt(e,n){if(typeof e===\"symbol\"){\"\"+e}var i=Fr(String(e));var a=u(n)||(r.test(i)?16:10);return t(i,a)}}(parseInt)}if(1/parseFloat(\"-0\")!==-Infinity){parseFloat=function(t){return function parseFloat(r){var e=Fr(String(r));var n=t(e);return n===0&&K(e,0,1)===\"-\"?-0:n}}(parseFloat)}if(String(new RangeError(\"test\"))!==\"RangeError: test\"){var kr=function toString(){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}var t=this.name;if(typeof t===\"undefined\"){t=\"Error\"}else if(typeof t!==\"string\"){t=o(t)}var r=this.message;if(typeof r===\"undefined\"){r=\"\"}else if(typeof r!==\"string\"){r=o(r)}if(!t){return r}if(!r){return t}return t+\": \"+r};Error.prototype.toString=kr}if(R){var Ar=function(t,r){if(tt(t,r)){var e=Object.getOwnPropertyDescriptor(t,r);if(e.configurable){e.enumerable=false;Object.defineProperty(t,r,e)}}};Ar(Error.prototype,\"message\");if(Error.prototype.message!==\"\"){Error.prototype.message=\"\"}Ar(Error.prototype,\"name\")}if(String(/a/gim)!==\"/a/gim\"){var Rr=function toString(){var t=\"/\"+this.source+\"/\";if(this.global){t+=\"g\"}if(this.ignoreCase){t+=\"i\"}if(this.multiline){t+=\"m\"}return t};RegExp.prototype.toString=Rr}});\n//# sourceMappingURL=es5-shim.map\n/*!\n * https://github.com/paulmillr/es6-shim\n * @license es6-shim Copyright 2013-2016 by Paul Miller (http://paulmillr.com)\n *   and contributors,  MIT License\n * es6-shim: v0.35.4\n * see https://github.com/paulmillr/es6-shim/blob/0.35.4/LICENSE\n * Details and documentation:\n * https://github.com/paulmillr/es6-shim/\n */\n(function(e,t){if(typeof define===\"function\"&&define.amd){define(t)}else if(typeof exports===\"object\"){module.exports=t()}else{e.returnExports=t()}})(this,function(){\"use strict\";var e=Function.call.bind(Function.apply);var t=Function.call.bind(Function.call);var r=Array.isArray;var n=Object.keys;var o=function notThunker(t){return function notThunk(){return!e(t,this,arguments)}};var i=function(e){try{e();return false}catch(t){return true}};var a=function valueOrFalseIfThrows(e){try{return e()}catch(t){return false}};var u=o(i);var f=function(){return!i(function(){return Object.defineProperty({},\"x\",{get:function(){}})})};var s=!!Object.defineProperty&&f();var c=function foo(){}.name===\"foo\";var l=Function.call.bind(Array.prototype.forEach);var p=Function.call.bind(Array.prototype.reduce);var v=Function.call.bind(Array.prototype.filter);var y=Function.call.bind(Array.prototype.some);var h=function(e,t,r,n){if(!n&&t in e){return}if(s){Object.defineProperty(e,t,{configurable:true,enumerable:false,writable:true,value:r})}else{e[t]=r}};var b=function(e,t,r){l(n(t),function(n){var o=t[n];h(e,n,o,!!r)})};var g=Function.call.bind(Object.prototype.toString);var d=typeof/abc/===\"function\"?function IsCallableSlow(e){return typeof e===\"function\"&&g(e)===\"[object Function]\"}:function IsCallableFast(e){return typeof e===\"function\"};var m={getter:function(e,t,r){if(!s){throw new TypeError(\"getters require true ES5 support\")}Object.defineProperty(e,t,{configurable:true,enumerable:false,get:r})},proxy:function(e,t,r){if(!s){throw new TypeError(\"getters require true ES5 support\")}var n=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,{configurable:n.configurable,enumerable:n.enumerable,get:function getKey(){return e[t]},set:function setKey(r){e[t]=r}})},redefine:function(e,t,r){if(s){var n=Object.getOwnPropertyDescriptor(e,t);n.value=r;Object.defineProperty(e,t,n)}else{e[t]=r}},defineByDescriptor:function(e,t,r){if(s){Object.defineProperty(e,t,r)}else if(\"value\"in r){e[t]=r.value}},preserveToString:function(e,t){if(t&&d(t.toString)){h(e,\"toString\",t.toString.bind(t),true)}}};var O=Object.create||function(e,t){var r=function Prototype(){};r.prototype=e;var o=new r;if(typeof t!==\"undefined\"){n(t).forEach(function(e){m.defineByDescriptor(o,e,t[e])})}return o};var w=function(e,t){if(!Object.setPrototypeOf){return false}return a(function(){var r=function Subclass(t){var r=new e(t);Object.setPrototypeOf(r,Subclass.prototype);return r};Object.setPrototypeOf(r,e);r.prototype=O(e.prototype,{constructor:{value:r}});return t(r)})};var j=function(){if(typeof self!==\"undefined\"){return self}if(typeof window!==\"undefined\"){return window}if(typeof global!==\"undefined\"){return global}throw new Error(\"unable to locate global object\")};var S=j();var T=S.isFinite;var I=Function.call.bind(String.prototype.indexOf);var E=Function.apply.bind(Array.prototype.indexOf);var P=Function.call.bind(Array.prototype.concat);var C=Function.call.bind(String.prototype.slice);var M=Function.call.bind(Array.prototype.push);var x=Function.apply.bind(Array.prototype.push);var N=Function.call.bind(Array.prototype.shift);var A=Math.max;var R=Math.min;var _=Math.floor;var k=Math.abs;var L=Math.exp;var F=Math.log;var D=Math.sqrt;var z=Function.call.bind(Object.prototype.hasOwnProperty);var q;var W=function(){};var G=S.Map;var H=G&&G.prototype[\"delete\"];var V=G&&G.prototype.get;var B=G&&G.prototype.has;var U=G&&G.prototype.set;var $=S.Symbol||{};var J=$.species||\"@@species\";var X=Number.isNaN||function isNaN(e){return e!==e};var K=Number.isFinite||function isFinite(e){return typeof e===\"number\"&&T(e)};var Z=d(Math.sign)?Math.sign:function sign(e){var t=Number(e);if(t===0){return t}if(X(t)){return t}return t<0?-1:1};var Y=function log1p(e){var t=Number(e);if(t<-1||X(t)){return NaN}if(t===0||t===Infinity){return t}if(t===-1){return-Infinity}return 1+t-1===0?t:t*(F(1+t)/(1+t-1))};var Q=function isArguments(e){return g(e)===\"[object Arguments]\"};var ee=function isArguments(e){return e!==null&&typeof e===\"object\"&&typeof e.length===\"number\"&&e.length>=0&&g(e)!==\"[object Array]\"&&g(e.callee)===\"[object Function]\"};var te=Q(arguments)?Q:ee;var re={primitive:function(e){return e===null||typeof e!==\"function\"&&typeof e!==\"object\"},string:function(e){return g(e)===\"[object String]\"},regex:function(e){return g(e)===\"[object RegExp]\"},symbol:function(e){return typeof S.Symbol===\"function\"&&typeof e===\"symbol\"}};var ne=function overrideNative(e,t,r){var n=e[t];h(e,t,r,true);m.preserveToString(e[t],n)};var oe=typeof $===\"function\"&&typeof $[\"for\"]===\"function\"&&re.symbol($());var ie=re.symbol($.iterator)?$.iterator:\"_es6-shim iterator_\";if(S.Set&&typeof(new S.Set)[\"@@iterator\"]===\"function\"){ie=\"@@iterator\"}if(!S.Reflect){h(S,\"Reflect\",{},true)}var ae=S.Reflect;var ue=String;var fe=typeof document===\"undefined\"||!document?null:document.all;var se=fe==null?function isNullOrUndefined(e){return e==null}:function isNullOrUndefinedAndNotDocumentAll(e){return e==null&&e!==fe};var ce={Call:function Call(t,r){var n=arguments.length>2?arguments[2]:[];if(!ce.IsCallable(t)){throw new TypeError(t+\" is not a function\")}return e(t,r,n)},RequireObjectCoercible:function(e,t){if(se(e)){throw new TypeError(t||\"Cannot call method on \"+e)}return e},TypeIsObject:function(e){if(e===void 0||e===null||e===true||e===false){return false}return typeof e===\"function\"||typeof e===\"object\"||e===fe},ToObject:function(e,t){return Object(ce.RequireObjectCoercible(e,t))},IsCallable:d,IsConstructor:function(e){return ce.IsCallable(e)},ToInt32:function(e){return ce.ToNumber(e)>>0},ToUint32:function(e){return ce.ToNumber(e)>>>0},ToNumber:function(e){if(g(e)===\"[object Symbol]\"){throw new TypeError(\"Cannot convert a Symbol value to a number\")}return+e},ToInteger:function(e){var t=ce.ToNumber(e);if(X(t)){return 0}if(t===0||!K(t)){return t}return(t>0?1:-1)*_(k(t))},ToLength:function(e){var t=ce.ToInteger(e);if(t<=0){return 0}if(t>Number.MAX_SAFE_INTEGER){return Number.MAX_SAFE_INTEGER}return t},SameValue:function(e,t){if(e===t){if(e===0){return 1/e===1/t}return true}return X(e)&&X(t)},SameValueZero:function(e,t){return e===t||X(e)&&X(t)},IsIterable:function(e){return ce.TypeIsObject(e)&&(typeof e[ie]!==\"undefined\"||te(e))},GetIterator:function(e){if(te(e)){return new q(e,\"value\")}var t=ce.GetMethod(e,ie);if(!ce.IsCallable(t)){throw new TypeError(\"value is not an iterable\")}var r=ce.Call(t,e);if(!ce.TypeIsObject(r)){throw new TypeError(\"bad iterator\")}return r},GetMethod:function(e,t){var r=ce.ToObject(e)[t];if(se(r)){return void 0}if(!ce.IsCallable(r)){throw new TypeError(\"Method not callable: \"+t)}return r},IteratorComplete:function(e){return!!e.done},IteratorClose:function(e,t){var r=ce.GetMethod(e,\"return\");if(r===void 0){return}var n,o;try{n=ce.Call(r,e)}catch(i){o=i}if(t){return}if(o){throw o}if(!ce.TypeIsObject(n)){throw new TypeError(\"Iterator's return method returned a non-object.\")}},IteratorNext:function(e){var t=arguments.length>1?e.next(arguments[1]):e.next();if(!ce.TypeIsObject(t)){throw new TypeError(\"bad iterator\")}return t},IteratorStep:function(e){var t=ce.IteratorNext(e);var r=ce.IteratorComplete(t);return r?false:t},Construct:function(e,t,r,n){var o=typeof r===\"undefined\"?e:r;if(!n&&ae.construct){return ae.construct(e,t,o)}var i=o.prototype;if(!ce.TypeIsObject(i)){i=Object.prototype}var a=O(i);var u=ce.Call(e,a,t);return ce.TypeIsObject(u)?u:a},SpeciesConstructor:function(e,t){var r=e.constructor;if(r===void 0){return t}if(!ce.TypeIsObject(r)){throw new TypeError(\"Bad constructor\")}var n=r[J];if(se(n)){return t}if(!ce.IsConstructor(n)){throw new TypeError(\"Bad @@species\")}return n},CreateHTML:function(e,t,r,n){var o=ce.ToString(e);var i=\"<\"+t;if(r!==\"\"){var a=ce.ToString(n);var u=a.replace(/\"/g,\"&quot;\");i+=\" \"+r+'=\"'+u+'\"'}var f=i+\">\";var s=f+o;return s+\"</\"+t+\">\"},IsRegExp:function IsRegExp(e){if(!ce.TypeIsObject(e)){return false}var t=e[$.match];if(typeof t!==\"undefined\"){return!!t}return re.regex(e)},ToString:function ToString(e){return ue(e)}};if(s&&oe){var le=function defineWellKnownSymbol(e){if(re.symbol($[e])){return $[e]}var t=$[\"for\"](\"Symbol.\"+e);Object.defineProperty($,e,{configurable:false,enumerable:false,writable:false,value:t});return t};if(!re.symbol($.search)){var pe=le(\"search\");var ve=String.prototype.search;h(RegExp.prototype,pe,function search(e){return ce.Call(ve,e,[this])});var ye=function search(e){var t=ce.RequireObjectCoercible(this);if(!se(e)){var r=ce.GetMethod(e,pe);if(typeof r!==\"undefined\"){return ce.Call(r,e,[t])}}return ce.Call(ve,t,[ce.ToString(e)])};ne(String.prototype,\"search\",ye)}if(!re.symbol($.replace)){var he=le(\"replace\");var be=String.prototype.replace;h(RegExp.prototype,he,function replace(e,t){return ce.Call(be,e,[this,t])});var ge=function replace(e,t){var r=ce.RequireObjectCoercible(this);if(!se(e)){var n=ce.GetMethod(e,he);if(typeof n!==\"undefined\"){return ce.Call(n,e,[r,t])}}return ce.Call(be,r,[ce.ToString(e),t])};ne(String.prototype,\"replace\",ge)}if(!re.symbol($.split)){var de=le(\"split\");var me=String.prototype.split;h(RegExp.prototype,de,function split(e,t){return ce.Call(me,e,[this,t])});var Oe=function split(e,t){var r=ce.RequireObjectCoercible(this);if(!se(e)){var n=ce.GetMethod(e,de);if(typeof n!==\"undefined\"){return ce.Call(n,e,[r,t])}}return ce.Call(me,r,[ce.ToString(e),t])};ne(String.prototype,\"split\",Oe)}var we=re.symbol($.match);var je=we&&function(){var e={};e[$.match]=function(){return 42};return\"a\".match(e)!==42}();if(!we||je){var Se=le(\"match\");var Te=String.prototype.match;h(RegExp.prototype,Se,function match(e){return ce.Call(Te,e,[this])});var Ie=function match(e){var t=ce.RequireObjectCoercible(this);if(!se(e)){var r=ce.GetMethod(e,Se);if(typeof r!==\"undefined\"){return ce.Call(r,e,[t])}}return ce.Call(Te,t,[ce.ToString(e)])};ne(String.prototype,\"match\",Ie)}}var Ee=function wrapConstructor(e,t,r){m.preserveToString(t,e);if(Object.setPrototypeOf){Object.setPrototypeOf(e,t)}if(s){l(Object.getOwnPropertyNames(e),function(n){if(n in W||r[n]){return}m.proxy(e,n,t)})}else{l(Object.keys(e),function(n){if(n in W||r[n]){return}t[n]=e[n]})}t.prototype=e.prototype;m.redefine(e.prototype,\"constructor\",t)};var Pe=function(){return this};var Ce=function(e){if(s&&!z(e,J)){m.getter(e,J,Pe)}};var Me=function(e,t){var r=t||function iterator(){return this};h(e,ie,r);if(!e[ie]&&re.symbol(ie)){e[ie]=r}};var xe=function createDataProperty(e,t,r){if(s){Object.defineProperty(e,t,{configurable:true,enumerable:true,writable:true,value:r})}else{e[t]=r}};var Ne=function createDataPropertyOrThrow(e,t,r){xe(e,t,r);if(!ce.SameValue(e[t],r)){throw new TypeError(\"property is nonconfigurable\")}};var Ae=function(e,t,r,n){if(!ce.TypeIsObject(e)){throw new TypeError(\"Constructor requires `new`: \"+t.name)}var o=t.prototype;if(!ce.TypeIsObject(o)){o=r}var i=O(o);for(var a in n){if(z(n,a)){var u=n[a];h(i,a,u,true)}}return i};if(String.fromCodePoint&&String.fromCodePoint.length!==1){var Re=String.fromCodePoint;ne(String,\"fromCodePoint\",function fromCodePoint(e){return ce.Call(Re,this,arguments)})}var _e={fromCodePoint:function fromCodePoint(e){var t=[];var r;for(var n=0,o=arguments.length;n<o;n++){r=Number(arguments[n]);if(!ce.SameValue(r,ce.ToInteger(r))||r<0||r>1114111){throw new RangeError(\"Invalid code point \"+r)}if(r<65536){M(t,String.fromCharCode(r))}else{r-=65536;M(t,String.fromCharCode((r>>10)+55296));M(t,String.fromCharCode(r%1024+56320))}}return t.join(\"\")},raw:function raw(e){var t=ce.ToObject(e,\"bad callSite\");var r=ce.ToObject(t.raw,\"bad raw value\");var n=r.length;var o=ce.ToLength(n);if(o<=0){return\"\"}var i=[];var a=0;var u,f,s,c;while(a<o){u=ce.ToString(a);s=ce.ToString(r[u]);M(i,s);if(a+1>=o){break}f=a+1<arguments.length?arguments[a+1]:\"\";c=ce.ToString(f);M(i,c);a+=1}return i.join(\"\")}};if(String.raw&&String.raw({raw:{0:\"x\",1:\"y\",length:2}})!==\"xy\"){ne(String,\"raw\",_e.raw)}b(String,_e);var ke=function repeat(e,t){if(t<1){return\"\"}if(t%2){return repeat(e,t-1)+e}var r=repeat(e,t/2);return r+r};var Le=Infinity;var Fe={repeat:function repeat(e){var t=ce.ToString(ce.RequireObjectCoercible(this));var r=ce.ToInteger(e);if(r<0||r>=Le){throw new RangeError(\"repeat count must be less than infinity and not overflow maximum string size\")}return ke(t,r)},startsWith:function startsWith(e){var t=ce.ToString(ce.RequireObjectCoercible(this));if(ce.IsRegExp(e)){throw new TypeError('Cannot call method \"startsWith\" with a regex')}var r=ce.ToString(e);var n;if(arguments.length>1){n=arguments[1]}var o=A(ce.ToInteger(n),0);return C(t,o,o+r.length)===r},endsWith:function endsWith(e){var t=ce.ToString(ce.RequireObjectCoercible(this));if(ce.IsRegExp(e)){throw new TypeError('Cannot call method \"endsWith\" with a regex')}var r=ce.ToString(e);var n=t.length;var o;if(arguments.length>1){o=arguments[1]}var i=typeof o===\"undefined\"?n:ce.ToInteger(o);var a=R(A(i,0),n);return C(t,a-r.length,a)===r},includes:function includes(e){if(ce.IsRegExp(e)){throw new TypeError('\"includes\" does not accept a RegExp')}var t=ce.ToString(e);var r;if(arguments.length>1){r=arguments[1]}return I(this,t,r)!==-1},codePointAt:function codePointAt(e){var t=ce.ToString(ce.RequireObjectCoercible(this));var r=ce.ToInteger(e);var n=t.length;if(r>=0&&r<n){var o=t.charCodeAt(r);var i=r+1===n;if(o<55296||o>56319||i){return o}var a=t.charCodeAt(r+1);if(a<56320||a>57343){return o}return(o-55296)*1024+(a-56320)+65536}}};if(String.prototype.includes&&\"a\".includes(\"a\",Infinity)!==false){ne(String.prototype,\"includes\",Fe.includes)}if(String.prototype.startsWith&&String.prototype.endsWith){var De=i(function(){return\"/a/\".startsWith(/a/)});var ze=a(function(){return\"abc\".startsWith(\"a\",Infinity)===false});if(!De||!ze){ne(String.prototype,\"startsWith\",Fe.startsWith);ne(String.prototype,\"endsWith\",Fe.endsWith)}}if(oe){var qe=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".startsWith(e)});if(!qe){ne(String.prototype,\"startsWith\",Fe.startsWith)}var We=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".endsWith(e)});if(!We){ne(String.prototype,\"endsWith\",Fe.endsWith)}var Ge=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".includes(e)});if(!Ge){ne(String.prototype,\"includes\",Fe.includes)}}b(String.prototype,Fe);var He=[\"\\t\\n\\x0B\\f\\r \\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\",\"\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\",\"\\u2029\\ufeff\"].join(\"\");var Ve=new RegExp(\"(^[\"+He+\"]+)|([\"+He+\"]+$)\",\"g\");var Be=function trim(){return ce.ToString(ce.RequireObjectCoercible(this)).replace(Ve,\"\")};var Ue=[\"\\x85\",\"\\u200b\",\"\\ufffe\"].join(\"\");var $e=new RegExp(\"[\"+Ue+\"]\",\"g\");var Je=/^[-+]0x[0-9a-f]+$/i;var Xe=Ue.trim().length!==Ue.length;h(String.prototype,\"trim\",Be,Xe);var Ke=function(e){return{value:e,done:arguments.length===0}};var Ze=function(e){ce.RequireObjectCoercible(e);this._s=ce.ToString(e);this._i=0};Ze.prototype.next=function(){var e=this._s;var t=this._i;if(typeof e===\"undefined\"||t>=e.length){this._s=void 0;return Ke()}var r=e.charCodeAt(t);var n,o;if(r<55296||r>56319||t+1===e.length){o=1}else{n=e.charCodeAt(t+1);o=n<56320||n>57343?1:2}this._i=t+o;return Ke(e.substr(t,o))};Me(Ze.prototype);Me(String.prototype,function(){return new Ze(this)});var Ye={from:function from(e){var r=this;var n;if(arguments.length>1){n=arguments[1]}var o,i;if(typeof n===\"undefined\"){o=false}else{if(!ce.IsCallable(n)){throw new TypeError(\"Array.from: when provided, the second argument must be a function\")}if(arguments.length>2){i=arguments[2]}o=true}var a=typeof(te(e)||ce.GetMethod(e,ie))!==\"undefined\";var u,f,s;if(a){f=ce.IsConstructor(r)?Object(new r):[];var c=ce.GetIterator(e);var l,p;s=0;while(true){l=ce.IteratorStep(c);if(l===false){break}p=l.value;try{if(o){p=typeof i===\"undefined\"?n(p,s):t(n,i,p,s)}f[s]=p}catch(v){ce.IteratorClose(c,true);throw v}s+=1}u=s}else{var y=ce.ToObject(e);u=ce.ToLength(y.length);f=ce.IsConstructor(r)?Object(new r(u)):new Array(u);var h;for(s=0;s<u;++s){h=y[s];if(o){h=typeof i===\"undefined\"?n(h,s):t(n,i,h,s)}Ne(f,s,h)}}f.length=u;return f},of:function of(){var e=arguments.length;var t=this;var n=r(t)||!ce.IsCallable(t)?new Array(e):ce.Construct(t,[e]);for(var o=0;o<e;++o){Ne(n,o,arguments[o])}n.length=e;return n}};b(Array,Ye);Ce(Array);q=function(e,t){this.i=0;this.array=e;this.kind=t};b(q.prototype,{next:function(){var e=this.i;var t=this.array;if(!(this instanceof q)){throw new TypeError(\"Not an ArrayIterator\")}if(typeof t!==\"undefined\"){var r=ce.ToLength(t.length);for(;e<r;e++){var n=this.kind;var o;if(n===\"key\"){o=e}else if(n===\"value\"){o=t[e]}else if(n===\"entry\"){o=[e,t[e]]}this.i=e+1;return Ke(o)}}this.array=void 0;return Ke()}});Me(q.prototype);var Qe=Array.of===Ye.of||function(){var e=function Foo(e){this.length=e};e.prototype=[];var t=Array.of.apply(e,[1,2]);return t instanceof e&&t.length===2}();if(!Qe){ne(Array,\"of\",Ye.of)}var et={copyWithin:function copyWithin(e,t){var r=ce.ToObject(this);var n=ce.ToLength(r.length);var o=ce.ToInteger(e);var i=ce.ToInteger(t);var a=o<0?A(n+o,0):R(o,n);var u=i<0?A(n+i,0):R(i,n);var f;if(arguments.length>2){f=arguments[2]}var s=typeof f===\"undefined\"?n:ce.ToInteger(f);var c=s<0?A(n+s,0):R(s,n);var l=R(c-u,n-a);var p=1;if(u<a&&a<u+l){p=-1;u+=l-1;a+=l-1}while(l>0){if(u in r){r[a]=r[u]}else{delete r[a]}u+=p;a+=p;l-=1}return r},fill:function fill(e){var t;if(arguments.length>1){t=arguments[1]}var r;if(arguments.length>2){r=arguments[2]}var n=ce.ToObject(this);var o=ce.ToLength(n.length);t=ce.ToInteger(typeof t===\"undefined\"?0:t);r=ce.ToInteger(typeof r===\"undefined\"?o:r);var i=t<0?A(o+t,0):R(t,o);var a=r<0?o+r:r;for(var u=i;u<o&&u<a;++u){n[u]=e}return n},find:function find(e){var r=ce.ToObject(this);var n=ce.ToLength(r.length);if(!ce.IsCallable(e)){throw new TypeError(\"Array#find: predicate must be a function\")}var o=arguments.length>1?arguments[1]:null;for(var i=0,a;i<n;i++){a=r[i];if(o){if(t(e,o,a,i,r)){return a}}else if(e(a,i,r)){return a}}},findIndex:function findIndex(e){var r=ce.ToObject(this);var n=ce.ToLength(r.length);if(!ce.IsCallable(e)){throw new TypeError(\"Array#findIndex: predicate must be a function\")}var o=arguments.length>1?arguments[1]:null;for(var i=0;i<n;i++){if(o){if(t(e,o,r[i],i,r)){return i}}else if(e(r[i],i,r)){return i}}return-1},keys:function keys(){return new q(this,\"key\")},values:function values(){return new q(this,\"value\")},entries:function entries(){return new q(this,\"entry\")}};if(Array.prototype.keys&&!ce.IsCallable([1].keys().next)){delete Array.prototype.keys}if(Array.prototype.entries&&!ce.IsCallable([1].entries().next)){delete Array.prototype.entries}if(Array.prototype.keys&&Array.prototype.entries&&!Array.prototype.values&&Array.prototype[ie]){b(Array.prototype,{values:Array.prototype[ie]});if(re.symbol($.unscopables)){Array.prototype[$.unscopables].values=true}}if(c&&Array.prototype.values&&Array.prototype.values.name!==\"values\"){var tt=Array.prototype.values;ne(Array.prototype,\"values\",function values(){return ce.Call(tt,this,arguments)});h(Array.prototype,ie,Array.prototype.values,true)}b(Array.prototype,et);if(1/[true].indexOf(true,-0)<0){h(Array.prototype,\"indexOf\",function indexOf(e){var t=E(this,arguments);if(t===0&&1/t<0){return 0}return t},true)}Me(Array.prototype,function(){return this.values()});if(Object.getPrototypeOf){Me(Object.getPrototypeOf([].values()))}var rt=function(){return a(function(){return Array.from({length:-1}).length===0})}();var nt=function(){var e=Array.from([0].entries());return e.length===1&&r(e[0])&&e[0][0]===0&&e[0][1]===0}();if(!rt||!nt){ne(Array,\"from\",Ye.from)}var ot=function(){return a(function(){return Array.from([0],void 0)})}();if(!ot){var it=Array.from;ne(Array,\"from\",function from(e){if(arguments.length>1&&typeof arguments[1]!==\"undefined\"){return ce.Call(it,this,arguments)}else{return t(it,this,e)}})}var at=-(Math.pow(2,32)-1);var ut=function(e,r){var n={length:at};n[r?(n.length>>>0)-1:0]=true;return a(function(){t(e,n,function(){throw new RangeError(\"should not reach here\")},[]);return true})};if(!ut(Array.prototype.forEach)){var ft=Array.prototype.forEach;ne(Array.prototype,\"forEach\",function forEach(e){return ce.Call(ft,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.map)){var st=Array.prototype.map;ne(Array.prototype,\"map\",function map(e){return ce.Call(st,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.filter)){var ct=Array.prototype.filter;ne(Array.prototype,\"filter\",function filter(e){return ce.Call(ct,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.some)){var lt=Array.prototype.some;ne(Array.prototype,\"some\",function some(e){return ce.Call(lt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.every)){var pt=Array.prototype.every;ne(Array.prototype,\"every\",function every(e){return ce.Call(pt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.reduce)){var vt=Array.prototype.reduce;ne(Array.prototype,\"reduce\",function reduce(e){return ce.Call(vt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.reduceRight,true)){var yt=Array.prototype.reduceRight;ne(Array.prototype,\"reduceRight\",function reduceRight(e){return ce.Call(yt,this.length>=0?this:[],arguments)},true)}var ht=Number(\"0o10\")!==8;var bt=Number(\"0b10\")!==2;var gt=y(Ue,function(e){return Number(e+0+e)===0});if(ht||bt||gt){var dt=Number;var mt=/^0b[01]+$/i;var Ot=/^0o[0-7]+$/i;var wt=mt.test.bind(mt);var jt=Ot.test.bind(Ot);var St=function(e){var t;if(typeof e.valueOf===\"function\"){t=e.valueOf();if(re.primitive(t)){return t}}if(typeof e.toString===\"function\"){t=e.toString();if(re.primitive(t)){return t}}throw new TypeError(\"No default value\")};var Tt=$e.test.bind($e);var It=Je.test.bind(Je);var Et=function(){var e=function Number(t){var r;if(arguments.length>0){r=re.primitive(t)?t:St(t,\"number\")}else{r=0}if(typeof r===\"string\"){r=ce.Call(Be,r);if(wt(r)){r=parseInt(C(r,2),2)}else if(jt(r)){r=parseInt(C(r,2),8)}else if(Tt(r)||It(r)){r=NaN}}var n=this;var o=a(function(){dt.prototype.valueOf.call(n);return true});if(n instanceof e&&!o){return new dt(r)}return dt(r)};return e}();Ee(dt,Et,{});b(Et,{NaN:dt.NaN,MAX_VALUE:dt.MAX_VALUE,MIN_VALUE:dt.MIN_VALUE,NEGATIVE_INFINITY:dt.NEGATIVE_INFINITY,POSITIVE_INFINITY:dt.POSITIVE_INFINITY});Number=Et;m.redefine(S,\"Number\",Et)}var Pt=Math.pow(2,53)-1;b(Number,{MAX_SAFE_INTEGER:Pt,MIN_SAFE_INTEGER:-Pt,EPSILON:2.220446049250313e-16,parseInt:S.parseInt,parseFloat:S.parseFloat,isFinite:K,isInteger:function isInteger(e){return K(e)&&ce.ToInteger(e)===e},isSafeInteger:function isSafeInteger(e){return Number.isInteger(e)&&k(e)<=Number.MAX_SAFE_INTEGER},isNaN:X});h(Number,\"parseInt\",S.parseInt,Number.parseInt!==S.parseInt);if([,1].find(function(){return true})===1){ne(Array.prototype,\"find\",et.find)}if([,1].findIndex(function(){return true})!==0){ne(Array.prototype,\"findIndex\",et.findIndex)}var Ct=Function.bind.call(Function.bind,Object.prototype.propertyIsEnumerable);var Mt=function ensureEnumerable(e,t){if(s&&Ct(e,t)){Object.defineProperty(e,t,{enumerable:false})}};var xt=function sliceArgs(){var e=Number(this);var t=arguments.length;var r=t-e;var n=new Array(r<0?0:r);for(var o=e;o<t;++o){n[o-e]=arguments[o]}return n};var Nt=function assignTo(e){return function assignToSource(t,r){t[r]=e[r];return t}};var At=function(e,t){var r=n(Object(t));var o;if(ce.IsCallable(Object.getOwnPropertySymbols)){o=v(Object.getOwnPropertySymbols(Object(t)),Ct(t))}return p(P(r,o||[]),Nt(t),e)};var Rt={assign:function(e,t){var r=ce.ToObject(e,\"Cannot convert undefined or null to object\");return p(ce.Call(xt,1,arguments),At,r)},is:function is(e,t){return ce.SameValue(e,t)}};var _t=Object.assign&&Object.preventExtensions&&function(){var e=Object.preventExtensions({1:2});try{Object.assign(e,\"xy\")}catch(t){return e[1]===\"y\"}}();if(_t){ne(Object,\"assign\",Rt.assign)}b(Object,Rt);if(s){var kt={setPrototypeOf:function(e,r){var n;var o=function(e,t){if(!ce.TypeIsObject(e)){throw new TypeError(\"cannot set prototype on a non-object\")}if(!(t===null||ce.TypeIsObject(t))){throw new TypeError(\"can only set prototype to an object or null\"+t)}};var i=function(e,r){o(e,r);t(n,e,r);return e};try{n=e.getOwnPropertyDescriptor(e.prototype,r).set;t(n,{},null)}catch(a){if(e.prototype!=={}[r]){return}n=function(e){this[r]=e};i.polyfill=i(i({},null),e.prototype)instanceof e}return i}(Object,\"__proto__\")};b(Object,kt)}if(Object.setPrototypeOf&&Object.getPrototypeOf&&Object.getPrototypeOf(Object.setPrototypeOf({},null))!==null&&Object.getPrototypeOf(Object.create(null))===null){(function(){var e=Object.create(null);var t=Object.getPrototypeOf;var r=Object.setPrototypeOf;Object.getPrototypeOf=function(r){var n=t(r);return n===e?null:n};Object.setPrototypeOf=function(t,n){var o=n===null?e:n;return r(t,o)};Object.setPrototypeOf.polyfill=false})()}var Lt=!i(function(){return Object.keys(\"foo\")});if(!Lt){var Ft=Object.keys;ne(Object,\"keys\",function keys(e){return Ft(ce.ToObject(e))});n=Object.keys}var Dt=i(function(){return Object.keys(/a/g)});if(Dt){var zt=Object.keys;ne(Object,\"keys\",function keys(e){if(re.regex(e)){var t=[];for(var r in e){if(z(e,r)){M(t,r)}}return t}return zt(e)});n=Object.keys}if(Object.getOwnPropertyNames){var qt=!i(function(){return Object.getOwnPropertyNames(\"foo\")});if(!qt){var Wt=typeof window===\"object\"?Object.getOwnPropertyNames(window):[];var Gt=Object.getOwnPropertyNames;ne(Object,\"getOwnPropertyNames\",function getOwnPropertyNames(e){var t=ce.ToObject(e);if(g(t)===\"[object Window]\"){try{return Gt(t)}catch(r){return P([],Wt)}}return Gt(t)})}}if(Object.getOwnPropertyDescriptor){var Ht=!i(function(){return Object.getOwnPropertyDescriptor(\"foo\",\"bar\")});if(!Ht){var Vt=Object.getOwnPropertyDescriptor;ne(Object,\"getOwnPropertyDescriptor\",function getOwnPropertyDescriptor(e,t){return Vt(ce.ToObject(e),t)})}}if(Object.seal){var Bt=!i(function(){return Object.seal(\"foo\")});if(!Bt){var Ut=Object.seal;ne(Object,\"seal\",function seal(e){if(!ce.TypeIsObject(e)){return e}return Ut(e)})}}if(Object.isSealed){var $t=!i(function(){return Object.isSealed(\"foo\")});if(!$t){var Jt=Object.isSealed;ne(Object,\"isSealed\",function isSealed(e){if(!ce.TypeIsObject(e)){return true}return Jt(e)})}}if(Object.freeze){var Xt=!i(function(){return Object.freeze(\"foo\")});if(!Xt){var Kt=Object.freeze;ne(Object,\"freeze\",function freeze(e){if(!ce.TypeIsObject(e)){return e}return Kt(e)})}}if(Object.isFrozen){var Zt=!i(function(){return Object.isFrozen(\"foo\")});if(!Zt){var Yt=Object.isFrozen;ne(Object,\"isFrozen\",function isFrozen(e){if(!ce.TypeIsObject(e)){return true}return Yt(e)})}}if(Object.preventExtensions){var Qt=!i(function(){return Object.preventExtensions(\"foo\")});if(!Qt){var er=Object.preventExtensions;ne(Object,\"preventExtensions\",function preventExtensions(e){if(!ce.TypeIsObject(e)){return e}return er(e)})}}if(Object.isExtensible){var tr=!i(function(){return Object.isExtensible(\"foo\")});if(!tr){var rr=Object.isExtensible;ne(Object,\"isExtensible\",function isExtensible(e){if(!ce.TypeIsObject(e)){return false}return rr(e)})}}if(Object.getPrototypeOf){var nr=!i(function(){return Object.getPrototypeOf(\"foo\")});if(!nr){var or=Object.getPrototypeOf;ne(Object,\"getPrototypeOf\",function getPrototypeOf(e){return or(ce.ToObject(e))})}}var ir=s&&function(){var e=Object.getOwnPropertyDescriptor(RegExp.prototype,\"flags\");return e&&ce.IsCallable(e.get)}();if(s&&!ir){var ar=function flags(){if(!ce.TypeIsObject(this)){throw new TypeError(\"Method called on incompatible type: must be an object.\")}var e=\"\";if(this.global){e+=\"g\"}if(this.ignoreCase){e+=\"i\"}if(this.multiline){e+=\"m\"}if(this.unicode){e+=\"u\"}if(this.sticky){e+=\"y\"}return e};m.getter(RegExp.prototype,\"flags\",ar)}var ur=s&&a(function(){return String(new RegExp(/a/g,\"i\"))===\"/a/i\"});var fr=oe&&s&&function(){var e=/./;e[$.match]=false;return RegExp(e)===e}();var sr=a(function(){return RegExp.prototype.toString.call({source:\"abc\"})===\"/abc/\"});var cr=sr&&a(function(){return RegExp.prototype.toString.call({source:\"a\",flags:\"b\"})===\"/a/b\"});if(!sr||!cr){var lr=RegExp.prototype.toString;h(RegExp.prototype,\"toString\",function toString(){var e=ce.RequireObjectCoercible(this);if(re.regex(e)){return t(lr,e)}var r=ue(e.source);var n=ue(e.flags);return\"/\"+r+\"/\"+n},true);m.preserveToString(RegExp.prototype.toString,lr)}if(s&&(!ur||fr)){var pr=Object.getOwnPropertyDescriptor(RegExp.prototype,\"flags\").get;var vr=Object.getOwnPropertyDescriptor(RegExp.prototype,\"source\")||{};var yr=function(){return this.source};var hr=ce.IsCallable(vr.get)?vr.get:yr;var br=RegExp;var gr=function(){return function RegExp(e,t){var r=ce.IsRegExp(e);var n=this instanceof RegExp;if(!n&&r&&typeof t===\"undefined\"&&e.constructor===RegExp){return e}var o=e;var i=t;if(re.regex(e)){o=ce.Call(hr,e);i=typeof t===\"undefined\"?ce.Call(pr,e):t;return new RegExp(o,i)}else if(r){o=e.source;i=typeof t===\"undefined\"?e.flags:t}return new br(e,t)}}();Ee(br,gr,{$input:true});RegExp=gr;m.redefine(S,\"RegExp\",gr)}if(s){var dr={input:\"$_\",lastMatch:\"$&\",lastParen:\"$+\",leftContext:\"$`\",rightContext:\"$'\"};l(n(dr),function(e){if(e in RegExp&&!(dr[e]in RegExp)){m.getter(RegExp,dr[e],function get(){return RegExp[e]})}})}Ce(RegExp);var mr=1/Number.EPSILON;var Or=function roundTiesToEven(e){return e+mr-mr};var wr=Math.pow(2,-23);var jr=Math.pow(2,127)*(2-wr);var Sr=Math.pow(2,-126);var Tr=Math.E;var Ir=Math.LOG2E;var Er=Math.LOG10E;var Pr=Number.prototype.clz;delete Number.prototype.clz;var Cr={acosh:function acosh(e){var t=Number(e);if(X(t)||e<1){return NaN}if(t===1){return 0}if(t===Infinity){return t}var r=1/(t*t);if(t<2){return Y(t-1+D(1-r)*t)}var n=t/2;return Y(n+D(1-r)*n-1)+1/Ir},asinh:function asinh(e){var t=Number(e);if(t===0||!T(t)){return t}var r=k(t);var n=r*r;var o=Z(t);if(r<1){return o*Y(r+n/(D(n+1)+1))}return o*(Y(r/2+D(1+1/n)*r/2-1)+1/Ir)},atanh:function atanh(e){var t=Number(e);if(t===0){return t}if(t===-1){return-Infinity}if(t===1){return Infinity}if(X(t)||t<-1||t>1){return NaN}var r=k(t);return Z(t)*Y(2*r/(1-r))/2},cbrt:function cbrt(e){var t=Number(e);if(t===0){return t}var r=t<0;var n;if(r){t=-t}if(t===Infinity){n=Infinity}else{n=L(F(t)/3);n=(t/(n*n)+2*n)/3}return r?-n:n},clz32:function clz32(e){var t=Number(e);var r=ce.ToUint32(t);if(r===0){return 32}return Pr?ce.Call(Pr,r):31-_(F(r+.5)*Ir)},cosh:function cosh(e){var t=Number(e);if(t===0){return 1}if(X(t)){return NaN}if(!T(t)){return Infinity}var r=L(k(t)-1);return(r+1/(r*Tr*Tr))*(Tr/2)},expm1:function expm1(e){var t=Number(e);if(t===-Infinity){return-1}if(!T(t)||t===0){return t}if(k(t)>.5){return L(t)-1}var r=t;var n=0;var o=1;while(n+r!==n){n+=r;o+=1;r*=t/o}return n},hypot:function hypot(e,t){var r=0;var n=0;for(var o=0;o<arguments.length;++o){var i=k(Number(arguments[o]));if(n<i){r*=n/i*(n/i);r+=1;n=i}else{r+=i>0?i/n*(i/n):i}}return n===Infinity?Infinity:n*D(r)},log2:function log2(e){return F(e)*Ir},log10:function log10(e){return F(e)*Er},log1p:Y,sign:Z,sinh:function sinh(e){var t=Number(e);if(!T(t)||t===0){return t}var r=k(t);if(r<1){var n=Math.expm1(r);return Z(t)*n*(1+1/(n+1))/2}var o=L(r-1);return Z(t)*(o-1/(o*Tr*Tr))*(Tr/2)},tanh:function tanh(e){var t=Number(e);if(X(t)||t===0){return t}if(t>=20){return 1}if(t<=-20){return-1}return(Math.expm1(t)-Math.expm1(-t))/(L(t)+L(-t))},trunc:function trunc(e){var t=Number(e);return t<0?-_(-t):_(t)},imul:function imul(e,t){var r=ce.ToUint32(e);var n=ce.ToUint32(t);var o=r>>>16&65535;var i=r&65535;var a=n>>>16&65535;var u=n&65535;return i*u+(o*u+i*a<<16>>>0)|0},fround:function fround(e){var t=Number(e);if(t===0||t===Infinity||t===-Infinity||X(t)){return t}var r=Z(t);var n=k(t);if(n<Sr){return r*Or(n/Sr/wr)*Sr*wr}var o=(1+wr/Number.EPSILON)*n;var i=o-(o-n);if(i>jr||X(i)){return r*Infinity}return r*i}};var Mr=function withinULPDistance(e,t,r){return k(1-e/t)/Number.EPSILON<(r||8)};b(Math,Cr);h(Math,\"sinh\",Cr.sinh,Math.sinh(710)===Infinity);h(Math,\"cosh\",Cr.cosh,Math.cosh(710)===Infinity);h(Math,\"log1p\",Cr.log1p,Math.log1p(-1e-17)!==-1e-17);h(Math,\"asinh\",Cr.asinh,Math.asinh(-1e7)!==-Math.asinh(1e7));h(Math,\"asinh\",Cr.asinh,Math.asinh(1e300)===Infinity);h(Math,\"atanh\",Cr.atanh,Math.atanh(1e-300)===0);h(Math,\"tanh\",Cr.tanh,Math.tanh(-2e-17)!==-2e-17);\nh(Math,\"acosh\",Cr.acosh,Math.acosh(Number.MAX_VALUE)===Infinity);h(Math,\"acosh\",Cr.acosh,!Mr(Math.acosh(1+Number.EPSILON),Math.sqrt(2*Number.EPSILON)));h(Math,\"cbrt\",Cr.cbrt,!Mr(Math.cbrt(1e-300),1e-100));h(Math,\"sinh\",Cr.sinh,Math.sinh(-2e-17)!==-2e-17);var xr=Math.expm1(10);h(Math,\"expm1\",Cr.expm1,xr>22025.465794806718||xr<22025.465794806718);var Nr=Math.round;var Ar=Math.round(.5-Number.EPSILON/4)===0&&Math.round(-.5+Number.EPSILON/3.99)===1;var Rr=mr+1;var _r=2*mr-1;var kr=[Rr,_r].every(function(e){return Math.round(e)===e});h(Math,\"round\",function round(e){var t=_(e);var r=t===-1?-0:t+1;return e-t<.5?t:r},!Ar||!kr);m.preserveToString(Math.round,Nr);var Lr=Math.imul;if(Math.imul(4294967295,5)!==-5){Math.imul=Cr.imul;m.preserveToString(Math.imul,Lr)}if(Math.imul.length!==2){ne(Math,\"imul\",function imul(e,t){return ce.Call(Lr,Math,arguments)})}var Fr=function(){var e=S.setTimeout;if(typeof e!==\"function\"&&typeof e!==\"object\"){return}ce.IsPromise=function(e){if(!ce.TypeIsObject(e)){return false}if(typeof e._promise===\"undefined\"){return false}return true};var r=function(e){if(!ce.IsConstructor(e)){throw new TypeError(\"Bad promise constructor\")}var t=this;var r=function(e,r){if(t.resolve!==void 0||t.reject!==void 0){throw new TypeError(\"Bad Promise implementation!\")}t.resolve=e;t.reject=r};t.resolve=void 0;t.reject=void 0;t.promise=new e(r);if(!(ce.IsCallable(t.resolve)&&ce.IsCallable(t.reject))){throw new TypeError(\"Bad promise constructor\")}};var n;if(typeof window!==\"undefined\"&&ce.IsCallable(window.postMessage)){n=function(){var e=[];var t=\"zero-timeout-message\";var r=function(r){M(e,r);window.postMessage(t,\"*\")};var n=function(r){if(r.source===window&&r.data===t){r.stopPropagation();if(e.length===0){return}var n=N(e);n()}};window.addEventListener(\"message\",n,true);return r}}var o=function(){var e=S.Promise;var t=e&&e.resolve&&e.resolve();return t&&function(e){return t.then(e)}};var i=ce.IsCallable(S.setImmediate)?S.setImmediate:typeof process===\"object\"&&process.nextTick?process.nextTick:o()||(ce.IsCallable(n)?n():function(t){e(t,0)});var a=function(e){return e};var u=function(e){throw e};var f=0;var s=1;var c=2;var l=0;var p=1;var v=2;var y={};var h=function(e,t,r){i(function(){g(e,t,r)})};var g=function(e,t,r){var n,o;if(t===y){return e(r)}try{n=e(r);o=t.resolve}catch(i){n=i;o=t.reject}o(n)};var d=function(e,t){var r=e._promise;var n=r.reactionLength;if(n>0){h(r.fulfillReactionHandler0,r.reactionCapability0,t);r.fulfillReactionHandler0=void 0;r.rejectReactions0=void 0;r.reactionCapability0=void 0;if(n>1){for(var o=1,i=0;o<n;o++,i+=3){h(r[i+l],r[i+v],t);e[i+l]=void 0;e[i+p]=void 0;e[i+v]=void 0}}}r.result=t;r.state=s;r.reactionLength=0};var m=function(e,t){var r=e._promise;var n=r.reactionLength;if(n>0){h(r.rejectReactionHandler0,r.reactionCapability0,t);r.fulfillReactionHandler0=void 0;r.rejectReactions0=void 0;r.reactionCapability0=void 0;if(n>1){for(var o=1,i=0;o<n;o++,i+=3){h(r[i+p],r[i+v],t);e[i+l]=void 0;e[i+p]=void 0;e[i+v]=void 0}}}r.result=t;r.state=c;r.reactionLength=0};var O=function(e){var t=false;var r=function(r){var n;if(t){return}t=true;if(r===e){return m(e,new TypeError(\"Self resolution\"))}if(!ce.TypeIsObject(r)){return d(e,r)}try{n=r.then}catch(o){return m(e,o)}if(!ce.IsCallable(n)){return d(e,r)}i(function(){j(e,r,n)})};var n=function(r){if(t){return}t=true;return m(e,r)};return{resolve:r,reject:n}};var w=function(e,r,n,o){if(e===I){t(e,r,n,o,y)}else{t(e,r,n,o)}};var j=function(e,t,r){var n=O(e);var o=n.resolve;var i=n.reject;try{w(r,t,o,i)}catch(a){i(a)}};var T,I;var E=function(){var e=function Promise(t){if(!(this instanceof e)){throw new TypeError('Constructor Promise requires \"new\"')}if(this&&this._promise){throw new TypeError(\"Bad construction\")}if(!ce.IsCallable(t)){throw new TypeError(\"not a valid resolver\")}var r=Ae(this,e,T,{_promise:{result:void 0,state:f,reactionLength:0,fulfillReactionHandler0:void 0,rejectReactionHandler0:void 0,reactionCapability0:void 0}});var n=O(r);var o=n.reject;try{t(n.resolve,o)}catch(i){o(i)}return r};return e}();T=E.prototype;var P=function(e,t,r,n){var o=false;return function(i){if(o){return}o=true;t[e]=i;if(--n.count===0){var a=r.resolve;a(t)}}};var C=function(e,t,r){var n=e.iterator;var o=[];var i={count:1};var a,u;var f=0;while(true){try{a=ce.IteratorStep(n);if(a===false){e.done=true;break}u=a.value}catch(s){e.done=true;throw s}o[f]=void 0;var c=t.resolve(u);var l=P(f,o,r,i);i.count+=1;w(c.then,c,l,r.reject);f+=1}if(--i.count===0){var p=r.resolve;p(o)}return r.promise};var x=function(e,t,r){var n=e.iterator;var o,i,a;while(true){try{o=ce.IteratorStep(n);if(o===false){e.done=true;break}i=o.value}catch(u){e.done=true;throw u}a=t.resolve(i);w(a.then,a,r.resolve,r.reject)}return r.promise};b(E,{all:function all(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Promise is not object\")}var n=new r(t);var o,i;try{o=ce.GetIterator(e);i={iterator:o,done:false};return C(i,t,n)}catch(a){var u=a;if(i&&!i.done){try{ce.IteratorClose(o,true)}catch(f){u=f}}var s=n.reject;s(u);return n.promise}},race:function race(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Promise is not object\")}var n=new r(t);var o,i;try{o=ce.GetIterator(e);i={iterator:o,done:false};return x(i,t,n)}catch(a){var u=a;if(i&&!i.done){try{ce.IteratorClose(o,true)}catch(f){u=f}}var s=n.reject;s(u);return n.promise}},reject:function reject(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Bad promise constructor\")}var n=new r(t);var o=n.reject;o(e);return n.promise},resolve:function resolve(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Bad promise constructor\")}if(ce.IsPromise(e)){var n=e.constructor;if(n===t){return e}}var o=new r(t);var i=o.resolve;i(e);return o.promise}});b(T,{\"catch\":function(e){return this.then(null,e)},then:function then(e,t){var n=this;if(!ce.IsPromise(n)){throw new TypeError(\"not a promise\")}var o=ce.SpeciesConstructor(n,E);var i;var b=arguments.length>2&&arguments[2]===y;if(b&&o===E){i=y}else{i=new r(o)}var g=ce.IsCallable(e)?e:a;var d=ce.IsCallable(t)?t:u;var m=n._promise;var O;if(m.state===f){if(m.reactionLength===0){m.fulfillReactionHandler0=g;m.rejectReactionHandler0=d;m.reactionCapability0=i}else{var w=3*(m.reactionLength-1);m[w+l]=g;m[w+p]=d;m[w+v]=i}m.reactionLength+=1}else if(m.state===s){O=m.result;h(g,i,O)}else if(m.state===c){O=m.result;h(d,i,O)}else{throw new TypeError(\"unexpected Promise state\")}return i.promise}});y=new r(E);I=T.then;return E}();if(S.Promise){delete S.Promise.accept;delete S.Promise.defer;delete S.Promise.prototype.chain}if(typeof Fr===\"function\"){b(S,{Promise:Fr});var Dr=w(S.Promise,function(e){return e.resolve(42).then(function(){})instanceof e});var zr=!i(function(){return S.Promise.reject(42).then(null,5).then(null,W)});var qr=i(function(){return S.Promise.call(3,W)});var Wr=function(e){var t=e.resolve(5);t.constructor={};var r=e.resolve(t);try{r.then(null,W).then(null,W)}catch(n){return true}return t===r}(S.Promise);var Gr=s&&function(){var e=0;var t=Object.defineProperty({},\"then\",{get:function(){e+=1}});Promise.resolve(t);return e===1}();var Hr=function BadResolverPromise(e){var t=new Promise(e);e(3,function(){});this.then=t.then;this.constructor=BadResolverPromise};Hr.prototype=Promise.prototype;Hr.all=Promise.all;var Vr=a(function(){return!!Hr.all([1,2])});if(!Dr||!zr||!qr||Wr||!Gr||Vr){Promise=Fr;ne(S,\"Promise\",Fr)}if(Promise.all.length!==1){var Br=Promise.all;ne(Promise,\"all\",function all(e){return ce.Call(Br,this,arguments)})}if(Promise.race.length!==1){var Ur=Promise.race;ne(Promise,\"race\",function race(e){return ce.Call(Ur,this,arguments)})}if(Promise.resolve.length!==1){var $r=Promise.resolve;ne(Promise,\"resolve\",function resolve(e){return ce.Call($r,this,arguments)})}if(Promise.reject.length!==1){var Jr=Promise.reject;ne(Promise,\"reject\",function reject(e){return ce.Call(Jr,this,arguments)})}Mt(Promise,\"all\");Mt(Promise,\"race\");Mt(Promise,\"resolve\");Mt(Promise,\"reject\");Ce(Promise)}var Xr=function(e){var t=n(p(e,function(e,t){e[t]=true;return e},{}));return e.join(\":\")===t.join(\":\")};var Kr=Xr([\"z\",\"a\",\"bb\"]);var Zr=Xr([\"z\",1,\"a\",\"3\",2]);if(s){var Yr=function fastkey(e,t){if(!t&&!Kr){return null}if(se(e)){return\"^\"+ce.ToString(e)}else if(typeof e===\"string\"){return\"$\"+e}else if(typeof e===\"number\"){if(!Zr){return\"n\"+e}return e}else if(typeof e===\"boolean\"){return\"b\"+e}return null};var Qr=function emptyObject(){return Object.create?Object.create(null):{}};var en=function addIterableToMap(e,n,o){if(r(o)||re.string(o)){l(o,function(e){if(!ce.TypeIsObject(e)){throw new TypeError(\"Iterator value \"+e+\" is not an entry object\")}n.set(e[0],e[1])})}else if(o instanceof e){t(e.prototype.forEach,o,function(e,t){n.set(t,e)})}else{var i,a;if(!se(o)){a=n.set;if(!ce.IsCallable(a)){throw new TypeError(\"bad map\")}i=ce.GetIterator(o)}if(typeof i!==\"undefined\"){while(true){var u=ce.IteratorStep(i);if(u===false){break}var f=u.value;try{if(!ce.TypeIsObject(f)){throw new TypeError(\"Iterator value \"+f+\" is not an entry object\")}t(a,n,f[0],f[1])}catch(s){ce.IteratorClose(i,true);throw s}}}}};var tn=function addIterableToSet(e,n,o){if(r(o)||re.string(o)){l(o,function(e){n.add(e)})}else if(o instanceof e){t(e.prototype.forEach,o,function(e){n.add(e)})}else{var i,a;if(!se(o)){a=n.add;if(!ce.IsCallable(a)){throw new TypeError(\"bad set\")}i=ce.GetIterator(o)}if(typeof i!==\"undefined\"){while(true){var u=ce.IteratorStep(i);if(u===false){break}var f=u.value;try{t(a,n,f)}catch(s){ce.IteratorClose(i,true);throw s}}}}};var rn={Map:function(){var e={};var r=function MapEntry(e,t){this.key=e;this.value=t;this.next=null;this.prev=null};r.prototype.isRemoved=function isRemoved(){return this.key===e};var n=function isMap(e){return!!e._es6map};var o=function requireMapSlot(e,t){if(!ce.TypeIsObject(e)||!n(e)){throw new TypeError(\"Method Map.prototype.\"+t+\" called on incompatible receiver \"+ce.ToString(e))}};var i=function MapIterator(e,t){o(e,\"[[MapIterator]]\");this.head=e._head;this.i=this.head;this.kind=t};i.prototype={isMapIterator:true,next:function next(){if(!this.isMapIterator){throw new TypeError(\"Not a MapIterator\")}var e=this.i;var t=this.kind;var r=this.head;if(typeof this.i===\"undefined\"){return Ke()}while(e.isRemoved()&&e!==r){e=e.prev}var n;while(e.next!==r){e=e.next;if(!e.isRemoved()){if(t===\"key\"){n=e.key}else if(t===\"value\"){n=e.value}else{n=[e.key,e.value]}this.i=e;return Ke(n)}}this.i=void 0;return Ke()}};Me(i.prototype);var a;var u=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}if(this&&this._es6map){throw new TypeError(\"Bad construction\")}var e=Ae(this,Map,a,{_es6map:true,_head:null,_map:G?new G:null,_size:0,_storage:Qr()});var t=new r(null,null);t.next=t.prev=t;e._head=t;if(arguments.length>0){en(Map,e,arguments[0])}return e};a=u.prototype;m.getter(a,\"size\",function(){if(typeof this._size===\"undefined\"){throw new TypeError(\"size method called on incompatible Map\")}return this._size});b(a,{get:function get(e){o(this,\"get\");var t;var r=Yr(e,true);if(r!==null){t=this._storage[r];if(t){return t.value}else{return}}if(this._map){t=V.call(this._map,e);if(t){return t.value}else{return}}var n=this._head;var i=n;while((i=i.next)!==n){if(ce.SameValueZero(i.key,e)){return i.value}}},has:function has(e){o(this,\"has\");var t=Yr(e,true);if(t!==null){return typeof this._storage[t]!==\"undefined\"}if(this._map){return B.call(this._map,e)}var r=this._head;var n=r;while((n=n.next)!==r){if(ce.SameValueZero(n.key,e)){return true}}return false},set:function set(e,t){o(this,\"set\");var n=this._head;var i=n;var a;var u=Yr(e,true);if(u!==null){if(typeof this._storage[u]!==\"undefined\"){this._storage[u].value=t;return this}else{a=this._storage[u]=new r(e,t);i=n.prev}}else if(this._map){if(B.call(this._map,e)){V.call(this._map,e).value=t}else{a=new r(e,t);U.call(this._map,e,a);i=n.prev}}while((i=i.next)!==n){if(ce.SameValueZero(i.key,e)){i.value=t;return this}}a=a||new r(e,t);if(ce.SameValue(-0,e)){a.key=+0}a.next=this._head;a.prev=this._head.prev;a.prev.next=a;a.next.prev=a;this._size+=1;return this},\"delete\":function(t){o(this,\"delete\");var r=this._head;var n=r;var i=Yr(t,true);if(i!==null){if(typeof this._storage[i]===\"undefined\"){return false}n=this._storage[i].prev;delete this._storage[i]}else if(this._map){if(!B.call(this._map,t)){return false}n=V.call(this._map,t).prev;H.call(this._map,t)}while((n=n.next)!==r){if(ce.SameValueZero(n.key,t)){n.key=e;n.value=e;n.prev.next=n.next;n.next.prev=n.prev;this._size-=1;return true}}return false},clear:function clear(){o(this,\"clear\");this._map=G?new G:null;this._size=0;this._storage=Qr();var t=this._head;var r=t;var n=r.next;while((r=n)!==t){r.key=e;r.value=e;n=r.next;r.next=r.prev=t}t.next=t.prev=t},keys:function keys(){o(this,\"keys\");return new i(this,\"key\")},values:function values(){o(this,\"values\");return new i(this,\"value\")},entries:function entries(){o(this,\"entries\");return new i(this,\"key+value\")},forEach:function forEach(e){o(this,\"forEach\");var r=arguments.length>1?arguments[1]:null;var n=this.entries();for(var i=n.next();!i.done;i=n.next()){if(r){t(e,r,i.value[1],i.value[0],this)}else{e(i.value[1],i.value[0],this)}}}});Me(a,a.entries);return u}(),Set:function(){var e=function isSet(e){return e._es6set&&typeof e._storage!==\"undefined\"};var r=function requireSetSlot(t,r){if(!ce.TypeIsObject(t)||!e(t)){throw new TypeError(\"Set.prototype.\"+r+\" called on incompatible receiver \"+ce.ToString(t))}};var o;var i=function Set(){if(!(this instanceof Set)){throw new TypeError('Constructor Set requires \"new\"')}if(this&&this._es6set){throw new TypeError(\"Bad construction\")}var e=Ae(this,Set,o,{_es6set:true,\"[[SetData]]\":null,_storage:Qr()});if(!e._es6set){throw new TypeError(\"bad set\")}if(arguments.length>0){tn(Set,e,arguments[0])}return e};o=i.prototype;var a=function(e){var t=e;if(t===\"^null\"){return null}else if(t===\"^undefined\"){return void 0}else{var r=t.charAt(0);if(r===\"$\"){return C(t,1)}else if(r===\"n\"){return+C(t,1)}else if(r===\"b\"){return t===\"btrue\"}}return+t};var u=function ensureMap(e){if(!e[\"[[SetData]]\"]){var t=new rn.Map;e[\"[[SetData]]\"]=t;l(n(e._storage),function(e){var r=a(e);t.set(r,r)});e[\"[[SetData]]\"]=t}e._storage=null};m.getter(i.prototype,\"size\",function(){r(this,\"size\");if(this._storage){return n(this._storage).length}u(this);return this[\"[[SetData]]\"].size});b(i.prototype,{has:function has(e){r(this,\"has\");var t;if(this._storage&&(t=Yr(e))!==null){return!!this._storage[t]}u(this);return this[\"[[SetData]]\"].has(e)},add:function add(e){r(this,\"add\");var t;if(this._storage&&(t=Yr(e))!==null){this._storage[t]=true;return this}u(this);this[\"[[SetData]]\"].set(e,e);return this},\"delete\":function(e){r(this,\"delete\");var t;if(this._storage&&(t=Yr(e))!==null){var n=z(this._storage,t);return delete this._storage[t]&&n}u(this);return this[\"[[SetData]]\"][\"delete\"](e)},clear:function clear(){r(this,\"clear\");if(this._storage){this._storage=Qr()}if(this[\"[[SetData]]\"]){this[\"[[SetData]]\"].clear()}},values:function values(){r(this,\"values\");u(this);return new f(this[\"[[SetData]]\"].values())},entries:function entries(){r(this,\"entries\");u(this);return new f(this[\"[[SetData]]\"].entries())},forEach:function forEach(e){r(this,\"forEach\");var n=arguments.length>1?arguments[1]:null;var o=this;u(o);this[\"[[SetData]]\"].forEach(function(r,i){if(n){t(e,n,i,i,o)}else{e(i,i,o)}})}});h(i.prototype,\"keys\",i.prototype.values,true);Me(i.prototype,i.prototype.values);var f=function SetIterator(e){this.it=e};f.prototype={isSetIterator:true,next:function next(){if(!this.isSetIterator){throw new TypeError(\"Not a SetIterator\")}return this.it.next()}};Me(f.prototype);return i}()};var nn=S.Set&&!Set.prototype[\"delete\"]&&Set.prototype.remove&&Set.prototype.items&&Set.prototype.map&&Array.isArray((new Set).keys);if(nn){S.Set=rn.Set}if(S.Map||S.Set){var on=a(function(){return new Map([[1,2]]).get(1)===2});if(!on){S.Map=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}var e=new G;if(arguments.length>0){en(Map,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,S.Map.prototype);return e};S.Map.prototype=O(G.prototype);h(S.Map.prototype,\"constructor\",S.Map,true);m.preserveToString(S.Map,G)}var an=new Map;var un=function(){var e=new Map([[1,0],[2,0],[3,0],[4,0]]);e.set(-0,e);return e.get(0)===e&&e.get(-0)===e&&e.has(0)&&e.has(-0)}();var fn=an.set(1,2)===an;if(!un||!fn){ne(Map.prototype,\"set\",function set(e,r){t(U,this,e===0?0:e,r);return this})}if(!un){b(Map.prototype,{get:function get(e){return t(V,this,e===0?0:e)},has:function has(e){return t(B,this,e===0?0:e)}},true);m.preserveToString(Map.prototype.get,V);m.preserveToString(Map.prototype.has,B)}var sn=new Set;var cn=Set.prototype[\"delete\"]&&Set.prototype.add&&Set.prototype.has&&function(e){e[\"delete\"](0);e.add(-0);return!e.has(0)}(sn);var ln=sn.add(1)===sn;if(!cn||!ln){var pn=Set.prototype.add;Set.prototype.add=function add(e){t(pn,this,e===0?0:e);return this};m.preserveToString(Set.prototype.add,pn)}if(!cn){var vn=Set.prototype.has;Set.prototype.has=function has(e){return t(vn,this,e===0?0:e)};m.preserveToString(Set.prototype.has,vn);var yn=Set.prototype[\"delete\"];Set.prototype[\"delete\"]=function SetDelete(e){return t(yn,this,e===0?0:e)};m.preserveToString(Set.prototype[\"delete\"],yn)}var hn=w(S.Map,function(e){var t=new e([]);t.set(42,42);return t instanceof e});var bn=Object.setPrototypeOf&&!hn;var gn=function(){try{return!(S.Map()instanceof S.Map)}catch(e){return e instanceof TypeError}}();if(S.Map.length!==0||bn||!gn){S.Map=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}var e=new G;if(arguments.length>0){en(Map,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,Map.prototype);return e};S.Map.prototype=G.prototype;h(S.Map.prototype,\"constructor\",S.Map,true);m.preserveToString(S.Map,G)}var dn=w(S.Set,function(e){var t=new e([]);t.add(42,42);return t instanceof e});var mn=Object.setPrototypeOf&&!dn;var On=function(){try{return!(S.Set()instanceof S.Set)}catch(e){return e instanceof TypeError}}();if(S.Set.length!==0||mn||!On){var wn=S.Set;S.Set=function Set(){if(!(this instanceof Set)){throw new TypeError('Constructor Set requires \"new\"')}var e=new wn;if(arguments.length>0){tn(Set,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,Set.prototype);return e};S.Set.prototype=wn.prototype;h(S.Set.prototype,\"constructor\",S.Set,true);m.preserveToString(S.Set,wn)}var jn=new S.Map;var Sn=!a(function(){return jn.keys().next().done});if(typeof S.Map.prototype.clear!==\"function\"||(new S.Set).size!==0||jn.size!==0||typeof S.Map.prototype.keys!==\"function\"||typeof S.Set.prototype.keys!==\"function\"||typeof S.Map.prototype.forEach!==\"function\"||typeof S.Set.prototype.forEach!==\"function\"||u(S.Map)||u(S.Set)||typeof jn.keys().next!==\"function\"||Sn||!hn){b(S,{Map:rn.Map,Set:rn.Set},true)}if(S.Set.prototype.keys!==S.Set.prototype.values){h(S.Set.prototype,\"keys\",S.Set.prototype.values,true)}Me(Object.getPrototypeOf((new S.Map).keys()));Me(Object.getPrototypeOf((new S.Set).keys()));if(c&&S.Set.prototype.has.name!==\"has\"){var Tn=S.Set.prototype.has;ne(S.Set.prototype,\"has\",function has(e){return t(Tn,this,e)})}}b(S,rn);Ce(S.Map);Ce(S.Set)}var In=function throwUnlessTargetIsObject(e){if(!ce.TypeIsObject(e)){throw new TypeError(\"target must be an object\")}};var En={apply:function apply(){return ce.Call(ce.Call,null,arguments)},construct:function construct(e,t){if(!ce.IsConstructor(e)){throw new TypeError(\"First argument must be a constructor.\")}var r=arguments.length>2?arguments[2]:e;if(!ce.IsConstructor(r)){throw new TypeError(\"new.target must be a constructor.\")}return ce.Construct(e,t,r,\"internal\")},deleteProperty:function deleteProperty(e,t){In(e);if(s){var r=Object.getOwnPropertyDescriptor(e,t);if(r&&!r.configurable){return false}}return delete e[t]},has:function has(e,t){In(e);return t in e}};if(Object.getOwnPropertyNames){Object.assign(En,{ownKeys:function ownKeys(e){In(e);var t=Object.getOwnPropertyNames(e);if(ce.IsCallable(Object.getOwnPropertySymbols)){x(t,Object.getOwnPropertySymbols(e))}return t}})}var Pn=function ConvertExceptionToBoolean(e){return!i(e)};if(Object.preventExtensions){Object.assign(En,{isExtensible:function isExtensible(e){In(e);return Object.isExtensible(e)},preventExtensions:function preventExtensions(e){In(e);return Pn(function(){return Object.preventExtensions(e)})}})}if(s){var Cn=function get(e,t,r){var n=Object.getOwnPropertyDescriptor(e,t);if(!n){var o=Object.getPrototypeOf(e);if(o===null){return void 0}return Cn(o,t,r)}if(\"value\"in n){return n.value}if(n.get){return ce.Call(n.get,r)}return void 0};var Mn=function set(e,r,n,o){var i=Object.getOwnPropertyDescriptor(e,r);if(!i){var a=Object.getPrototypeOf(e);if(a!==null){return Mn(a,r,n,o)}i={value:void 0,writable:true,enumerable:true,configurable:true}}if(\"value\"in i){if(!i.writable){return false}if(!ce.TypeIsObject(o)){return false}var u=Object.getOwnPropertyDescriptor(o,r);if(u){return ae.defineProperty(o,r,{value:n})}else{return ae.defineProperty(o,r,{value:n,writable:true,enumerable:true,configurable:true})}}if(i.set){t(i.set,o,n);return true}return false};Object.assign(En,{defineProperty:function defineProperty(e,t,r){In(e);return Pn(function(){return Object.defineProperty(e,t,r)})},getOwnPropertyDescriptor:function getOwnPropertyDescriptor(e,t){In(e);return Object.getOwnPropertyDescriptor(e,t)},get:function get(e,t){In(e);var r=arguments.length>2?arguments[2]:e;return Cn(e,t,r)},set:function set(e,t,r){In(e);var n=arguments.length>3?arguments[3]:e;return Mn(e,t,r,n)}})}if(Object.getPrototypeOf){var xn=Object.getPrototypeOf;En.getPrototypeOf=function getPrototypeOf(e){In(e);return xn(e)}}if(Object.setPrototypeOf&&En.getPrototypeOf){var Nn=function(e,t){var r=t;while(r){if(e===r){return true}r=En.getPrototypeOf(r)}return false};Object.assign(En,{setPrototypeOf:function setPrototypeOf(e,t){In(e);if(t!==null&&!ce.TypeIsObject(t)){throw new TypeError(\"proto must be an object or null\")}if(t===ae.getPrototypeOf(e)){return true}if(ae.isExtensible&&!ae.isExtensible(e)){return false}if(Nn(e,t)){return false}Object.setPrototypeOf(e,t);return true}})}var An=function(e,t){if(!ce.IsCallable(S.Reflect[e])){h(S.Reflect,e,t)}else{var r=a(function(){S.Reflect[e](1);S.Reflect[e](NaN);S.Reflect[e](true);return true});if(r){ne(S.Reflect,e,t)}}};Object.keys(En).forEach(function(e){An(e,En[e])});var Rn=S.Reflect.getPrototypeOf;if(c&&Rn&&Rn.name!==\"getPrototypeOf\"){ne(S.Reflect,\"getPrototypeOf\",function getPrototypeOf(e){return t(Rn,S.Reflect,e)})}if(S.Reflect.setPrototypeOf){if(a(function(){S.Reflect.setPrototypeOf(1,{});return true})){ne(S.Reflect,\"setPrototypeOf\",En.setPrototypeOf)}}if(S.Reflect.defineProperty){if(!a(function(){var e=!S.Reflect.defineProperty(1,\"test\",{value:1});var t=typeof Object.preventExtensions!==\"function\"||!S.Reflect.defineProperty(Object.preventExtensions({}),\"test\",{});return e&&t})){ne(S.Reflect,\"defineProperty\",En.defineProperty)}}if(S.Reflect.construct){if(!a(function(){var e=function F(){};return S.Reflect.construct(function(){},[],e)instanceof e})){ne(S.Reflect,\"construct\",En.construct)}}if(String(new Date(NaN))!==\"Invalid Date\"){var _n=Date.prototype.toString;var kn=function toString(){var e=+this;if(e!==e){return\"Invalid Date\"}return ce.Call(_n,this)};ne(Date.prototype,\"toString\",kn)}var Ln={anchor:function anchor(e){return ce.CreateHTML(this,\"a\",\"name\",e)},big:function big(){return ce.CreateHTML(this,\"big\",\"\",\"\")},blink:function blink(){return ce.CreateHTML(this,\"blink\",\"\",\"\")},bold:function bold(){return ce.CreateHTML(this,\"b\",\"\",\"\")},fixed:function fixed(){return ce.CreateHTML(this,\"tt\",\"\",\"\")},fontcolor:function fontcolor(e){return ce.CreateHTML(this,\"font\",\"color\",e)},fontsize:function fontsize(e){return ce.CreateHTML(this,\"font\",\"size\",e)},italics:function italics(){return ce.CreateHTML(this,\"i\",\"\",\"\")},link:function link(e){return ce.CreateHTML(this,\"a\",\"href\",e)},small:function small(){return ce.CreateHTML(this,\"small\",\"\",\"\")},strike:function strike(){return ce.CreateHTML(this,\"strike\",\"\",\"\")},sub:function sub(){return ce.CreateHTML(this,\"sub\",\"\",\"\")},sup:function sub(){return ce.CreateHTML(this,\"sup\",\"\",\"\")}};l(Object.keys(Ln),function(e){var r=String.prototype[e];var n=false;if(ce.IsCallable(r)){var o=t(r,\"\",' \" ');var i=P([],o.match(/\"/g)).length;n=o!==o.toLowerCase()||i>2}else{n=true}if(n){ne(String.prototype,e,Ln[e])}});var Fn=function(){if(!oe){return false}var e=typeof JSON===\"object\"&&typeof JSON.stringify===\"function\"?JSON.stringify:null;if(!e){return false}if(typeof e($())!==\"undefined\"){return true}if(e([$()])!==\"[null]\"){return true}var t={a:$()};t[$()]=true;if(e(t)!==\"{}\"){return true}return false}();var Dn=a(function(){if(!oe){return true}return JSON.stringify(Object($()))===\"{}\"&&JSON.stringify([Object($())])===\"[{}]\"});if(Fn||!Dn){var zn=JSON.stringify;ne(JSON,\"stringify\",function stringify(e){if(typeof e===\"symbol\"){return}var n;if(arguments.length>1){n=arguments[1]}var o=[e];if(!r(n)){var i=ce.IsCallable(n)?n:null;var a=function(e,r){var n=i?t(i,this,e,r):r;if(typeof n!==\"symbol\"){if(re.symbol(n)){return Nt({})(n)}else{return n}}};o.push(a)}else{o.push(n)}if(arguments.length>2){o.push(arguments[2])}return zn.apply(this,o)})}return S});\n//# sourceMappingURL=es6-shim.map\n/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */\n!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return t(e)}:t(e)}(\"undefined\"!=typeof window?window:this,function(C,e){\"use strict\";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return\"function\"==typeof e&&\"number\"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement(\"script\");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?n[o.call(e)]||\"object\":typeof e}var f=\"3.4.1\",k=function(e,t){return new k.fn.init(e,t)},p=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;function d(e){var t=!!e&&\"length\"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&0<t&&t-1 in e)}k.fn=k.prototype={jquery:f,constructor:k,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=k.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return k.each(this,e)},map:function(n){return this.pushStack(k.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},k.extend=k.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for(\"boolean\"==typeof a&&(l=a,a=arguments[s]||{},s++),\"object\"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],\"__proto__\"!==t&&a!==r&&(l&&r&&(k.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||k.isPlainObject(n)?n:{},i=!1,a[t]=k.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},k.extend({expando:\"jQuery\"+(f+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||\"[object Object]\"!==o.call(e))&&(!(t=r(e))||\"function\"==typeof(n=v.call(t,\"constructor\")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t){b(e,{nonce:t&&t.nonce})},each:function(e,t){var n,r=0;if(d(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?\"\":(e+\"\").replace(p,\"\")},makeArray:function(e,t){var n=t||[];return null!=e&&(d(Object(e))?k.merge(n,\"string\"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(d(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g.apply([],a)},guid:1,support:y}),\"function\"==typeof Symbol&&(k.fn[Symbol.iterator]=t[Symbol.iterator]),k.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){n[\"[object \"+t+\"]\"]=t.toLowerCase()});var h=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,k=\"sizzle\"+1*new Date,m=n.document,S=0,r=0,p=ue(),x=ue(),N=ue(),A=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",M=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",I=\"(?:\\\\\\\\.|[\\\\w-]|[^\\0-\\\\xa0])+\",W=\"\\\\[\"+M+\"*(\"+I+\")(?:\"+M+\"*([*^$|!~]?=)\"+M+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+I+\"))|)\"+M+\"*\\\\]\",$=\":(\"+I+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+W+\")*)|.*)\\\\)|)\",F=new RegExp(M+\"+\",\"g\"),B=new RegExp(\"^\"+M+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+M+\"+$\",\"g\"),_=new RegExp(\"^\"+M+\"*,\"+M+\"*\"),z=new RegExp(\"^\"+M+\"*([>+~]|\"+M+\")\"+M+\"*\"),U=new RegExp(M+\"|>\"),X=new RegExp($),V=new RegExp(\"^\"+I+\"$\"),G={ID:new RegExp(\"^#(\"+I+\")\"),CLASS:new RegExp(\"^\\\\.(\"+I+\")\"),TAG:new RegExp(\"^(\"+I+\"|[*])\"),ATTR:new RegExp(\"^\"+W),PSEUDO:new RegExp(\"^\"+$),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+M+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+M+\"*(?:([+-]|)\"+M+\"*(\\\\d+)|))\"+M+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+R+\")$\",\"i\"),needsContext:new RegExp(\"^\"+M+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+M+\"*((?:-\\\\d)?\\\\d*)\"+M+\"*\\\\)|)(?=[^-]|$)\",\"i\")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\\d$/i,K=/^[^{]+\\{\\s*\\[native \\w/,Z=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,ee=/[+~]/,te=new RegExp(\"\\\\\\\\([\\\\da-f]{1,6}\"+M+\"?|(\"+M+\")|.)\",\"ig\"),ne=function(e,t,n){var r=\"0x\"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,ie=function(e,t){return t?\"\\0\"===e?\"\\ufffd\":e.slice(0,-1)+\"\\\\\"+e.charCodeAt(e.length-1).toString(16)+\" \":\"\\\\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&\"fieldset\"===e.nodeName.toLowerCase()},{dir:\"parentNode\",next:\"legend\"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],\"string\"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+\" \"]&&(!v||!v.test(t))&&(1!==p||\"object\"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute(\"id\"))?s=s.replace(re,ie):e.setAttribute(\"id\",s=k),o=(l=h(t)).length;while(o--)l[o]=\"#\"+s+\" \"+xe(l[o]);c=l.join(\",\"),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute(\"id\")}}}return g(t.replace(B,\"$1\"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+\" \")>b.cacheLength&&delete e[r.shift()],e[t+\" \"]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement(\"fieldset\");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split(\"|\"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return\"input\"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return(\"input\"===t||\"button\"===t)&&e.type===n}}function ge(t){return function(e){return\"form\"in e?e.parentNode&&!1===e.disabled?\"label\"in e?\"label\"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:\"label\"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&\"undefined\"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||\"HTML\")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener(\"unload\",oe,!1):n.attachEvent&&n.attachEvent(\"onunload\",oe)),d.attributes=ce(function(e){return e.className=\"i\",!e.getAttribute(\"className\")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment(\"\")),!e.getElementsByTagName(\"*\").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute(\"id\")===t}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t=\"undefined\"!=typeof e.getAttributeNode&&e.getAttributeNode(\"id\");return t&&t.value===n}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return\"undefined\"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if(\"*\"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if(\"undefined\"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML=\"<a id='\"+k+\"'></a><select id='\"+k+\"-\\r\\\\' msallowcapture=''><option selected=''></option></select>\",e.querySelectorAll(\"[msallowcapture^='']\").length&&v.push(\"[*^$]=\"+M+\"*(?:''|\\\"\\\")\"),e.querySelectorAll(\"[selected]\").length||v.push(\"\\\\[\"+M+\"*(?:value|\"+R+\")\"),e.querySelectorAll(\"[id~=\"+k+\"-]\").length||v.push(\"~=\"),e.querySelectorAll(\":checked\").length||v.push(\":checked\"),e.querySelectorAll(\"a#\"+k+\"+*\").length||v.push(\".#.+[+~]\")}),ce(function(e){e.innerHTML=\"<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>\";var t=C.createElement(\"input\");t.setAttribute(\"type\",\"hidden\"),e.appendChild(t).setAttribute(\"name\",\"D\"),e.querySelectorAll(\"[name=d]\").length&&v.push(\"name\"+M+\"*[*^$|!~]?=\"),2!==e.querySelectorAll(\":enabled\").length&&v.push(\":enabled\",\":disabled\"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(\":disabled\").length&&v.push(\":enabled\",\":disabled\"),e.querySelectorAll(\"*,:x\"),v.push(\",.*:\")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,\"*\"),c.call(e,\"[s!='']:x\"),s.push(\"!=\",$)}),v=v.length&&new RegExp(v.join(\"|\")),s=s.length&&new RegExp(s.join(\"|\")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+\" \"]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!==C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!==C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+\"\").replace(re,ie)},se.error=function(e){throw new Error(\"Syntax error, unrecognized expression: \"+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n=\"\",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if(\"string\"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||\"\").replace(te,ne),\"~=\"===e[2]&&(e[3]=\" \"+e[3]+\" \"),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),\"nth\"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*(\"even\"===e[3]||\"odd\"===e[3])),e[5]=+(e[7]+e[8]||\"odd\"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||\"\":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(\")\",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return\"*\"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+\" \"];return t||(t=new RegExp(\"(^|\"+M+\")\"+e+\"(\"+M+\"|$)\"))&&p(e,function(e){return t.test(\"string\"==typeof e.className&&e.className||\"undefined\"!=typeof e.getAttribute&&e.getAttribute(\"class\")||\"\")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?\"!=\"===r:!r||(t+=\"\",\"=\"===r?t===i:\"!=\"===r?t!==i:\"^=\"===r?i&&0===t.indexOf(i):\"*=\"===r?i&&-1<t.indexOf(i):\"$=\"===r?i&&t.slice(-i.length)===i:\"~=\"===r?-1<(\" \"+t.replace(F,\" \")+\" \").indexOf(i):\"|=\"===r&&(t===i||t.slice(0,i.length+1)===i+\"-\"))}},CHILD:function(h,e,t,g,v){var y=\"nth\"!==h.slice(0,3),m=\"last\"!==h.slice(-4),x=\"of-type\"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?\"nextSibling\":\"previousSibling\",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l=\"only\"===h&&!u&&\"nextSibling\"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[S,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[S,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error(\"unsupported pseudo: \"+e);return a[k]?a(o):1<a.length?(t=[e,e,\"\",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace(B,\"$1\"));return s[k]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||\"\")||se.error(\"unsupported lang: \"+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute(\"xml:lang\")||e.getAttribute(\"lang\"))return(t=t.toLowerCase())===n||0===t.indexOf(n+\"-\")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&!!e.checked||\"option\"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&\"button\"===e.type||\"button\"===t},text:function(e){var t;return\"input\"===e.nodeName.toLowerCase()&&\"text\"===e.type&&(null==(t=e.getAttribute(\"type\"))||\"text\"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r=\"\";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&\"parentNode\"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[S,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[k]||(e[k]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===S&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[k]&&(v=Ce(v)),y&&!y[k]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||\"*\",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[\" \"],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[k]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:\" \"===e[s-2].type?\"*\":\"\"})).replace(B,\"$1\"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+\" \"];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace(B,\" \")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=N[e+\" \"];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[k]?i.push(a):o.push(a);(a=N(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l=\"0\",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG(\"*\",i),h=S+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t===C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument===C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(S=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(S=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l=\"function\"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&\"ID\"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=k.split(\"\").sort(D).join(\"\")===k,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement(\"fieldset\"))}),ce(function(e){return e.innerHTML=\"<a href='#'></a>\",\"#\"===e.firstChild.getAttribute(\"href\")})||fe(\"type|href|height|width\",function(e,t,n){if(!n)return e.getAttribute(t,\"type\"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML=\"<input/>\",e.firstChild.setAttribute(\"value\",\"\"),\"\"===e.firstChild.getAttribute(\"value\")})||fe(\"value\",function(e,t,n){if(!n&&\"input\"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute(\"disabled\")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);k.find=h,k.expr=h.selectors,k.expr[\":\"]=k.expr.pseudos,k.uniqueSort=k.unique=h.uniqueSort,k.text=h.getText,k.isXMLDoc=h.isXML,k.contains=h.contains,k.escapeSelector=h.escape;var T=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&k(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},N=k.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var D=/^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):\"string\"!=typeof n?k.grep(e,function(e){return-1<i.call(n,e)!==r}):k.filter(n,e,r)}k.filter=function(e,t,n){var r=t[0];return n&&(e=\":not(\"+e+\")\"),1===t.length&&1===r.nodeType?k.find.matchesSelector(r,e)?[r]:[]:k.find.matches(e,k.grep(t,function(e){return 1===e.nodeType}))},k.fn.extend({find:function(e){var t,n,r=this.length,i=this;if(\"string\"!=typeof e)return this.pushStack(k(e).filter(function(){for(t=0;t<r;t++)if(k.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)k.find(e,i[t],n);return 1<r?k.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,\"string\"==typeof e&&N.test(e)?k(e):e||[],!1).length}});var q,L=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,\"string\"==typeof e){if(!(r=\"<\"===e[0]&&\">\"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(k.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a=\"string\"!=typeof e&&k(e);if(!N.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&k.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?k.uniqueSort(o):o)},index:function(e){return e?\"string\"==typeof e?i.call(k(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(k.uniqueSort(k.merge(this.get(),k(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),k.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return T(e,\"parentNode\")},parentsUntil:function(e,t,n){return T(e,\"parentNode\",n)},next:function(e){return P(e,\"nextSibling\")},prev:function(e){return P(e,\"previousSibling\")},nextAll:function(e){return T(e,\"nextSibling\")},prevAll:function(e){return T(e,\"previousSibling\")},nextUntil:function(e,t,n){return T(e,\"nextSibling\",n)},prevUntil:function(e,t,n){return T(e,\"previousSibling\",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return\"undefined\"!=typeof e.contentDocument?e.contentDocument:(A(e,\"template\")&&(e=e.content||e),k.merge([],e.childNodes))}},function(r,i){k.fn[r]=function(e,t){var n=k.map(this,i,e);return\"Until\"!==r.slice(-5)&&(t=e),t&&\"string\"==typeof t&&(n=k.filter(t,n)),1<this.length&&(O[r]||k.uniqueSort(n),H.test(r)&&n.reverse()),this.pushStack(n)}});var R=/[^\\x20\\t\\r\\n\\f]+/g;function M(e){return e}function I(e){throw e}function W(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}k.Callbacks=function(r){var e,n;r=\"string\"==typeof r?(e=r,n={},k.each(e.match(R)||[],function(e,t){n[t]=!0}),n):k.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:\"\")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){k.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&\"string\"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return k.each(arguments,function(e,t){var n;while(-1<(n=k.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<k.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t=\"\",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=\"\"),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},k.extend({Deferred:function(e){var o=[[\"notify\",\"progress\",k.Callbacks(\"memory\"),k.Callbacks(\"memory\"),2],[\"resolve\",\"done\",k.Callbacks(\"once memory\"),k.Callbacks(\"once memory\"),0,\"resolved\"],[\"reject\",\"fail\",k.Callbacks(\"once memory\"),k.Callbacks(\"once memory\"),1,\"rejected\"]],i=\"pending\",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},\"catch\":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return k.Deferred(function(r){k.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+\"With\"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError(\"Thenable self-resolution\");t=e&&(\"object\"==typeof e||\"function\"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,M,s),l(u,o,I,s)):(u++,t.call(e,l(u,o,M,s),l(u,o,I,s),l(u,o,M,o.notifyWith))):(a!==M&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){k.Deferred.exceptionHook&&k.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==I&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(k.Deferred.getStackHook&&(t.stackTrace=k.Deferred.getStackHook()),C.setTimeout(t))}}return k.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:M,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:M)),o[2][3].add(l(0,e,m(n)?n:I))}).promise()},promise:function(e){return null!=e?k.extend(e,a):a}},s={};return k.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+\"With\"](this===s?void 0:this,arguments),this},s[t[0]+\"With\"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=k.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(W(e,o.done(a(t)).resolve,o.reject,!n),\"pending\"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)W(i[t],a(t),o.reject);return o.promise()}});var $=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;k.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&$.test(e.name)&&C.console.warn(\"jQuery.Deferred exception: \"+e.message,e.stack,t)},k.readyException=function(e){C.setTimeout(function(){throw e})};var F=k.Deferred();function B(){E.removeEventListener(\"DOMContentLoaded\",B),C.removeEventListener(\"load\",B),k.ready()}k.fn.ready=function(e){return F.then(e)[\"catch\"](function(e){k.readyException(e)}),this},k.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--k.readyWait:k.isReady)||(k.isReady=!0)!==e&&0<--k.readyWait||F.resolveWith(E,[k])}}),k.ready.then=F.then,\"complete\"===E.readyState||\"loading\"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(k.ready):(E.addEventListener(\"DOMContentLoaded\",B),C.addEventListener(\"load\",B));var _=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if(\"object\"===w(n))for(s in i=!0,n)_(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(k(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},z=/^-ms-/,U=/-([a-z])/g;function X(e,t){return t.toUpperCase()}function V(e){return e.replace(z,\"ms-\").replace(U,X)}var G=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function Y(){this.expando=k.expando+Y.uid++}Y.uid=1,Y.prototype={cache:function(e){var t=e[this.expando];return t||(t={},G(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if(\"string\"==typeof t)i[V(t)]=n;else for(r in t)i[V(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][V(t)]},access:function(e,t,n){return void 0===t||t&&\"string\"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(V):(t=V(t))in r?[t]:t.match(R)||[]).length;while(n--)delete r[t[n]]}(void 0===t||k.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!k.isEmptyObject(t)}};var Q=new Y,J=new Y,K=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,Z=/[A-Z]/g;function ee(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r=\"data-\"+t.replace(Z,\"-$&\").toLowerCase(),\"string\"==typeof(n=e.getAttribute(r))){try{n=\"true\"===(i=n)||\"false\"!==i&&(\"null\"===i?null:i===+i+\"\"?+i:K.test(i)?JSON.parse(i):i)}catch(e){}J.set(e,t,n)}else n=void 0;return n}k.extend({hasData:function(e){return J.hasData(e)||Q.hasData(e)},data:function(e,t,n){return J.access(e,t,n)},removeData:function(e,t){J.remove(e,t)},_data:function(e,t,n){return Q.access(e,t,n)},_removeData:function(e,t){Q.remove(e,t)}}),k.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=J.get(o),1===o.nodeType&&!Q.get(o,\"hasDataAttrs\"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf(\"data-\")&&(r=V(r.slice(5)),ee(o,r,i[r]));Q.set(o,\"hasDataAttrs\",!0)}return i}return\"object\"==typeof n?this.each(function(){J.set(this,n)}):_(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=J.get(o,n))?t:void 0!==(t=ee(o,n))?t:void 0;this.each(function(){J.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){J.remove(this,e)})}}),k.extend({queue:function(e,t,n){var r;if(e)return t=(t||\"fx\")+\"queue\",r=Q.get(e,t),n&&(!r||Array.isArray(n)?r=Q.access(e,t,k.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||\"fx\";var n=k.queue(e,t),r=n.length,i=n.shift(),o=k._queueHooks(e,t);\"inprogress\"===i&&(i=n.shift(),r--),i&&(\"fx\"===t&&n.unshift(\"inprogress\"),delete o.stop,i.call(e,function(){k.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+\"queueHooks\";return Q.get(e,n)||Q.access(e,n,{empty:k.Callbacks(\"once memory\").add(function(){Q.remove(e,[t+\"queue\",n])})})}}),k.fn.extend({queue:function(t,n){var e=2;return\"string\"!=typeof t&&(n=t,t=\"fx\",e--),arguments.length<e?k.queue(this[0],t):void 0===n?this:this.each(function(){var e=k.queue(this,t,n);k._queueHooks(this,t),\"fx\"===t&&\"inprogress\"!==e[0]&&k.dequeue(this,t)})},dequeue:function(e){return this.each(function(){k.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||\"fx\",[])},promise:function(e,t){var n,r=1,i=k.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};\"string\"!=typeof e&&(t=e,e=void 0),e=e||\"fx\";while(a--)(n=Q.get(o[a],e+\"queueHooks\"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var te=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,ne=new RegExp(\"^(?:([+-])=|)(\"+te+\")([a-z%]*)$\",\"i\"),re=[\"Top\",\"Right\",\"Bottom\",\"Left\"],ie=E.documentElement,oe=function(e){return k.contains(e.ownerDocument,e)},ae={composed:!0};ie.getRootNode&&(oe=function(e){return k.contains(e.ownerDocument,e)||e.getRootNode(ae)===e.ownerDocument});var se=function(e,t){return\"none\"===(e=t||e).style.display||\"\"===e.style.display&&oe(e)&&\"none\"===k.css(e,\"display\")},ue=function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];for(o in i=n.apply(e,r||[]),t)e.style[o]=a[o];return i};function le(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return k.css(e,t,\"\")},u=s(),l=n&&n[3]||(k.cssNumber[t]?\"\":\"px\"),c=e.nodeType&&(k.cssNumber[t]||\"px\"!==l&&+u)&&ne.exec(k.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)k.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,k.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ce={};function fe(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?(\"none\"===n&&(l[c]=Q.get(r,\"display\")||null,l[c]||(r.style.display=\"\")),\"\"===r.style.display&&se(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ce[s])||(o=a.body.appendChild(a.createElement(s)),u=k.css(o,\"display\"),o.parentNode.removeChild(o),\"none\"===u&&(u=\"block\"),ce[s]=u)))):\"none\"!==n&&(l[c]=\"none\",Q.set(r,\"display\",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}k.fn.extend({show:function(){return fe(this,!0)},hide:function(){return fe(this)},toggle:function(e){return\"boolean\"==typeof e?e?this.show():this.hide():this.each(function(){se(this)?k(this).show():k(this).hide()})}});var pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i,he=/^$|^module$|\\/(?:java|ecma)script/i,ge={option:[1,\"<select multiple='multiple'>\",\"</select>\"],thead:[1,\"<table>\",\"</table>\"],col:[2,\"<table><colgroup>\",\"</colgroup></table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:[0,\"\",\"\"]};function ve(e,t){var n;return n=\"undefined\"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):\"undefined\"!=typeof e.querySelectorAll?e.querySelectorAll(t||\"*\"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Q.set(e[n],\"globalEval\",!t||Q.get(t[n],\"globalEval\"))}ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;var me,xe,be=/<|&#?\\w+;/;function we(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if(\"object\"===w(o))k.merge(p,o.nodeType?[o]:o);else if(be.test(o)){a=a||f.appendChild(t.createElement(\"div\")),s=(de.exec(o)||[\"\",\"\"])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+k.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;k.merge(p,a.childNodes),(a=f.firstChild).textContent=\"\"}else p.push(t.createTextNode(o));f.textContent=\"\",d=0;while(o=p[d++])if(r&&-1<k.inArray(o,r))i&&i.push(o);else if(l=oe(o),a=ve(f.appendChild(o),\"script\"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||\"\")&&n.push(o)}return f}me=E.createDocumentFragment().appendChild(E.createElement(\"div\")),(xe=E.createElement(\"input\")).setAttribute(\"type\",\"radio\"),xe.setAttribute(\"checked\",\"checked\"),xe.setAttribute(\"name\",\"t\"),me.appendChild(xe),y.checkClone=me.cloneNode(!0).cloneNode(!0).lastChild.checked,me.innerHTML=\"<textarea>x</textarea>\",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==(\"focus\"===t)}function Ae(e,t,n,r,i,o){var a,s;if(\"object\"==typeof t){for(s in\"string\"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&(\"string\"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return\"undefined\"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||\"\").match(R)||[\"\"]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(\".\")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||\"\").match(R)||[\"\"]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&(\"**\"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,\"handle events\")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,\"events\")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t<arguments.length;t++)u[t]=arguments[t];if(s.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,s)){a=k.event.handlers.call(this,s,l),t=0;while((i=a[t++])&&!s.isPropagationStopped()){s.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!s.isImmediatePropagationStopped())s.rnamespace&&!1!==o.namespace&&!s.rnamespace.test(o.namespace)||(s.handleObj=o,s.data=o.data,void 0!==(r=((k.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,u))&&!1===(s.result=r)&&(s.preventDefault(),s.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,s),s.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!(\"click\"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&(\"click\"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+\" \"]&&(a[i]=r.needsContext?-1<k(i,this).index(l):k.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(k.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[k.expando]?e:new k.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,\"input\")&&De(t,\"click\",ke),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,\"input\")&&De(t,\"click\"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,\"input\")&&Q.get(t,\"click\")||A(t,\"a\")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},k.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},k.Event=function(e,t){if(!(this instanceof k.Event))return new k.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?ke:Se,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&k.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[k.expando]=!0},k.Event.prototype={constructor:k.Event,isDefaultPrevented:Se,isPropagationStopped:Se,isImmediatePropagationStopped:Se,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=ke,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=ke,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=ke,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},k.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,\"char\":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&Te.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&Ce.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},k.event.addProp),k.each({focus:\"focusin\",blur:\"focusout\"},function(e,t){k.event.special[e]={setup:function(){return De(this,e,Ne),!1},trigger:function(){return De(this,e),!0},delegateType:t}}),k.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(e,i){k.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||k.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),k.fn.extend({on:function(e,t,n,r){return Ae(this,e,t,n,r)},one:function(e,t,n,r){return Ae(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,k(e.delegateTarget).off(r.namespace?r.origType+\".\"+r.namespace:r.origType,r.selector,r.handler),this;if(\"object\"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&\"function\"!=typeof t||(n=t,t=void 0),!1===n&&(n=Se),this.each(function(){k.event.remove(this,e,n,t)})}});var je=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)[^>]*)\\/>/gi,qe=/<script|<style|<link/i,Le=/checked\\s*(?:[^=]|=\\s*.checked.)/i,He=/^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;function Oe(e,t){return A(e,\"table\")&&A(11!==t.nodeType?t:t.firstChild,\"tr\")&&k(e).children(\"tbody\")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute(\"type\"))+\"/\"+e.type,e}function Re(e){return\"true/\"===(e.type||\"\").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute(\"type\"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n<r;n++)k.event.add(t,i,l[i][n]);J.hasData(e)&&(s=J.access(e),u=k.extend({},s),J.set(t,u))}}function Ie(n,r,i,o){r=g.apply([],r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&\"string\"==typeof d&&!y.checkClone&&Le.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Ie(t,r,i,o)});if(f&&(t=(e=we(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=k.map(ve(e,\"script\"),Pe)).length;c<f;c++)u=e,c!==p&&(u=k.clone(u,!0,!0),s&&k.merge(a,ve(u,\"script\"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,k.map(a,Re),c=0;c<s;c++)u=a[c],he.test(u.type||\"\")&&!Q.access(u,\"globalEval\")&&k.contains(l,u)&&(u.src&&\"module\"!==(u.type||\"\").toLowerCase()?k._evalUrl&&!u.noModule&&k._evalUrl(u.src,{nonce:u.nonce||u.getAttribute(\"nonce\")}):b(u.textContent.replace(He,\"\"),u,l))}return n}function We(e,t,n){for(var r,i=t?k.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||k.cleanData(ve(r)),r.parentNode&&(n&&oe(r)&&ye(ve(r,\"script\")),r.parentNode.removeChild(r));return e}k.extend({htmlPrefilter:function(e){return e.replace(je,\"<$1></$2>\")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,\"input\"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:\"input\"!==l&&\"textarea\"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Me(o[r],a[r]);else Me(e,c);return 0<(a=ve(c,\"script\")).length&&ye(a,!f&&ve(e,\"script\")),c},cleanData:function(e){for(var t,n,r,i=k.event.special,o=0;void 0!==(n=e[o]);o++)if(G(n)){if(t=n[Q.expando]){if(t.events)for(r in t.events)i[r]?k.event.remove(n,r):k.removeEvent(n,r,t.handle);n[Q.expando]=void 0}n[J.expando]&&(n[J.expando]=void 0)}}}),k.fn.extend({detach:function(e){return We(this,e,!0)},remove:function(e){return We(this,e)},text:function(e){return _(this,function(e){return void 0===e?k.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Ie(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Oe(this,e).appendChild(e)})},prepend:function(){return Ie(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Oe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(k.cleanData(ve(e,!1)),e.textContent=\"\");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return k.clone(this,e,t)})},html:function(e){return _(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if(\"string\"==typeof e&&!qe.test(e)&&!ge[(de.exec(e)||[\"\",\"\"])[1].toLowerCase()]){e=k.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(k.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Ie(this,arguments,function(e){var t=this.parentNode;k.inArray(this,n)<0&&(k.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),k.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(e,a){k.fn[e]=function(e){for(var t,n=[],r=k(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),k(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var $e=new RegExp(\"^(\"+te+\")(?!px)[a-z%]+$\",\"i\"),Fe=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},Be=new RegExp(re.join(\"|\"),\"i\");function _e(e,t,n){var r,i,o,a,s=e.style;return(n=n||Fe(e))&&(\"\"!==(a=n.getPropertyValue(t)||n[t])||oe(e)||(a=k.style(e,t)),!y.pixelBoxStyles()&&$e.test(a)&&Be.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+\"\":a}function ze(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(u){s.style.cssText=\"position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0\",u.style.cssText=\"position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%\",ie.appendChild(s).appendChild(u);var e=C.getComputedStyle(u);n=\"1%\"!==e.top,a=12===t(e.marginLeft),u.style.right=\"60%\",o=36===t(e.right),r=36===t(e.width),u.style.position=\"absolute\",i=12===t(u.offsetWidth/3),ie.removeChild(s),u=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s=E.createElement(\"div\"),u=E.createElement(\"div\");u.style&&(u.style.backgroundClip=\"content-box\",u.cloneNode(!0).style.backgroundClip=\"\",y.clearCloneStyle=\"content-box\"===u.style.backgroundClip,k.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),a},scrollboxSize:function(){return e(),i}}))}();var Ue=[\"Webkit\",\"Moz\",\"ms\"],Xe=E.createElement(\"div\").style,Ve={};function Ge(e){var t=k.cssProps[e]||Ve[e];return t||(e in Xe?e:Ve[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Ue.length;while(n--)if((e=Ue[n]+t)in Xe)return e}(e)||e)}var Ye=/^(none|table(?!-c[ea]).+)/,Qe=/^--/,Je={position:\"absolute\",visibility:\"hidden\",display:\"block\"},Ke={letterSpacing:\"0\",fontWeight:\"400\"};function Ze(e,t,n){var r=ne.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||\"px\"):t}function et(e,t,n,r,i,o){var a=\"width\"===t?1:0,s=0,u=0;if(n===(r?\"border\":\"content\"))return 0;for(;a<4;a+=2)\"margin\"===n&&(u+=k.css(e,n+re[a],!0,i)),r?(\"content\"===n&&(u-=k.css(e,\"padding\"+re[a],!0,i)),\"margin\"!==n&&(u-=k.css(e,\"border\"+re[a]+\"Width\",!0,i))):(u+=k.css(e,\"padding\"+re[a],!0,i),\"padding\"!==n?u+=k.css(e,\"border\"+re[a]+\"Width\",!0,i):s+=k.css(e,\"border\"+re[a]+\"Width\",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e[\"offset\"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function tt(e,t,n){var r=Fe(e),i=(!y.boxSizingReliable()||n)&&\"border-box\"===k.css(e,\"boxSizing\",!1,r),o=i,a=_e(e,t,r),s=\"offset\"+t[0].toUpperCase()+t.slice(1);if($e.test(a)){if(!n)return a;a=\"auto\"}return(!y.boxSizingReliable()&&i||\"auto\"===a||!parseFloat(a)&&\"inline\"===k.css(e,\"display\",!1,r))&&e.getClientRects().length&&(i=\"border-box\"===k.css(e,\"boxSizing\",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+et(e,t,n||(i?\"border\":\"content\"),o,r,a)+\"px\"}function nt(e,t,n,r,i){return new nt.prototype.init(e,t,n,r,i)}k.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=_e(e,\"opacity\");return\"\"===n?\"1\":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=V(t),u=Qe.test(t),l=e.style;if(u||(t=Ge(s)),a=k.cssHooks[t]||k.cssHooks[s],void 0===n)return a&&\"get\"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];\"string\"===(o=typeof n)&&(i=ne.exec(n))&&i[1]&&(n=le(e,t,i),o=\"number\"),null!=n&&n==n&&(\"number\"!==o||u||(n+=i&&i[3]||(k.cssNumber[s]?\"\":\"px\")),y.clearCloneStyle||\"\"!==n||0!==t.indexOf(\"background\")||(l[t]=\"inherit\"),a&&\"set\"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=V(t);return Qe.test(t)||(t=Ge(s)),(a=k.cssHooks[t]||k.cssHooks[s])&&\"get\"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=_e(e,t,r)),\"normal\"===i&&t in Ke&&(i=Ke[t]),\"\"===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),k.each([\"height\",\"width\"],function(e,u){k.cssHooks[u]={get:function(e,t,n){if(t)return!Ye.test(k.css(e,\"display\"))||e.getClientRects().length&&e.getBoundingClientRect().width?tt(e,u,n):ue(e,Je,function(){return tt(e,u,n)})},set:function(e,t,n){var r,i=Fe(e),o=!y.scrollboxSize()&&\"absolute\"===i.position,a=(o||n)&&\"border-box\"===k.css(e,\"boxSizing\",!1,i),s=n?et(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e[\"offset\"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-et(e,u,\"border\",!1,i)-.5)),s&&(r=ne.exec(t))&&\"px\"!==(r[3]||\"px\")&&(e.style[u]=t,t=k.css(e,u)),Ze(0,t,s)}}}),k.cssHooks.marginLeft=ze(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(_e(e,\"marginLeft\"))||e.getBoundingClientRect().left-ue(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+\"px\"}),k.each({margin:\"\",padding:\"\",border:\"Width\"},function(i,o){k.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r=\"string\"==typeof e?e.split(\" \"):[e];t<4;t++)n[i+re[t]+o]=r[t]||r[t-2]||r[0];return n}},\"margin\"!==i&&(k.cssHooks[i+o].set=Ze)}),k.fn.extend({css:function(e,t){return _(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Fe(e),i=t.length;a<i;a++)o[t[a]]=k.css(e,t[a],!1,r);return o}return void 0!==n?k.style(e,t,n):k.css(e,t)},e,t,1<arguments.length)}}),((k.Tween=nt).prototype={constructor:nt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||k.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(k.cssNumber[n]?\"\":\"px\")},cur:function(){var e=nt.propHooks[this.prop];return e&&e.get?e.get(this):nt.propHooks._default.get(this)},run:function(e){var t,n=nt.propHooks[this.prop];return this.options.duration?this.pos=t=k.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):nt.propHooks._default.set(this),this}}).init.prototype=nt.prototype,(nt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=k.css(e.elem,e.prop,\"\"))&&\"auto\"!==t?t:0},set:function(e){k.fx.step[e.prop]?k.fx.step[e.prop](e):1!==e.elem.nodeType||!k.cssHooks[e.prop]&&null==e.elem.style[Ge(e.prop)]?e.elem[e.prop]=e.now:k.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=nt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},k.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:\"swing\"},k.fx=nt.prototype.init,k.fx.step={};var rt,it,ot,at,st=/^(?:toggle|show|hide)$/,ut=/queueHooks$/;function lt(){it&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(lt):C.setTimeout(lt,k.fx.interval),k.fx.tick())}function ct(){return C.setTimeout(function(){rt=void 0}),rt=Date.now()}function ft(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i[\"margin\"+(n=re[r])]=i[\"padding\"+n]=e;return t&&(i.opacity=i.width=e),i}function pt(e,t,n){for(var r,i=(dt.tweeners[t]||[]).concat(dt.tweeners[\"*\"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function dt(o,e,t){var n,a,r=0,i=dt.prefilters.length,s=k.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=rt||ct(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:k.extend({},e),opts:k.extend(!0,{specialEasing:{},easing:k.easing._default},t),originalProperties:e,originalOptions:t,startTime:rt||ct(),duration:t.duration,tweens:[],createTween:function(e,t){var n=k.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=V(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=k.cssHooks[r])&&\"expand\"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=dt.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(k._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return k.map(c,pt,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),k.fx.timer(k.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}k.Animation=k.extend(dt,{tweeners:{\"*\":[function(e,t){var n=this.createTween(e,t);return le(n.elem,e,ne.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=[\"*\"]):e=e.match(R);for(var n,r=0,i=e.length;r<i;r++)n=e[r],dt.tweeners[n]=dt.tweeners[n]||[],dt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f=\"width\"in t||\"height\"in t,p=this,d={},h=e.style,g=e.nodeType&&se(e),v=Q.get(e,\"fxshow\");for(r in n.queue||(null==(a=k._queueHooks(e,\"fx\")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,k.queue(e,\"fx\").length||a.empty.fire()})})),t)if(i=t[r],st.test(i)){if(delete t[r],o=o||\"toggle\"===i,i===(g?\"hide\":\"show\")){if(\"show\"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||k.style(e,r)}if((u=!k.isEmptyObject(t))||!k.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Q.get(e,\"display\")),\"none\"===(c=k.css(e,\"display\"))&&(l?c=l:(fe([e],!0),l=e.style.display||l,c=k.css(e,\"display\"),fe([e]))),(\"inline\"===c||\"inline-block\"===c&&null!=l)&&\"none\"===k.css(e,\"float\")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l=\"none\"===c?\"\":c)),h.display=\"inline-block\")),n.overflow&&(h.overflow=\"hidden\",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?\"hidden\"in v&&(g=v.hidden):v=Q.access(e,\"fxshow\",{display:l}),o&&(v.hidden=!g),g&&fe([e],!0),p.done(function(){for(r in g||fe([e]),Q.remove(e,\"fxshow\"),d)k.style(e,r,d[r])})),u=pt(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?dt.prefilters.unshift(e):dt.prefilters.push(e)}}),k.speed=function(e,t,n){var r=e&&\"object\"==typeof e?k.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return k.fx.off?r.duration=0:\"number\"!=typeof r.duration&&(r.duration in k.fx.speeds?r.duration=k.fx.speeds[r.duration]:r.duration=k.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue=\"fx\"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&k.dequeue(this,r.queue)},r},k.fn.extend({fadeTo:function(e,t,n,r){return this.filter(se).css(\"opacity\",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=k.isEmptyObject(t),o=k.speed(e,n,r),a=function(){var e=dt(this,k.extend({},t),o);(i||Q.get(this,\"finish\"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return\"string\"!=typeof i&&(o=e,e=i,i=void 0),e&&!1!==i&&this.queue(i||\"fx\",[]),this.each(function(){var e=!0,t=null!=i&&i+\"queueHooks\",n=k.timers,r=Q.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&ut.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||k.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||\"fx\"),this.each(function(){var e,t=Q.get(this),n=t[a+\"queue\"],r=t[a+\"queueHooks\"],i=k.timers,o=n?n.length:0;for(t.finish=!0,k.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),k.each([\"toggle\",\"show\",\"hide\"],function(e,r){var i=k.fn[r];k.fn[r]=function(e,t,n){return null==e||\"boolean\"==typeof e?i.apply(this,arguments):this.animate(ft(r,!0),e,t,n)}}),k.each({slideDown:ft(\"show\"),slideUp:ft(\"hide\"),slideToggle:ft(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(e,r){k.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),k.timers=[],k.fx.tick=function(){var e,t=0,n=k.timers;for(rt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||k.fx.stop(),rt=void 0},k.fx.timer=function(e){k.timers.push(e),k.fx.start()},k.fx.interval=13,k.fx.start=function(){it||(it=!0,lt())},k.fx.stop=function(){it=null},k.fx.speeds={slow:600,fast:200,_default:400},k.fn.delay=function(r,e){return r=k.fx&&k.fx.speeds[r]||r,e=e||\"fx\",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},ot=E.createElement(\"input\"),at=E.createElement(\"select\").appendChild(E.createElement(\"option\")),ot.type=\"checkbox\",y.checkOn=\"\"!==ot.value,y.optSelected=at.selected,(ot=E.createElement(\"input\")).value=\"t\",ot.type=\"radio\",y.radioValue=\"t\"===ot.value;var ht,gt=k.expr.attrHandle;k.fn.extend({attr:function(e,t){return _(this,k.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){k.removeAttr(this,e)})}}),k.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return\"undefined\"==typeof e.getAttribute?k.prop(e,t,n):(1===o&&k.isXMLDoc(e)||(i=k.attrHooks[t.toLowerCase()]||(k.expr.match.bool.test(t)?ht:void 0)),void 0!==n?null===n?void k.removeAttr(e,t):i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+\"\"),n):i&&\"get\"in i&&null!==(r=i.get(e,t))?r:null==(r=k.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&\"radio\"===t&&A(e,\"input\")){var n=e.value;return e.setAttribute(\"type\",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(R);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),ht={set:function(e,t,n){return!1===t?k.removeAttr(e,n):e.setAttribute(n,n),n}},k.each(k.expr.match.bool.source.match(/\\w+/g),function(e,t){var a=gt[t]||k.find.attr;gt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=gt[o],gt[o]=r,r=null!=a(e,t,n)?o:null,gt[o]=i),r}});var vt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;function mt(e){return(e.match(R)||[]).join(\" \")}function xt(e){return e.getAttribute&&e.getAttribute(\"class\")||\"\"}function bt(e){return Array.isArray(e)?e:\"string\"==typeof e&&e.match(R)||[]}k.fn.extend({prop:function(e,t){return _(this,k.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[k.propFix[e]||e]})}}),k.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&k.isXMLDoc(e)||(t=k.propFix[t]||t,i=k.propHooks[t]),void 0!==n?i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&\"get\"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=k.find.attr(e,\"tabindex\");return t?parseInt(t,10):vt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{\"for\":\"htmlFor\",\"class\":\"className\"}}),y.optSelected||(k.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),k.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){k.propFix[this.toLowerCase()]=this}),k.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).addClass(t.call(this,e,xt(this)))});if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&\" \"+mt(i)+\" \"){a=0;while(o=e[a++])r.indexOf(\" \"+o+\" \")<0&&(r+=o+\" \");i!==(s=mt(r))&&n.setAttribute(\"class\",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).removeClass(t.call(this,e,xt(this)))});if(!arguments.length)return this.attr(\"class\",\"\");if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&\" \"+mt(i)+\" \"){a=0;while(o=e[a++])while(-1<r.indexOf(\" \"+o+\" \"))r=r.replace(\" \"+o+\" \",\" \");i!==(s=mt(r))&&n.setAttribute(\"class\",s)}return this},toggleClass:function(i,t){var o=typeof i,a=\"string\"===o||Array.isArray(i);return\"boolean\"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){k(this).toggleClass(i.call(this,e,xt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=k(this),r=bt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&\"boolean\"!==o||((e=xt(this))&&Q.set(this,\"__className__\",e),this.setAttribute&&this.setAttribute(\"class\",e||!1===i?\"\":Q.get(this,\"__className__\")||\"\"))})},hasClass:function(e){var t,n,r=0;t=\" \"+e+\" \";while(n=this[r++])if(1===n.nodeType&&-1<(\" \"+mt(xt(n))+\" \").indexOf(t))return!0;return!1}});var wt=/\\r/g;k.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,k(this).val()):n)?t=\"\":\"number\"==typeof t?t+=\"\":Array.isArray(t)&&(t=k.map(t,function(e){return null==e?\"\":e+\"\"})),(r=k.valHooks[this.type]||k.valHooks[this.nodeName.toLowerCase()])&&\"set\"in r&&void 0!==r.set(this,t,\"value\")||(this.value=t))})):t?(r=k.valHooks[t.type]||k.valHooks[t.nodeName.toLowerCase()])&&\"get\"in r&&void 0!==(e=r.get(t,\"value\"))?e:\"string\"==typeof(e=t.value)?e.replace(wt,\"\"):null==e?\"\":e:void 0}}),k.extend({valHooks:{option:{get:function(e){var t=k.find.attr(e,\"value\");return null!=t?t:mt(k.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a=\"select-one\"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,\"optgroup\"))){if(t=k(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=k.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<k.inArray(k.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),k.each([\"radio\",\"checkbox\"],function(){k.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<k.inArray(k(e).val(),t)}},y.checkOn||(k.valHooks[this].get=function(e){return null===e.getAttribute(\"value\")?\"on\":e.value})}),y.focusin=\"onfocusin\"in C;var Tt=/^(?:focusinfocus|focusoutblur)$/,Ct=function(e){e.stopPropagation()};k.extend(k.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,\"type\")?e.type:e,h=v.call(e,\"namespace\")?e.namespace.split(\".\"):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!Tt.test(d+k.event.triggered)&&(-1<d.indexOf(\".\")&&(d=(h=d.split(\".\")).shift(),h.sort()),u=d.indexOf(\":\")<0&&\"on\"+d,(e=e[k.expando]?e:new k.Event(d,\"object\"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join(\".\"),e.rnamespace=e.namespace?new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:k.makeArray(t,[e]),c=k.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,Tt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Q.get(o,\"events\")||{})[e.type]&&Q.get(o,\"handle\"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&G(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!G(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),k.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,Ct),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,Ct),k.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=k.extend(new k.Event,n,{type:e,isSimulated:!0});k.event.trigger(r,null,t)}}),k.fn.extend({trigger:function(e,t){return this.each(function(){k.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return k.event.trigger(e,t,n,!0)}}),y.focusin||k.each({focus:\"focusin\",blur:\"focusout\"},function(n,r){var i=function(e){k.event.simulate(r,e.target,k.event.fix(e))};k.event.special[r]={setup:function(){var e=this.ownerDocument||this,t=Q.access(e,r);t||e.addEventListener(n,i,!0),Q.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this,t=Q.access(e,r)-1;t?Q.access(e,r,t):(e.removeEventListener(n,i,!0),Q.remove(e,r))}}});var Et=C.location,kt=Date.now(),St=/\\?/;k.parseXML=function(e){var t;if(!e||\"string\"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,\"text/xml\")}catch(e){t=void 0}return t&&!t.getElementsByTagName(\"parsererror\").length||k.error(\"Invalid XML: \"+e),t};var Nt=/\\[\\]$/,At=/\\r?\\n/g,Dt=/^(?:submit|button|image|reset|file)$/i,jt=/^(?:input|select|textarea|keygen)/i;function qt(n,e,r,i){var t;if(Array.isArray(e))k.each(e,function(e,t){r||Nt.test(n)?i(n,t):qt(n+\"[\"+(\"object\"==typeof t&&null!=t?e:\"\")+\"]\",t,r,i)});else if(r||\"object\"!==w(e))i(n,e);else for(t in e)qt(n+\"[\"+t+\"]\",e[t],r,i)}k.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+\"=\"+encodeURIComponent(null==n?\"\":n)};if(null==e)return\"\";if(Array.isArray(e)||e.jquery&&!k.isPlainObject(e))k.each(e,function(){i(this.name,this.value)});else for(n in e)qt(n,e[n],t,i);return r.join(\"&\")},k.fn.extend({serialize:function(){return k.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=k.prop(this,\"elements\");return e?k.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!k(this).is(\":disabled\")&&jt.test(this.nodeName)&&!Dt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=k(this).val();return null==n?null:Array.isArray(n)?k.map(n,function(e){return{name:t.name,value:e.replace(At,\"\\r\\n\")}}):{name:t.name,value:n.replace(At,\"\\r\\n\")}}).get()}});var Lt=/%20/g,Ht=/#.*$/,Ot=/([?&])_=[^&]*/,Pt=/^(.*?):[ \\t]*([^\\r\\n]*)$/gm,Rt=/^(?:GET|HEAD)$/,Mt=/^\\/\\//,It={},Wt={},$t=\"*/\".concat(\"*\"),Ft=E.createElement(\"a\");function Bt(o){return function(e,t){\"string\"!=typeof e&&(t=e,e=\"*\");var n,r=0,i=e.toLowerCase().match(R)||[];if(m(t))while(n=i[r++])\"+\"===n[0]?(n=n.slice(1)||\"*\",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function _t(t,i,o,a){var s={},u=t===Wt;function l(e){var r;return s[e]=!0,k.each(t[e]||[],function(e,t){var n=t(i,o,a);return\"string\"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s[\"*\"]&&l(\"*\")}function zt(e,t){var n,r,i=k.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&k.extend(!0,e,r),e}Ft.href=Et.href,k.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Et.href,type:\"GET\",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Et.protocol),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":$t,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":JSON.parse,\"text xml\":k.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,k.ajaxSettings),t):zt(k.ajaxSettings,e)},ajaxPrefilter:Bt(It),ajaxTransport:Bt(Wt),ajax:function(e,t){\"object\"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=k.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?k(y):k.event,x=k.Deferred(),b=k.Callbacks(\"once memory\"),w=v.statusCode||{},a={},s={},u=\"canceled\",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Pt.exec(p))n[t[1].toLowerCase()+\" \"]=(n[t[1].toLowerCase()+\" \"]||[]).concat(t[2])}t=n[e.toLowerCase()+\" \"]}return null==t?null:t.join(\", \")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Et.href)+\"\").replace(Mt,Et.protocol+\"//\"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||\"*\").toLowerCase().match(R)||[\"\"],null==v.crossDomain){r=E.createElement(\"a\");try{r.href=v.url,r.href=r.href,v.crossDomain=Ft.protocol+\"//\"+Ft.host!=r.protocol+\"//\"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&\"string\"!=typeof v.data&&(v.data=k.param(v.data,v.traditional)),_t(It,v,t,T),h)return T;for(i in(g=k.event&&v.global)&&0==k.active++&&k.event.trigger(\"ajaxStart\"),v.type=v.type.toUpperCase(),v.hasContent=!Rt.test(v.type),f=v.url.replace(Ht,\"\"),v.hasContent?v.data&&v.processData&&0===(v.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&(v.data=v.data.replace(Lt,\"+\")):(o=v.url.slice(f.length),v.data&&(v.processData||\"string\"==typeof v.data)&&(f+=(St.test(f)?\"&\":\"?\")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Ot,\"$1\"),o=(St.test(f)?\"&\":\"?\")+\"_=\"+kt+++o),v.url=f+o),v.ifModified&&(k.lastModified[f]&&T.setRequestHeader(\"If-Modified-Since\",k.lastModified[f]),k.etag[f]&&T.setRequestHeader(\"If-None-Match\",k.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader(\"Content-Type\",v.contentType),T.setRequestHeader(\"Accept\",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+(\"*\"!==v.dataTypes[0]?\", \"+$t+\"; q=0.01\":\"\"):v.accepts[\"*\"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u=\"abort\",b.add(v.complete),T.done(v.success),T.fail(v.error),c=_t(Wt,v,t,T)){if(T.readyState=1,g&&m.trigger(\"ajaxSend\",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort(\"timeout\")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,\"No Transport\");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||\"\",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while(\"*\"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader(\"Content-Type\"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+\" \"+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if(\"*\"===o)o=u;else if(\"*\"!==u&&u!==o){if(!(a=l[u+\" \"+o]||l[\"* \"+o]))for(i in l)if((s=i.split(\" \"))[1]===o&&(a=l[u+\" \"+s[0]]||l[\"* \"+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e[\"throws\"])t=a(t);else try{t=a(t)}catch(e){return{state:\"parsererror\",error:a?e:\"No conversion from \"+u+\" to \"+o}}}return{state:\"success\",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader(\"Last-Modified\"))&&(k.lastModified[f]=u),(u=T.getResponseHeader(\"etag\"))&&(k.etag[f]=u)),204===e||\"HEAD\"===v.type?l=\"nocontent\":304===e?l=\"notmodified\":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l=\"error\",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+\"\",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?\"ajaxSuccess\":\"ajaxError\",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger(\"ajaxComplete\",[T,v]),--k.active||k.event.trigger(\"ajaxStop\")))}return T},getJSON:function(e,t,n){return k.get(e,t,n,\"json\")},getScript:function(e,t){return k.get(e,void 0,t,\"script\")}}),k.each([\"get\",\"post\"],function(e,i){k[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),k.ajax(k.extend({url:e,type:i,dataType:r,data:t,success:n},k.isPlainObject(e)&&e))}}),k._evalUrl=function(e,t){return k.ajax({url:e,type:\"GET\",dataType:\"script\",cache:!0,async:!1,global:!1,converters:{\"text script\":function(){}},dataFilter:function(e){k.globalEval(e,t)}})},k.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=k(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){k(this).wrapInner(n.call(this,e))}):this.each(function(){var e=k(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){k(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not(\"body\").each(function(){k(this).replaceWith(this.childNodes)}),this}}),k.expr.pseudos.hidden=function(e){return!k.expr.pseudos.visible(e)},k.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},k.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var Ut={0:200,1223:204},Xt=k.ajaxSettings.xhr();y.cors=!!Xt&&\"withCredentials\"in Xt,y.ajax=Xt=!!Xt,k.ajaxTransport(function(i){var o,a;if(y.cors||Xt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e[\"X-Requested-With\"]||(e[\"X-Requested-With\"]=\"XMLHttpRequest\"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,\"abort\"===e?r.abort():\"error\"===e?\"number\"!=typeof r.status?t(0,\"error\"):t(r.status,r.statusText):t(Ut[r.status]||r.status,r.statusText,\"text\"!==(r.responseType||\"text\")||\"string\"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o(\"error\"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o(\"abort\");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),k.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),k.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(e){return k.globalEval(e),e}}}),k.ajaxPrefilter(\"script\",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type=\"GET\")}),k.ajaxTransport(\"script\",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=k(\"<script>\").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on(\"load error\",i=function(e){r.remove(),i=null,e&&t(\"error\"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\\?(?=&|$)|\\?\\?/;k.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var e=Gt.pop()||k.expando+\"_\"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter(\"json jsonp\",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?\"url\":\"string\"==typeof e.data&&0===(e.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&Yt.test(e.data)&&\"data\");if(a||\"jsonp\"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,\"$1\"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?\"&\":\"?\")+e.jsonp+\"=\"+r),e.converters[\"script json\"]=function(){return o||k.error(r+\" was not called\"),o[0]},e.dataTypes[0]=\"json\",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),\"script\"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument(\"\").body).innerHTML=\"<form></form><form></form>\",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return\"string\"!=typeof e?[]:(\"boolean\"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument(\"\")).createElement(\"base\")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(\" \");return-1<s&&(r=mt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&\"object\"==typeof t&&(i=\"POST\"),0<a.length&&k.ajax({url:e,type:i||\"GET\",dataType:\"html\",data:t}).done(function(e){o=arguments,a.html(r?k(\"<div>\").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,\"position\"),c=k(e),f={};\"static\"===l&&(e.style.position=\"relative\"),s=c.offset(),o=k.css(e,\"top\"),u=k.css(e,\"left\"),(\"absolute\"===l||\"fixed\"===l)&&-1<(o+u).indexOf(\"auto\")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),\"using\"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if(\"fixed\"===k.css(r,\"position\"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&\"static\"===k.css(e,\"position\"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,\"borderTopWidth\",!0),i.left+=k.css(e,\"borderLeftWidth\",!0))}return{top:t.top-i.top-k.css(r,\"marginTop\",!0),left:t.left-i.left-k.css(r,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&\"static\"===k.css(e,\"position\"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(t,i){var o=\"pageYOffset\"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each([\"top\",\"left\"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+\"px\":t})}),k.each({Height:\"height\",Width:\"width\"},function(a,s){k.each({padding:\"inner\"+a,content:s,\"\":\"outer\"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||\"boolean\"!=typeof e),i=r||(!0===e||!0===t?\"margin\":\"border\");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf(\"outer\")?e[\"inner\"+a]:e.document.documentElement[\"client\"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body[\"scroll\"+a],r[\"scroll\"+a],e.body[\"offset\"+a],r[\"offset\"+a],r[\"client\"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each(\"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu\".split(\" \"),function(e,n){k.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}}),k.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),k.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)}}),k.proxy=function(e,t){var n,r,i;if(\"string\"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||k.guid++,i},k.holdReady=function(e){e?k.readyWait++:k.ready(!0)},k.isArray=Array.isArray,k.parseJSON=JSON.parse,k.nodeName=A,k.isFunction=m,k.isWindow=x,k.camelCase=V,k.type=w,k.now=Date.now,k.isNumeric=function(e){var t=k.type(e);return(\"number\"===t||\"string\"===t)&&!isNaN(e-parseFloat(e))},\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return k});var Qt=C.jQuery,Jt=C.$;return k.noConflict=function(e){return C.$===k&&(C.$=Jt),e&&C.jQuery===k&&(C.jQuery=Qt),k},e||(C.jQuery=C.$=k),k});\n/*\n * jQuery throttle / debounce - v1.1 - 3/7/2010\n * http://benalman.com/projects/jquery-throttle-debounce-plugin/\n * \n * Copyright (c) 2010 \"Cowboy\" Ben Alman\n * Dual licensed under the MIT and GPL licenses.\n * http://benalman.com/about/license/\n */\n(function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!==\"boolean\"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this);\n/*!\n * imagesLoaded PACKAGED v4.1.0\n * JavaScript is all like \"You images are done yet or what?\"\n * MIT License\n */\n!function(t,e){\"function\"==typeof define&&define.amd?define(\"ev-emitter/ev-emitter\",e):\"object\"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}(this,function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var i=this._events=this._events||{},n=i[t]=i[t]||[];return-1==n.indexOf(e)&&n.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var i=this._onceEvents=this._onceEvents||{},n=i[t]=i[t]||[];return n[e]=!0,this}},e.off=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=i.indexOf(e);return-1!=n&&i.splice(n,1),this}},e.emitEvent=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=0,o=i[n];e=e||[];for(var r=this._onceEvents&&this._onceEvents[t];o;){var s=r&&r[o];s&&(this.off(t,o),delete r[o]),o.apply(this,e),n+=s?0:1,o=i[n]}return this}},t}),function(t,e){\"use strict\";\"function\"==typeof define&&define.amd?define([\"ev-emitter/ev-emitter\"],function(i){return e(t,i)}):\"object\"==typeof module&&module.exports?module.exports=e(t,require(\"ev-emitter\")):t.imagesLoaded=e(t,t.EvEmitter)}(window,function(t,e){function i(t,e){for(var i in e)t[i]=e[i];return t}function n(t){var e=[];if(Array.isArray(t))e=t;else if(\"number\"==typeof t.length)for(var i=0;i<t.length;i++)e.push(t[i]);else e.push(t);return e}function o(t,e,r){return this instanceof o?(\"string\"==typeof t&&(t=document.querySelectorAll(t)),this.elements=n(t),this.options=i({},this.options),\"function\"==typeof e?r=e:i(this.options,e),r&&this.on(\"always\",r),this.getImages(),h&&(this.jqDeferred=new h.Deferred),void setTimeout(function(){this.check()}.bind(this))):new o(t,e,r)}function r(t){this.img=t}function s(t,e){this.url=t,this.element=e,this.img=new Image}var h=t.jQuery,a=t.console;o.prototype=Object.create(e.prototype),o.prototype.options={},o.prototype.getImages=function(){this.images=[],this.elements.forEach(this.addElementImages,this)},o.prototype.addElementImages=function(t){\"IMG\"==t.nodeName&&this.addImage(t),this.options.background===!0&&this.addElementBackgroundImages(t);var e=t.nodeType;if(e&&d[e]){for(var i=t.querySelectorAll(\"img\"),n=0;n<i.length;n++){var o=i[n];this.addImage(o)}if(\"string\"==typeof this.options.background){var r=t.querySelectorAll(this.options.background);for(n=0;n<r.length;n++){var s=r[n];this.addElementBackgroundImages(s)}}}};var d={1:!0,9:!0,11:!0};return o.prototype.addElementBackgroundImages=function(t){var e=getComputedStyle(t);if(e)for(var i=/url\\((['\"])?(.*?)\\1\\)/gi,n=i.exec(e.backgroundImage);null!==n;){var o=n&&n[2];o&&this.addBackground(o,t),n=i.exec(e.backgroundImage)}},o.prototype.addImage=function(t){var e=new r(t);this.images.push(e)},o.prototype.addBackground=function(t,e){var i=new s(t,e);this.images.push(i)},o.prototype.check=function(){function t(t,i,n){setTimeout(function(){e.progress(t,i,n)})}var e=this;return this.progressedCount=0,this.hasAnyBroken=!1,this.images.length?void this.images.forEach(function(e){e.once(\"progress\",t),e.check()}):void this.complete()},o.prototype.progress=function(t,e,i){this.progressedCount++,this.hasAnyBroken=this.hasAnyBroken||!t.isLoaded,this.emitEvent(\"progress\",[this,t,e]),this.jqDeferred&&this.jqDeferred.notify&&this.jqDeferred.notify(this,t),this.progressedCount==this.images.length&&this.complete(),this.options.debug&&a&&a.log(\"progress: \"+i,t,e)},o.prototype.complete=function(){var t=this.hasAnyBroken?\"fail\":\"done\";if(this.isComplete=!0,this.emitEvent(t,[this]),this.emitEvent(\"always\",[this]),this.jqDeferred){var e=this.hasAnyBroken?\"reject\":\"resolve\";this.jqDeferred[e](this)}},r.prototype=Object.create(e.prototype),r.prototype.check=function(){var t=this.getIsImageComplete();return t?void this.confirm(0!==this.img.naturalWidth,\"naturalWidth\"):(this.proxyImage=new Image,this.proxyImage.addEventListener(\"load\",this),this.proxyImage.addEventListener(\"error\",this),this.img.addEventListener(\"load\",this),this.img.addEventListener(\"error\",this),void(this.proxyImage.src=this.img.src))},r.prototype.getIsImageComplete=function(){return this.img.complete&&void 0!==this.img.naturalWidth},r.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent(\"progress\",[this,this.img,e])},r.prototype.handleEvent=function(t){var e=\"on\"+t.type;this[e]&&this[e](t)},r.prototype.onload=function(){this.confirm(!0,\"onload\"),this.unbindEvents()},r.prototype.onerror=function(){this.confirm(!1,\"onerror\"),this.unbindEvents()},r.prototype.unbindEvents=function(){this.proxyImage.removeEventListener(\"load\",this),this.proxyImage.removeEventListener(\"error\",this),this.img.removeEventListener(\"load\",this),this.img.removeEventListener(\"error\",this)},s.prototype=Object.create(r.prototype),s.prototype.check=function(){this.img.addEventListener(\"load\",this),this.img.addEventListener(\"error\",this),this.img.src=this.url;var t=this.getIsImageComplete();t&&(this.confirm(0!==this.img.naturalWidth,\"naturalWidth\"),this.unbindEvents())},s.prototype.unbindEvents=function(){this.img.removeEventListener(\"load\",this),this.img.removeEventListener(\"error\",this)},s.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent(\"progress\",[this,this.element,e])},o.makeJQueryPlugin=function(e){e=e||t.jQuery,e&&(h=e,h.fn.imagesLoaded=function(t,e){var i=new o(this,t,e);return i.jqDeferred.promise(h(this))})},o.makeJQueryPlugin(),o});\n/*! lz-string-1.3.3-min.js | (c) 2013 Pieroxy | Licensed under a WTFPL license */\nvar LZString={_keyStr:\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\",_f:String.fromCharCode,compressToBase64:function(e){if(e==null)return\"\";var t=\"\";var n,r,i,s,o,u,a;var f=0;e=LZString.compress(e);while(f<e.length*2){if(f%2==0){n=e.charCodeAt(f/2)>>8;r=e.charCodeAt(f/2)&255;if(f/2+1<e.length)i=e.charCodeAt(f/2+1)>>8;else i=NaN}else{n=e.charCodeAt((f-1)/2)&255;if((f+1)/2<e.length){r=e.charCodeAt((f+1)/2)>>8;i=e.charCodeAt((f+1)/2)&255}else r=i=NaN}f+=3;s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+LZString._keyStr.charAt(s)+LZString._keyStr.charAt(o)+LZString._keyStr.charAt(u)+LZString._keyStr.charAt(a)}return t},decompressFromBase64:function(e){if(e==null)return\"\";var t=\"\",n=0,r,i,s,o,u,a,f,l,c=0,h=LZString._f;e=e.replace(/[^A-Za-z0-9\\+\\/\\=]/g,\"\");while(c<e.length){u=LZString._keyStr.indexOf(e.charAt(c++));a=LZString._keyStr.indexOf(e.charAt(c++));f=LZString._keyStr.indexOf(e.charAt(c++));l=LZString._keyStr.indexOf(e.charAt(c++));i=u<<2|a>>4;s=(a&15)<<4|f>>2;o=(f&3)<<6|l;if(n%2==0){r=i<<8;if(f!=64){t+=h(r|s)}if(l!=64){r=o<<8}}else{t=t+h(r|i);if(f!=64){r=s<<8}if(l!=64){t+=h(r|o)}}n+=3}return LZString.decompress(t)},compressToUTF16:function(e){if(e==null)return\"\";var t=\"\",n,r,i,s=0,o=LZString._f;e=LZString.compress(e);for(n=0;n<e.length;n++){r=e.charCodeAt(n);switch(s++){case 0:t+=o((r>>1)+32);i=(r&1)<<14;break;case 1:t+=o(i+(r>>2)+32);i=(r&3)<<13;break;case 2:t+=o(i+(r>>3)+32);i=(r&7)<<12;break;case 3:t+=o(i+(r>>4)+32);i=(r&15)<<11;break;case 4:t+=o(i+(r>>5)+32);i=(r&31)<<10;break;case 5:t+=o(i+(r>>6)+32);i=(r&63)<<9;break;case 6:t+=o(i+(r>>7)+32);i=(r&127)<<8;break;case 7:t+=o(i+(r>>8)+32);i=(r&255)<<7;break;case 8:t+=o(i+(r>>9)+32);i=(r&511)<<6;break;case 9:t+=o(i+(r>>10)+32);i=(r&1023)<<5;break;case 10:t+=o(i+(r>>11)+32);i=(r&2047)<<4;break;case 11:t+=o(i+(r>>12)+32);i=(r&4095)<<3;break;case 12:t+=o(i+(r>>13)+32);i=(r&8191)<<2;break;case 13:t+=o(i+(r>>14)+32);i=(r&16383)<<1;break;case 14:t+=o(i+(r>>15)+32,(r&32767)+32);s=0;break}}return t+o(i+32)},decompressFromUTF16:function(e){if(e==null)return\"\";var t=\"\",n,r,i=0,s=0,o=LZString._f;while(s<e.length){r=e.charCodeAt(s)-32;switch(i++){case 0:n=r<<1;break;case 1:t+=o(n|r>>14);n=(r&16383)<<2;break;case 2:t+=o(n|r>>13);n=(r&8191)<<3;break;case 3:t+=o(n|r>>12);n=(r&4095)<<4;break;case 4:t+=o(n|r>>11);n=(r&2047)<<5;break;case 5:t+=o(n|r>>10);n=(r&1023)<<6;break;case 6:t+=o(n|r>>9);n=(r&511)<<7;break;case 7:t+=o(n|r>>8);n=(r&255)<<8;break;case 8:t+=o(n|r>>7);n=(r&127)<<9;break;case 9:t+=o(n|r>>6);n=(r&63)<<10;break;case 10:t+=o(n|r>>5);n=(r&31)<<11;break;case 11:t+=o(n|r>>4);n=(r&15)<<12;break;case 12:t+=o(n|r>>3);n=(r&7)<<13;break;case 13:t+=o(n|r>>2);n=(r&3)<<14;break;case 14:t+=o(n|r>>1);n=(r&1)<<15;break;case 15:t+=o(n|r);i=0;break}s++}return LZString.decompress(t)},compress:function(e){if(e==null)return\"\";var t,n,r={},i={},s=\"\",o=\"\",u=\"\",a=2,f=3,l=2,c=\"\",h=0,p=0,d,v=LZString._f;for(d=0;d<e.length;d+=1){s=e.charAt(d);if(!Object.prototype.hasOwnProperty.call(r,s)){r[s]=f++;i[s]=true}o=u+s;if(Object.prototype.hasOwnProperty.call(r,o)){u=o}else{if(Object.prototype.hasOwnProperty.call(i,u)){if(u.charCodeAt(0)<256){for(t=0;t<l;t++){h=h<<1;if(p==15){p=0;c+=v(h);h=0}else{p++}}n=u.charCodeAt(0);for(t=0;t<8;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}else{n=1;for(t=0;t<l;t++){h=h<<1|n;if(p==15){p=0;c+=v(h);h=0}else{p++}n=0}n=u.charCodeAt(0);for(t=0;t<16;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}delete i[u]}else{n=r[u];for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}r[o]=f++;u=String(s)}}if(u!==\"\"){if(Object.prototype.hasOwnProperty.call(i,u)){if(u.charCodeAt(0)<256){for(t=0;t<l;t++){h=h<<1;if(p==15){p=0;c+=v(h);h=0}else{p++}}n=u.charCodeAt(0);for(t=0;t<8;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}else{n=1;for(t=0;t<l;t++){h=h<<1|n;if(p==15){p=0;c+=v(h);h=0}else{p++}n=0}n=u.charCodeAt(0);for(t=0;t<16;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}delete i[u]}else{n=r[u];for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}}n=2;for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}while(true){h=h<<1;if(p==15){c+=v(h);break}else p++}return c},decompress:function(e){if(e==null)return\"\";if(e==\"\")return null;var t=[],n,r=4,i=4,s=3,o=\"\",u=\"\",a,f,l,c,h,p,d,v=LZString._f,m={string:e,val:e.charCodeAt(0),position:32768,index:1};for(a=0;a<3;a+=1){t[a]=a}l=0;h=Math.pow(2,2);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}switch(n=l){case 0:l=0;h=Math.pow(2,8);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}d=v(l);break;case 1:l=0;h=Math.pow(2,16);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}d=v(l);break;case 2:return\"\"}t[3]=d;f=u=d;while(true){if(m.index>m.string.length){return\"\"}l=0;h=Math.pow(2,s);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}switch(d=l){case 0:l=0;h=Math.pow(2,8);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}t[i++]=v(l);d=i-1;r--;break;case 1:l=0;h=Math.pow(2,16);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}t[i++]=v(l);d=i-1;r--;break;case 2:return u}if(r==0){r=Math.pow(2,s);s++}if(t[d]){o=t[d]}else{if(d===i){o=f+f.charAt(0)}else{return null}}u+=o;t[i++]=f+o.charAt(0);r--;f=o;if(r==0){r=Math.pow(2,s);s++}}}};if(typeof module!==\"undefined\"&&module!=null){module.exports=LZString}\n/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */\nvar saveAs=saveAs||navigator.msSaveBlob&&navigator.msSaveBlob.bind(navigator)||function(e){\"use strict\";var t=e.document,n=function(){return e.URL||e.webkitURL||e},r=e.URL||e.webkitURL||e,i=t.createElementNS(\"http://www.w3.org/1999/xhtml\",\"a\"),s=\"download\"in i,o=function(n){var r=t.createEvent(\"MouseEvents\");r.initMouseEvent(\"click\",true,false,e,0,0,0,0,0,false,false,false,false,0,null);n.dispatchEvent(r)},u=e.webkitRequestFileSystem,a=e.requestFileSystem||u||e.mozRequestFileSystem,f=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},l=\"application/octet-stream\",c=0,h=[],p=function(){var e=h.length;while(e--){var t=h[e];if(typeof t===\"string\"){r.revokeObjectURL(t)}else{t.remove()}}h.length=0},d=function(e,t,n){t=[].concat(t);var r=t.length;while(r--){var i=e[\"on\"+t[r]];if(typeof i===\"function\"){try{i.call(e,n||e)}catch(s){f(s)}}}},v=function(t,r){var f=this,p=t.type,v=false,m,g,y=function(){var e=n().createObjectURL(t);h.push(e);return e},b=function(){d(f,\"writestart progress write writeend\".split(\" \"))},w=function(){if(v||!m){m=y(t)}if(g){g.location.href=m}else{window.open(m,\"_blank\")}f.readyState=f.DONE;b()},E=function(e){return function(){if(f.readyState!==f.DONE){return e.apply(this,arguments)}}},S={create:true,exclusive:false},x;f.readyState=f.INIT;if(!r){r=\"download\"}if(s){m=y(t);i.href=m;i.download=r;o(i);f.readyState=f.DONE;b();return}if(e.chrome&&p&&p!==l){x=t.slice||t.webkitSlice;t=x.call(t,0,t.size,l);v=true}if(u&&r!==\"download\"){r+=\".download\"}if(p===l||u){g=e}if(!a){w();return}c+=t.size;a(e.TEMPORARY,c,E(function(e){e.root.getDirectory(\"saved\",S,E(function(e){var n=function(){e.getFile(r,S,E(function(e){e.createWriter(E(function(n){n.onwriteend=function(t){g.location.href=e.toURL();h.push(e);f.readyState=f.DONE;d(f,\"writeend\",t)};n.onerror=function(){var e=n.error;if(e.code!==e.ABORT_ERR){w()}};\"writestart progress write abort\".split(\" \").forEach(function(e){n[\"on\"+e]=f[\"on\"+e]});n.write(t);f.abort=function(){n.abort();f.readyState=f.DONE};f.readyState=f.WRITING}),w)}),w)};e.getFile(r,{create:false},E(function(e){e.remove();n()}),E(function(e){if(e.code===e.NOT_FOUND_ERR){n()}else{w()}}))}),w)}),w)},m=v.prototype,g=function(e,t){return new v(e,t)};m.abort=function(){var e=this;e.readyState=e.DONE;d(e,\"abort\")};m.readyState=m.INIT=0;m.WRITING=1;m.DONE=2;m.error=m.onwritestart=m.onprogress=m.onwrite=m.onabort=m.onerror=m.onwriteend=null;e.addEventListener(\"unload\",p,false);return g}(self)\n/*! seedrandom.js v2.3.3 | (c) 2013 David Bau, all rights reserved. | Licensed under a BSD-style license */\n!function(a,b,c,d,e,f,g,h,i){function j(a){var b,c=a.length,e=this,f=0,g=e.i=e.j=0,h=e.S=[];for(c||(a=[c++]);d>f;)h[f]=f++;for(f=0;d>f;f++)h[f]=h[g=r&g+a[f%c]+(b=h[f])],h[g]=b;(e.g=function(a){for(var b,c=0,f=e.i,g=e.j,h=e.S;a--;)b=h[f=r&f+1],c=c*d+h[r&(h[f]=h[g=r&g+b])+(h[g]=b)];return e.i=f,e.j=g,c})(d)}function k(a,b){var c,d=[],e=typeof a;if(b&&\"object\"==e)for(c in a)try{d.push(k(a[c],b-1))}catch(f){}return d.length?d:\"string\"==e?a:a+\"\\0\"}function l(a,b){for(var c,d=a+\"\",e=0;e<d.length;)b[r&e]=r&(c^=19*b[r&e])+d.charCodeAt(e++);return n(b)}function m(c){try{return a.crypto.getRandomValues(c=new Uint8Array(d)),n(c)}catch(e){return[+new Date,a,(c=a.navigator)&&c.plugins,a.screen,n(b)]}}function n(a){return String.fromCharCode.apply(0,a)}var o=c.pow(d,e),p=c.pow(2,f),q=2*p,r=d-1,s=c[\"seed\"+i]=function(a,f,g){var h=[],r=l(k(f?[a,n(b)]:null==a?m():a,3),h),s=new j(h);return l(n(s.S),b),(g||function(a,b,d){return d?(c[i]=a,b):a})(function(){for(var a=s.g(e),b=o,c=0;p>a;)a=(a+c)*d,b*=d,c=s.g(1);for(;a>=q;)a/=2,b/=2,c>>>=1;return(a+c)/b},r,this==c)};l(c[i](),b),g&&g.exports?g.exports=s:h&&h.amd&&h(function(){return s})}(this,[],Math,256,6,52,\"object\"==typeof module&&module,\"function\"==typeof define&&define,\"random\");\n/*! console_hack.js | (c) 2015 Thomas Michael Edwards | Licensed under SugarCube's Simple BSD license */\n!function(){for(var methods=[\"assert\",\"clear\",\"count\",\"debug\",\"dir\",\"dirxml\",\"error\",\"exception\",\"group\",\"groupCollapsed\",\"groupEnd\",\"info\",\"log\",\"markTimeline\",\"profile\",\"profileEnd\",\"table\",\"time\",\"timeEnd\",\"timeline\",\"timelineEnd\",\"timeStamp\",\"trace\",\"warn\"],length=methods.length,noop=function(){},console=window.console=window.console||{};length--;){var method=methods[length];console[method]||(console[method]=noop)}}();\n}else{document.documentElement.setAttribute(\"data-init\", \"lacking\");}\n</script>\n<style id=\"style-normalize\" type=\"text/css\">/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\n\n/**\n * 1. Set default font family to sans-serif.\n * 2. Prevent iOS and IE text size adjust after device orientation change,\n *    without disabling user zoom.\n */\n\nhtml {\n  font-family: sans-serif; /* 1 */\n  -ms-text-size-adjust: 100%; /* 2 */\n  -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/**\n * Remove default margin.\n */\n\nbody {\n  margin: 0;\n}\n\n/* HTML5 display definitions\n   ========================================================================== */\n\n/**\n * Correct `block` display not defined for any HTML5 element in IE 8/9.\n * Correct `block` display not defined for `details` or `summary` in IE 10/11\n * and Firefox.\n * Correct `block` display not defined for `main` in IE 11.\n */\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\n\n/**\n * 1. Correct `inline-block` display not defined in IE 8/9.\n * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n */\n\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block; /* 1 */\n  vertical-align: baseline; /* 2 */\n}\n\n/**\n * Prevent modern browsers from displaying `audio` without controls.\n * Remove excess height in iOS 5 devices.\n */\n\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n\n/**\n * Address `[hidden]` styling not present in IE 8/9/10.\n * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.\n */\n\n[hidden],\ntemplate {\n  display: none;\n}\n\n/* Links\n   ========================================================================== */\n\n/**\n * Remove the gray background color from active links in IE 10.\n */\n\na {\n  background-color: transparent;\n}\n\n/**\n * Improve readability of focused elements when they are also in an\n * active/hover state.\n */\n\na:active,\na:hover {\n  outline: 0;\n}\n\n/* Text-level semantics\n   ========================================================================== */\n\n/**\n * Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n */\n\nabbr[title] {\n  border-bottom: 1px dotted;\n}\n\n/**\n * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n */\n\nb,\nstrong {\n  font-weight: bold;\n}\n\n/**\n * Address styling not present in Safari and Chrome.\n */\n\ndfn {\n  font-style: italic;\n}\n\n/**\n * Address variable `h1` font-size and margin within `section` and `article`\n * contexts in Firefox 4+, Safari, and Chrome.\n */\n\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\n/**\n * Address styling not present in IE 8/9.\n */\n\nmark {\n  background: #ff0;\n  color: #000;\n}\n\n/**\n * Address inconsistent and variable font size in all browsers.\n */\n\nsmall {\n  font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` affecting `line-height` in all browsers.\n */\n\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\n/* Embedded content\n   ========================================================================== */\n\n/**\n * Remove border when inside `a` element in IE 8/9/10.\n */\n\nimg {\n  border: 0;\n}\n\n/**\n * Correct overflow not hidden in IE 9/10/11.\n */\n\nsvg:not(:root) {\n  overflow: hidden;\n}\n\n/* Grouping content\n   ========================================================================== */\n\n/**\n * Address margin not present in IE 8/9 and Safari.\n */\n\nfigure {\n  margin: 1em 40px;\n}\n\n/**\n * Address differences between Firefox and other browsers.\n */\n\nhr {\n  box-sizing: content-box;\n  height: 0;\n}\n\n/**\n * Contain overflow in all browsers.\n */\n\npre {\n  overflow: auto;\n}\n\n/**\n * Address odd `em`-unit font size rendering in all browsers.\n */\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\n\n/* Forms\n   ========================================================================== */\n\n/**\n * Known limitation: by default, Chrome and Safari on OS X allow very limited\n * styling of `select`, unless a `border` property is set.\n */\n\n/**\n * 1. Correct color not being inherited.\n *    Known issue: affects color of disabled elements.\n * 2. Correct font properties not being inherited.\n * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit; /* 1 */\n  font: inherit; /* 2 */\n  margin: 0; /* 3 */\n}\n\n/**\n * Address `overflow` set to `hidden` in IE 8/9/10/11.\n */\n\nbutton {\n  overflow: visible;\n}\n\n/**\n * Address inconsistent `text-transform` inheritance for `button` and `select`.\n * All other form control elements do not inherit `text-transform` values.\n * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n * Correct `select` style inheritance in Firefox.\n */\n\nbutton,\nselect {\n  text-transform: none;\n}\n\n/**\n * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n *    and `video` controls.\n * 2. Correct inability to style clickable `input` types in iOS.\n * 3. Improve usability and consistency of cursor style between image-type\n *    `input` and others.\n */\n\nbutton,\nhtml input[type=\"button\"], /* 1 */\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button; /* 2 */\n  cursor: pointer; /* 3 */\n}\n\n/**\n * Re-set default cursor for disabled elements.\n */\n\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\n\n/**\n * Remove inner padding and border in Firefox 4+.\n */\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\n\n/**\n * Address Firefox 4+ setting `line-height` on `input` using `!important` in\n * the UA stylesheet.\n */\n\ninput {\n  line-height: normal;\n}\n\n/**\n * It's recommended that you don't attempt to style these elements.\n * Firefox's implementation doesn't respect box-sizing, padding, or width.\n *\n * 1. Address box sizing set to `content-box` in IE 8/9/10.\n * 2. Remove excess padding in IE 8/9/10.\n */\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Fix the cursor style for Chrome's increment/decrement buttons. For certain\n * `font-size` values of the `input`, it causes the cursor style of the\n * decrement button to change from `default` to `text`.\n */\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\n/**\n * 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.\n */\n\ninput[type=\"search\"] {\n  -webkit-appearance: textfield; /* 1 */\n  box-sizing: content-box; /* 2 */\n}\n\n/**\n * Remove inner padding and search cancel button in Safari and Chrome on OS X.\n * Safari (but not Chrome) clips the cancel button when the search input has\n * padding (and `textfield` appearance).\n */\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n/**\n * Define consistent border, margin, and padding.\n */\n\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\n\n/**\n * 1. Correct `color` not being inherited in IE 8/9/10/11.\n * 2. Remove padding so people aren't caught out if they zero out fieldsets.\n */\n\nlegend {\n  border: 0; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Remove default vertical scrollbar in IE 8/9/10/11.\n */\n\ntextarea {\n  overflow: auto;\n}\n\n/**\n * Don't inherit the `font-weight` (applied by a rule above).\n * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n */\n\noptgroup {\n  font-weight: bold;\n}\n\n/* Tables\n   ========================================================================== */\n\n/**\n * Remove most spacing between table cells.\n */\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\ntd,\nth {\n  padding: 0;\n}\n</style>\n<style id=\"style-init-screen\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/init-screen.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n@-webkit-keyframes init-loading-spin {\n\t0%   { -webkit-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); }\n}\n\n@-o-keyframes init-loading-spin {\n\t0%   { -o-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -o-transform: rotate(360deg); transform: rotate(360deg); }\n}\n\n@keyframes init-loading-spin {\n\t0%   { -webkit-transform: rotate(0deg); -o-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -webkit-transform: rotate(360deg); -o-transform: rotate(360deg); transform: rotate(360deg); }\n}\n#init-screen {\n\tdisplay: none;\n\tz-index: 500000;\n\tposition: fixed;\n\ttop: 0px;\n\tleft: 0px;\n\theight: 100%;\n\twidth: 100%;\n\tfont: 28px/1 Helmet, Freesans, sans-serif;\n\tfont-weight: bold;\n\tcolor: #eee;\n\tbackground-color: #111;\n\ttext-align: center;\n}\n#init-screen > div {\n\tdisplay: none;\n\tposition: relative;\n\tmargin: 0 auto;\n\tmax-width: 1136px;\n\ttop: 25%;\n}\nhtml[data-init=\"no-js\"] #init-screen, html[data-init=\"lacking\"] #init-screen, html[data-init=\"loading\"] #init-screen {\n\tdisplay: block;\n}\nhtml[data-init=\"no-js\"] #init-no-js, html[data-init=\"lacking\"] #init-lacking {\n\tdisplay: block;\n\tpadding: 0 1em;\n}\nhtml[data-init=\"no-js\"] #init-no-js {\n\tcolor: red;\n}\nhtml[data-init=\"loading\"] #init-loading {\n\tdisplay: block;\n\tborder: 24px solid transparent;\n\tborder-radius: 50%;\n\tborder-top-color: #7f7f7f;\n\tborder-bottom-color: #7f7f7f;\n\twidth: 100px;\n\theight: 100px;\n\t-webkit-animation: init-loading-spin 2s linear infinite;\n\t     -o-animation: init-loading-spin 2s linear infinite;\n\t        animation: init-loading-spin 2s linear infinite;\n}\nhtml[data-init=\"loading\"] #init-loading > div {\n\ttext-indent: 9999em;\n\toverflow: hidden;\n\twhite-space: nowrap;\n}\nhtml[data-init=\"loading\"] #ui-bar, html[data-init=\"loading\"] #passages {\n\tdisplay: none;\n}\n</style>\n<style id=\"style-font\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/font.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n@font-face {\n\t/*\n\t\ttme-fa-icons (2020-03-27)\n\n\t\t`tme-fa-icons` is a subset of the Font Awesome font v4.7.0 by Dave Gandy (http://fontawesome.com)\n\t\tand is licensed under the SIL OFL 1.1 (http://scripts.sil.org/OFL).\n\t*/\n\tfont-family: \"tme-fa-icons\";\n\tsrc: url('data:application/octet-stream;base64,d09GRgABAAAAADLAAA8AAAAAWHgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABWAAAADsAAABUIIslek9TLzIAAAGUAAAAQwAAAFY+IEkIY21hcAAAAdgAAAG8AAAF3rob9jFjdnQgAAADlAAAABMAAAAgBtX/BGZwZ20AAAOoAAAFkAAAC3CKkZBZZ2FzcAAACTgAAAAIAAAACAAAABBnbHlmAAAJQAAAI6gAADv+gJOpzGhlYWQAACzoAAAAMwAAADYY1IZaaGhlYQAALRwAAAAgAAAAJAfCBClobXR4AAAtPAAAAJEAAAFMBfb/0WxvY2EAAC3QAAAAqAAAAKhjiHI5bWF4cAAALngAAAAgAAAAIAFjDA9uYW1lAAAumAAAAY0AAAL94+zEpHBvc3QAADAoAAACHAAAA11cG/YjcHJlcAAAMkQAAAB6AAAAhuVBK7x4nGNgZGBg4GIwYLBjYHJx8wlh4MtJLMljkGJgYYAAkDwymzEnMz2RgQPGA8qxgGkOIGaDiAIAJjsFSAB4nGNgZNZgnMDAysDAVMW0h4GBoQdCMz5gMGRkAooysDIzYAUBaa4pDA4vGF4EMgf9z2KIYg5imAYUZgTJAQDSIQumAHic7dTVbltRAETR7dpNCikzQ8rMzMxt/M39mHnsU1/TfZz5jFpaV7pXJunMDLAZmOqaZjD5y4Tx+uPTyeL5lG2L5zN+L94zG8+ztr7ulXH1fra4bvK9M79xiWW2sNXPbWeFHexkF7vZw172sZ8DHOQQhznCUY5xnBOc5BSnOcNZVjnHeS5wkUtc5gpX/f3r3OAmt7jNHe5yj/s84CGPeMwTnvKM57zgJa94zRve8o73fOAjn/jMF77yje/84Ce/WGPun1zi/2tlXKbp3Xyc44bFyZanSWokJDXOOjXSk/LUSXn+pEwCKTNBaqQqZU5IjX+XMjukTBEp80TKZJEyY6RMGylzR8oEkjKLpEwlKfNJyqSSMrOkTC8pc0zKRJMy26RMOSnzTsrkk7IDpGwDKXtByoaQsiukbA0p+0PKJpGyU6RsFyl7RmosQcrukbKFpOwjKZtJyo6Ssq2k7C0pG0zKLpOy1aTsNymbTsrOk7L9pNwBUi4CKbeBlCtByr0g5XKQckNIuSak3BVSLgwpt4aUq0PK/SHlEpFyk0i5TqTcKVIuFim3i5QrRso9I+WykXLjXOYNzP8BuAPUwHicY2BAAxIQyBz0PwuEARJsA90AeJytVml300YUHXlJnIQsJQstamHExGmwRiZswYAJQbJjIF2crZWgixQ76b7xid/gX/Nk2nPoN35a7xsvJJC053Cak6N3583VzNtlElqS2AvrkZSbL8XU1iaN7DwJ6YZNy1F8KDt7IWWKyd8FURCtltq3HYdERCJQta6wRBD7HlmaZHzoUUbLtqRXTcotPekuW+NBvVXffho6yrE7oaRmM3RoPbIlVRhVokimPVLSpmWo+itJK7y/wsxXzVDCiE4iabwZxtBI3htntMpoNbbjKIpsstwoUiSa4UEUeZTVEufkigkMygfNkPLKpxHlw/yIrNijnFawS7bT/L4vead3OT+xX29RtuRAH8iO7ODsdCVfhFtbYdy0k+0oVBF213dCbNnsVP9mj/KaRgO3KzK90IxgqXyFECs/ocz+IVktnE/5kkejWrKRE0HrZU7sSz6B1uOIKXHNGFnQ3dEJEdT9kjMM9pg+Hvzx3imWCxMCeBzLekclnAgTKWFzNEnaMHJgJWWLKqn1rpg45XVaxFvCfu3a0ZfOaONQd2I8Ww8dWzlRyfFoUqeZTJ3aSc2jKQ2ilHQmeMyvAyg/oklebWM1iZVH0zhmxoREIgIt3EtTQSw7saQpBM2jGb25G6a5di1apMkD9dyj9/TmVri501PaDvSzRn9Wp2I62AvT6WnkL/Fp2uUiRen66Rl+TOJB1gIykS02w5SDB2/9DtLL15YchdcG2O7t8yuofdZE8KQB+xvQHk/VKQlMhZhViFZAYq1rWZbJ1awWqcjUd0OaVr6s0wSKchwXx76Mcf1fMzOWmBK+34nTsyMuPXPtSwjTHHybdT2a16nFcgFxZnlOp1mW7+s0x/IDneZZntfpCEtbp6MsP9RpgeVHOh1jeUELmnTfwZCLMOQCDpAwhKUDQ1hegiEsFQxhuQhDWBZhCMslGMLyYxjCchmGsLysZdXUU0nj2plYBmxCYGKOHrnMReVqKrlUQrtoVGpDnhJulVQUz6p/ZaBePPKGObAWSJfIml8xzpWPRuX41hUtbxo7V8Cx6m8fjvY58VLWi4U/Bf/V1lQlvWLNw5Or8BuGnmwnqjapeHRNl89VPbr+X1RUWAv0G0iFWCjKsmxwZyKEjzqdhmqglUPMbMw8tOt1y5qfw/03MUIWUP34NxQaC9yDTllJWe3grNXX27LcO4NyOBMsSTE38/pW+CIjs9J+kVnKno98HnAFjEpl2GoDrRW82ScxD5neJM8EcVtRNkja2M4EiQ0c84B5850EJmHqqg3kTuGGDfgFYW7BeSdconqjLIfuRezzKKT8W6fiRPaoaIzAs9kbYa/vQspvcQwkNPmlfgxUFaGpGDUV0DRSbqgGX8bZum1Cxg70Iyp2w7Ks4sPHFveVkm0ZhHykiNWjo5/WXqJOqtx+ZhSX752+BcEgNTF/e990cZDKu1rJMkdtA1O3GpVT15pD41WH6uZR9b3j7BM5a5puuiceel/TqtvBxVwssPZtDtJSJhfU9WGFDaLLxaVQ6mU0Se+4BxgWGNDvUIqN/6v62HyeK1WF0XEk307Ut9HnYAz8D9h/R/UD0Pdj6HINLs/3mhOfbvThbJmuohfrp+g3MGutuVm6BtzQdAPiIUetjrjKDXynBnF6pLkc6SHgY90V4gHAJoDF4BPdtYzmUwCj+Yw5PsDnzGHQZA6DLeYw2GbOGsAOcxjsMofBHnMYfMGcdYAvmcMgZA6DiDkMnjAnAHjKHAZfMYfB18xh8A1z7gN8yxwGMXMYJMxhsK/p1jDMLV7QXaC2QVWgA1NPWNzD4lBTZcj+jheG/b1BzP7BIKb+qOn2kPoTLwz1Z4OY+otBTP1V050h9TdeGOrvBjH1D4OY+ky/GMtlBr+MfJcKB5RdbD7n74n3D9vFQLkAAQAB//8AD3icrXsLcFzlleZ//v+++nb37dfte/VotVrdrW5JltuKpO6WJVluPyXbsmOEbGRjO4KVjWPZlsM4QIU4IYGlgCE2yxqKIQkJg2GreKQCTCZb1CZkiswjzOwOmSTATNVWTZLdDUwSMrVDsomD23vOf69assFAqgbk+773P4//nPOdc/5mwNjFl8WjosbaWblmxiOmIlTGYXzb11M7Z2ohAMbZCcZ5iG9prZl4whfwGju05xtttitUdwXYEUgkbQtWga5lC+XBaqJI285qpb8dVEc8Gnm5L5QM/f58yAlB399a7dD0mWAmdAqaMvBmKPKX9TdDwSjod9yhx03FAPcvI6Gk2lV33XoXUtKgL8C6Wa0WSzXbVjhg6JoqIPShCK0FOvOuE48K1V4B1VUQAVevugmP7Fz2CmTzW5/8+ZGP/+Kp7h/8oI4MuOZ7M5B9IvujH2Wf+PnCAjzn8ZK6AieMKRcvXnxWWSWCzGARlPcqtqs21WZzEBFgYIVDAYWzVJIrXBlH+hXGlWNM00GAJmYZ8sKBzTJFVZVppijqDFMVdTIWLa0o5JrdaHusPZGIG1IjFhQGK2mAZEe56kJnR1bTY7ZT7eivFGODBTdma3pHtlCNDVbwmgMHx/aO4R8ffeet5/ZCG6TfuV03IaSJU3oIzKsGO9+5PV+BwU5xqnOQx1aO8fW71yvD9fPn55/fA22PmsaFvfSgwZ8wzPiFvZ2DUMnzJ2hHVDMmHucPsSRrq7UQo4DMAV/AW7CANw/Zru3NIx20bBEpXwukArlxxOPReibaG63/SyQyiftzcBy3k1HuOHgjEgFHnkYfh4VodDJC4138Ff8hv5PlWbrWmm2O6grNEgGNCWGnbFtRm1Z04gzQPPWvkqMWF4eWU8DB267Df+gNe84bBvfRpfNI5Ny5yAmHDh5/PPLuByMlekDS9DsRR73nWHetwBShSO5PqCBQONO4E2wGlSvYZG6gMzeQ09SWFZC0tWION3oOVVXGTbGM+hrAzQj0O25yoN8R8YzzRsaZdzLwhpsGPEm783hAJ9+kq286eDX5pn/VydDjvk7i8EuchU21JJ3DNOqFzeABmywPcNXxhu/wB+3whrqwVw7Cn1j8vPfdDH6O7PR3fDV/Cb85wua/waSit309grZJHHOhHEQ9CA7zTGVCUb0ZvXzc1lrRe5Af+4An0aSL9op0IU9y6vRFtAYGKy7KJGFbQrdg2dXqGAwWilld0zUy9xLqd6A/zeFuy7gzYFmBOwOhZ6NNhZakm8YTI7S1pyM1mM032V26qevXGlzZ8+TKvROlB/BBkO9ACDalB7OZuBnuC5tRcAItpalENNOfhajVH1A2a1HjbHZ4N4r54oWLz4qPoe4jrMo2sonapm5QRQBQ3XycKVxwRRxjQuVCnWc6mrzOZ5FvBiraOmia5FubYRpok8n0ioRTKOQMNbWiszxYWAFZrQ1sB+dDJTFYghzyiBN3oB857ndIAha4Se/+YGUtjAkXXUO2xPE2eoe3TWPeMOXmzNi+j9w1HghvVbSAmu4c6nFac6MgbzXFU2baDr1241+98TfHtU/9t7df+MzU4msmfPYj06Wbw8Gqohda0/FkSyiyvtPGG/FsMKq1pLqmPvndkye/+y+08eYIHEJZpFmJra2Nop/VWuKcCwPvgRhnGlOFps6iIdAEmFVAKh53jblZyBU6nAFdbfX03tGwioZ9oGnEyDSWTQCyFzhoR+s/jdjgWLmc3L2K21zEmXCsM5aDm4g9Ny5v0PZVb+dY9Rcd/sl5eTiPj0nTaeiU+BhhW2qbuzJcUy2Nc2gCrjBkxWCqZiArGgOuwSzjAlDb5L91XfpvfYbpij6ZRIUWYoVcLqC2+UqNLddsMrekY3GZztVl2uQjpl4xjedIM+Uybc/r5viShuHgcgXuwQtpuoMHz8utCe/s8S+Y/7xMaYu2DX1yDrez3lp3cyyKdop+HLcLi878Uh9SKOSlj73cOIUFRVKVKHhaSS9JP452RCcYoJ3w85bz8Ckp9VN4xeZj9atpH4FnPCV4OtiDNIVYCrWwsbauK81VxUlaQnA+riFBisoUsiU0LbQpASCmmRAwg1MNJoH19uQ6WpriUV1jIQjphA5QjosiTfiy1tF+kPJKMTFYpAu6lkx40odnTv7VjYtC/QtTJyGH9HmMnKamGrcaqmaagRsMUwR9WeLmwsQREvIRevSvYa8uVFXo9Sc0w5A8/Rp5+jcxhXLuYAOIx/pbY+ggFp0FV8lNoLNAEQvyDkwBZR9T1ZC6xR0qFgsybix3DJcR7iIGwCsCHHQM0nYKVSBXQZPnqG7KDZiqrn8K524gpN9ghAx42k4GsvF3nohnA0kbnglkC9mrl7h4Db2TommKcVE1QOPRd97K5WJxsKO5nIjHbHtx/og3kK8iWys1he/EkKlqCbFOB6iKQp5Q5Yp6DB0AsjmPvHEFSGsoFraPaVpI2zLc2lmudErjJ/eeQwbKPoRBZulcwhwXYc6i1SdiEpiCF+KrFOIrAzKaHdhQ79tw4MAGuJv4rt8sQQu80jloGnnDfNVJBa+vn1WjSg1d8NHrg44FbTgdJ5+T77yy/gDI5wY7633yTbI7+CdyMDyEL2paDd0BvZjyfIYXH2/H+aqjDfXUisgnk3rFYMePoyZBegWanQpM5hKdlUSU1JnoQH2iG1d90IYADi0JPV2/oxMEeB7apm+aBngFw/ObMjzHzv7dgzyOh48fHZnmO9c8Wv+2RAGwHiP20UNnzx46mvYxyaMixDpZX22lQqQgRDqG4kYcMo92cpypAOo0Ti+iSYXJRGc5l8wvQhPfqpE0SYa7nDwkeQyh26OOlbecqVumoCwJ8+mDm+9/5T4eOyOt+4wk8WjavYTIG+7nD5Li2cWv8zGkMYoz51q2u3Y1JQSwfcumSn9JUxW0CZIWQ5isqKCo8zoGFPybx/lyHD2w4AaCBw7Ap1HIxAaHyZlr1tXG1owMt7h5Ox5QmxF4Iv6vDhaQoTFAYADuYIlnLa7b7RwtiOBDtVK1dbyCMXXxn5azOIIKfLFKaQP9K3HKIMYEQosvhkIWH23TQ9wIpCq9M4WxycnJsQIUYrEJ/bPGuOZohfHVzdmMaAmHm418c7DU3xdoyYPebFktPJtpHu7fefjw4R0VHiNTa06ZUTPe09a1sdTUVNrYtbo3nth11VW7tBa1d/U1a1t71rdG2u1IJNkWDYdbUs0pnnFT+OloWzISsdsjqVpvy9prqrNjed41POfPx2+J7TIXaWP5Wgf5bvToBEvpppQYOXPOJoda4gTQE6TsNK8sAvUSSHBFygfnfM9wL+8aK/Bddv0tZ8SufyKZ7ml7s20iCWdsPpPu4YVaXuur/2M6WX8riReTE21vtPUAnn4iyTxdf0vJ+/QM0pwsUL4D5BmUBQEeXpaU4W6RtExzN1In7eT9qHPpIoUdqAzSrdyHIPo1JNRps1uioCWJyIm2U/JG8oO4aZMXozF8b4RupRd5JJv7Nn8ZeUyxjlrakhJHcwO2gHMUDgGLR0MmS0GrIoMRWos0K81LUnPZYgmkw6sM8HtCoQTaT9y0Wu3f/MZuCYfijhMPhUVQNdL2hY8kMroS/8UvEqqeSfC/xzPV07k3vsqyrL+2ykYnhJjEz45OLIdbu4ncrbrWhImzltU7oqqaXAEdMWiHxPsSdvuF70K6/xf6FejjL13YBvFVP+UXrkwnyelZjBcltoLypQIoEmsoiDUw4C2QFS/I/J6yx5ybWOOqaMad0kJlKo+ElAdLqvRTMqOsgucuM64j3hgHU1H1mIkQ084Oje3eXT1lZwL1nwaD0BZMNfFTcHpv+sf7v6LEo4oZMlRbFNqH9tb60nEN0UkQ0mYawZNpR878eFuD1lWsl/Jb9J5iMbPlDKnkh3raBmS66U1M9Jm5rKUmMel1dKLOcxrVSgf5dJqU4o0g0pJyTlV37x4bytpCATOG8VUT4+m9cPoURiakE34ZMes/wbB0Roun+2p7h9oLSlwzQqZq2eIr+xe2/Rhp5QF8hHn5Hh/FfM9ibs32UrNG+l22ZbrnJ8N+fERAcD6YCp6nuPc2Aq/vWXiMfzKaye/BDfzTLPwe33MT8ns4P/y0uiLBdyZw3qRvNvGZegjF6H+escXvreOnkD7zm7IkADTbJEkU4sdw1jmwzpTj42smHLB82ijenjfx9YsXkccR+B5+I1azGtQk+4maTpnLlsBL75E7O1IPea+mzfPmUwQt00FJoG+nPxN/zruZzZprTljyx2GpXiHdYWBZtcINeB+2xVP16/GT9euDwf00TbqgK5gK7QvCmfp/wPn15WDa3BcM1l/Hy8F9wZQ31nf4Q2IjjrXyG+BnzXnMmqXiTuB5CLa01gINjvb8mesSTwHuSAEtzm8anp+uvwbdprkfhUs0wCNIxH6TP1l/vf6aPDThK0TXI5I+tjj+SX/8wIcaPxWX4y+CqsCiEIiAIzhsKrgfh+6qv+4L4RETPl6/zqMKukki9AA96OseZb3Zk7UKVKxZKt65tpR1J9p1sTGgP5Z4ah+KEzl73R/xEfr+I8H5fchlN/Jr0n0c3fSGkrz+vbhd5m2ZWltThDeKUaKh3WTZXWauS+WomBdMkjGvOCRuT9YfcIZxk0x24/5cT3q8redxe8TpTsLn03b9LIaFo/I0eQ7uxtjQm6rffI4elnTcJfbwX/qRFyG+Vw+SaJdyFIpugk0WXCcnaZFo1323viNAWHZPvk1+ugfjTf2sbcPR5LDT442bhwPj6Z5z9qi9wr8B85Ji51yXb3tISxlpSUtaZEYnFX8ZbHI6C8vk4ll2h5/YdRQbM0CUbSmXHsd5rH5zWz7fBnc/5iA1NLANwyQZ2+5JjiYfQ4mle+BxJA1prT9g+770dv4zTz9RnTPp+JlY4DJKoroOucmyT4fnsGIeFC3H9EtmB+qnGyP6413tPvs4BhIwipskDKakeIg+KKTgbl92JBkkHn1J3c8t+9ia2vBKhMFkGBJtEjrGDIzKE1SeAgTJiDAVRYpKmSGwMlksJor5gUWgjKlXYS0gurS4neaYflXJnaWBUjDKNAVhkWoF1WhHz7uJ2PapE8NHJkulySPD62/qVmLapMq10a997JqvnphQarc8dO3UQ2smYr38pfOWszK6fTs+eBKfHy4j8t2uWNrWnbDx5CNfe+TkxrHVE/EEW4ynxM9H2FhtpAeE2tnGFUH1J4xXChxD5hACLNXbLgOA3WU353rI37Y44SipbwdxwED/mEC0rOmuIzmlGkw7SBzNxZ6NN3519+zXRhV1Uosp3TdtGD68s4eXJo8uzHVtjyXc85gC9MYmRh+euuaRk+vhAG43Tm3RLGW7Clp52Oesq3N7dKVjnW9KxCdWjyFvi/nUs+Ja5CnPxtn+2t4NnVwLrELw76JqDMz1MacMGJoR0I5RVsA1lR/DLEdonLJLQWnOMcSamKlrszLnWWZ3mzcVOjsrnYWynTfVNmQ6aQFxrWtL9SQtgjqsojbxf5lp+qquSF1rVGyk02qZZEEKRkPdlv9ff3LVQ6MTFMas8xSft3fNVbd+vqg1KaF5w7RwBsirUye24UVXDS3oIcj/nz+56mF6qQlUAQ++gGoNytcxFG7P98DWMXMoHIL/6l/Z7p1riv8ko2oiyiru129WsSrmUjO1XdtWc0Pr7miOoWOV9YUQ07WQPmsCisWYDge5puAUAI3NIk6EQACmaQ+BGRaAwOSemV1TH90+vnlDrZBNFOi/nEUlLL96lYx5VZLqB5zDQLFQzGm6KuUX89L6YqxRuaPsCwXYTlJE1EVJt9ycWTo8bereoW7Wv38ewfOzmgI/N42Kn53LatjTxUCv85zbEyg+Y5hTcDddq99M2ysc8/51lABfjZ++8KvSxvUlnpCj7U+mIG3vR8yhXSbXEbaB3cDmatdds4lrhi9Z8hskNo2hkI+RQHWN6fMIUwKGFZiNhDmCNq6BoR1gejCoTzNdD86woB6cPDh33YFr91w99dHJLePr1tp525NylKZkzJtthLplN+ADzhOxjpiN1trRPwb/vhKfqIcMg8Mr3DDqd38o4cM36y9KWa+Tsn7v4/ocj134Vcg2TZsf/ABFKH4tYwrtObZYYxoF3QiQC+PjATwUho5+W8MkQlOOqUDxnlMNjZpsfB8zjJCxZe2afKeTjXeuboqT2XcOlsACB6XROFhWch7AeNy/VsZfx4fO5Aj8EjTVRPjLdtrmTS1NX7Azce6kmjZnnHf+1iuBiG0duzsmQTiZPzfjEoTGAqZ7xqt/nmmai8gXOWb0/sG9z8vyyPNOZjKDf9DlRgmQR93keVlHOU/9RTkfH8W8ieTQzWpsc21DGRM0Xw4soAUWDEDPtMB0oS9I5qeXC0PhMySPyTWjuYFctn9JEgWLp6FSXdz71TeSgzuQBmnXVHPXGqWhIhXkF+H2lQXxVqiSO5OthN9CQQSazmBOhdycwSgoZRJvQ28Yz8SVltDiwd3PUxMLN9De1dWehinH5783RvA9xhpyoHgnWAfGvE3sqtqOFT25rGIoMB4GBa0NAaepg2KYyiwVijQqFKGtopEeUFFYgQCboj0jZ8cCk7U1Q2W3MBBLjMRi0SCKxO0od6gD6Muon6Q35JGLDZS9DEpfLNZTA4aqrmrD0rwHCAO8Cs/Ur4a3J0Lql9WU4RfBJiYySfg+cviqaczLvipt59LuhbjXflPdSuRLUUd/9VV422jRv6SF/NbehYrcQ1p2AZ6jd80L5+kSRwE3WV+OVGTs9GvnU6yLDbJsrZ2aE+iijskqPtuHgTAktgz0r+xtaUaslZRRH6FKlRJrBwO9bK+lef8YXipg7j8GSJjM+GRPmSApRv6n//T4VrH3qqbRaNxoqoxSNMfwD6MV18yPulftrX+xZ7gXeka7vMCPgf2aQ8+N4bPuaKz7lg2LIGjjTT3x4T4jvubPYKL+cFtPTxscwm0DA+yVNaMjbFNt/cE9k+sUpoxgas8Gu1qjhG7GqUu+oAFel8B2gTDcgt+54If2XXv1VVsmVvRkM4m4TnnrYCGLtt5foc4F2rWO/NrIbxENvBHUy0WJBYqEg8hbyklAxoATvupfHMCZ3wAHaASEAFz/Y7pUPh+ZumWK7z65G1KGftgMJro0NbIzrOvbm1sCuhL9tBGKtrof1aLaZkdRjS4zYhzSDTDVw4bldnrPGtubWgKGiH0adR1JuR9VI/qErSgB72HMk0emp2+anr6F7kfTydZ+zdKSO0EdDRuTqaip3xAIjapaLa1aWqg/kmqNQEiXzza3ZFbqId3euezR4Iiqbkj5j7ZEIeTX7X4n9vLvLmKL2mAXILVUp0WPoyLCVJVGQ+/yNlGhjP8PNLq4y9vNy9rPrn+eW36OaPmdX0nTF7EIpu9XPlvW1XMgOiHbSHIL1ji1nsbpBdbAyXtlTRwjSHuCqyJvkjfAVEiMe317oeLEURlNKa/CI7tfVLxLp5qb4tFwUFVYJ3R6/STHqy1Xi1R9RLvvd6lSPIba14rZoo6zwa3w/7L18OGzRwC+N7B52+HD2zYPfA8OP3iIH9kyjkd4Fdwj9x85skUPzfXhQd9cSN96mB+97yjgoYUXvZ7kxYu/UW7mL7Eo+rwKK9byTKWsSWWz6N8VBaZxB5ShgDJZHerscm0J6L1at2fNGPH4CqQNZ+gAGTeaPZVNBB52IJ7nt/uI3N/B0707Do+8vmEH37rpdTLX8eEDd47Xr564Y3aIj+67azM8Q4dwYHjpHbJoOu1/8OkH++lk4s59Y2Lo+tsevG1ukA/N3uHb9f9TbkFebNRET61I/GEuOEtdCkxKcdfISpPptmSn01kdVNF4Y4NjHF1rWnh0cxWZKImsJdKcKPPIkZR5RIoYkcJ7dh665dDOHqV/4jgc2ILXkYz77zgwypGsH1zKst/L+ir6nJVsPdtR2zaC4aQTZC9CR4p0jigDQ6gmexJcUeeXdbS0xY7WslzDdpPF8uryAPX0L+tqoVNFD5QrFi7rbKGXwYnkJGCpwra4XMZe1th6JZcOCL0VgV445HepqL+l5jVdKMHP1VeH89a/WtYaK2/9Z/g4noyFYduzjf6WpSS0FIKDRovrC4aaQ9ZArQ9b1r/K58P0Yhi/4Msl4WPhFbUuzCTBb1OitsjmCVsAn+Qs3eokTJ1FeEQlI1nGXNlfnbS8tcc/sYz4wU8vsbd+lr/UII5u7mncOYBJ+WKc+5jsETe/L03AXCfmN4IlTVnCOYiVSxyWr5h45up7d/Lpu568c7ey4zRcu6yjzk9P3Xvu3im5qb9yaf98ab2AwZIsy0Zrq6nXxkG22zi121ScGiC71IoiZwcZqlAmzUCmvaU5GgkkzaQfoNCjlKimWnxvGhtR5b4r0roYFX59BZLFsvVB5NMRIVAGQ65bJoBsRuaFbLJM/0n3nZCLlZaWYKj+efWy88WezKv+yiG5dKnN23mX2uUJbi5bY+Rc4XgxBrHXGnlYb637gwLPEuXVBmD1ViiIyzgRfl5f9NddvfoB9NDxw0clWD9KV0FbdhMMjzfc+H7uJXEG8fo6Ns4O1q5fU+KCCq16PhXG3JuJcczFw6GwEaLSBXkQwNwF4DgLs1AgHDqA2FToAXEgCDpj+jTudDaDgUmnGsaG9bWx1UOVctJGzBlDf2HJWgZyh1HHkeV53RK5WC6Gc8fr45AzKSByxwlWHShTsxydSgfVLhALUZsXOiS8w0TlVOdJ006bC4ZayA43j7cN9WCqeCgYDTvGJzKnKG0Jn7ou6KSC18Frs8FUk2Jch1frv65/kWLdMMbf2fWfDKac4HFdaYpb8HY9ZDXZhnEylEgHP7t2L6YMcO46M22b111HA113zoFBDJQUpy/WLx6B36K+MxQdmlHBKerm0BIJKqUu68GgoLY0VSpexdChJiDC1WpC9qwK1cQYpS7U0BW0JAzeMrX6P+hRI2Dy4z/hqqmb4gS3jG8GLT77P1Ue5E4wfOFTFoioAS8NYVYZhv9umJapaPV6hct6wHdkHiowcqVYnvUivt5Qa+3vK/X2dBXy2Uy6pclBE4pR4XkwxWHTtq93vH+tv0l2U6pFvbNRePWrv51uBFbBWmgHbw/upXv+0LnRc1AxL/RjLrVgmvx/yP0Fq1KJxarV2A+PHct2HDvWwbvxJIYX60/THfzHrcdGH7shQm/iC2l6E/fXRumtaPU/ybeyx+p34UkVL0LJv9PAUHOomzL1w8q9uZaYoV3SIOoujHBKKii60eKMxhJHXUMgTQW0InVqqErq22AbYN6BHOMkFCMtlpWLDDc/0NM23tYLZ1uGMX5ZrWfPtkQj+chQ61lZiH+gZSiai0Sbz4JhDbeswXd2PSVr8E/twqtr8KXdu690Q2KpI6jHMMuhBjdRdbG9iQslEae6YVhDV7gBdOiHgK4iKtSERkv4yOpAP8ZMpimmNqtSRuUFG50FDD2AeaYRNrasGS0P2LTwuGDncpRJNtZ5Fpev85SVhMY6T3ewBJrtjAFIs8XZi95eSXOXLJkW75wKaXmE7afkst1TsjBDJxP3v3I//kG6Z9R+ce7WnfcfrvHRo6fPnT46CpteTMJZ7yXKMb2XTlHieMpspgUYLz+k3UsJV/LFTWNH7vvT08eHlfWHHtx+69yLSbZMRhHWhDn2SG0oYCC3qE/B0qAKuZqPg+b5XkErlwWmYkKlMkNY2eLmUAqF3OJinmKjrPIhuK1/W/IJ6z8kh5K1D2aK+/UTWqOzkz1fC4xVOgKKKqgjZqKV9nhTGGOgUGnZjiK4Mq8jJFKOMwJ0UxSLdlO/Ymvrtq8H3/UG+nBNcG0e7Vh79xt/yOf37KklDMPYaeyc3LZ1y8hwT671KoP8BApooL9agOqYUm2FATeRptTcdeQGxexmC3pWyw2u5ZSr4l9xsLCKW+DaaeqxVskXZql+XdTggY9NDrcHk331MoTzqZSj3fGlCe3GxJQT6IsGjeBkQOGQO53v+VKSb9E1EVMQ5vKs2/R7axiimWAmiVCh4/MZ1eYrecvvMWx9oa71KppmNkVhBs6G6m+veHkw8amOFi0QFY4pTI7RrikRxSd1jgBaCeytDEHmYSsUN/HTEEyqQVQ6ppY4937ER/nPmMXaWK6W8TvQy1cj+s28wcIlS70LHqQsSoS5rB18abP70ubwv0VMqrRhJALnb2SJXZ76vg7pAPc9++oF2+s8XzLyZUMt/3ajhy35encPGy4n+lIy4Xvvou1JERMJFmTa8zqHldSwlaBa9k6VC63heDzM/3cYttfndDMiKlbIwCN7eV2F8FS61toUNZhCzHltUoKChwg/yah6WVnr8jIXJer+ultoizj14CWn/GfvvEU5uIjTdtnx8nw86K1TlzWF5QsXBhYXGlw+3rLk/5IB/G8+gzZuYUagPa8ByoUaWfiRIuA35I4CrJOMVariLtOCaKD+Ryq3gvWTwSDci1AAfVtQi7zzsmWE4F5Vq/+RPKDe8714vX5SVSVGuXjxa2K/iCyN42qyOkbLkXwt6FIjmt5sRsHC11VB2yANZQl1HL+GWjFC9Em4Vx7Q2oKTeB2+oKkeL3xEkBU015zWlri4VEBrpICIlwZ7Eso2mgSVKs8GLeJN5YsLnmn7Lh7/45KS6ncSg5I/Por8NcaWi7UW27Te2JeyTGPqPg3VS9j2CzJyeznjn1qaGXCrpsq8ro655n7+1zi3WwkBRkGuRl5e3eMyi6L0TvDJcnYwTnM14fWG5Xyh5nXVLya56BmNJRUi25oYoiGRJBGXdaO+Rb1Y9R861mlZYzodsf21K8/wZ1mC8I75Hr9viTsF+fsW5BzxTSO1IFQNz6DJvnC/lPv9L6Ab4KcvfJU6gC94y9NfMP31s7i5XY5RIn6LJqKRxjAKDuOVppiQA65ycUhaEvVeQya8dVuF6uCYKClVFADVGd5FyGt9RTWAAgg50ahiNFm2YkcCarHv3QTW/6Jna0TY0VA0FEpnMkbciKJ0RGSrrMN/XzzKfy7p3saOsq21cUl7FVQ2Dboqxg8D38S4hnxooL2bGRU1qurqAtP1Q1M7xzd3Sd4MKlx9aN7cxtWq/1OQAi25ohrK0s0ilVHwbgmKVNGWD1T/IMmcmd2u68h5MhPsLpW6Mf7ZEUPfceC+0zfhdXy9uTm5cQffujnZrMQFzmZdv+n0HyDOnl33Z4RjOcFoIL338N50IIpBxBEd9+2+7fV+vGGHQ5Y18NCTDw1EwkITYRu/JwZe9fPMI+IfxFUsyjbSqvKhAcwt168pdedsTBbTzZxTnRzRxQyV/if8uggP8y2VcpqWw7iyTmgJOy3GuEu5oK35P5xC0L6GZFag308hopD9/6r3KyoE7rKG5Tqi3D9z8s6TM/3+7mEeeCxiPDanxdWDjxmRxwKIeebmVFVePajGtTl5VaWLcGDdLdMVpbTvxD0n9pWUyvQtew1RfioQFOU/1vU/Lotg4KmyMEz9nnuM2OINTVu8ETPuuUeXPuNZUcFYEmd9rFRbYSxfVUjLiN9dFerqyvd2yKWFBEEB548Fup3m1PWnBQHUERnjyKYur0O1v1pBfvl30u2Hnj4EwydOw/CBOyd23vd4+YefpuUbvHb84elmO9HXD1P3Tq1f48YM5VZ17msH5/d1fPtmWQndeOwTd1EnZNeXbtwsoBRbcbJ29T3T0GbGDO+3J95aen6KxViWDVCHL8i5wsPAxPLfE1FDb55RmQnmCYgrEoijOyX+6KeDoE66Tt5ONjkSgheKBA9LqL6qpqchU0E7QaSYtJ3+irSVimrrmpLJU3ej0gsK6vTRXbdlEXtnb9u17Z9B+Un9m9Hg5rmoE93YF4zCPwZ31H9b/6f6b3cEgzvAgAIYO4IwfMe64Q03nOX3fXzD8Lo7brzrLtiCz85tCkajwb6N0b9LJD738MOfSxTs2x7mj3yGsEgjzzBYB9Xw2hGCYAZOzYWG2uR6nFlvxlJeEZfO732ziNsX84be4ffMGz7/gRmQb1dyTX8Q/dtArU8Hb8Wybmgod53NBlQOilxbg9mPCIstK3sTAzE7O5BMJuTKkvJgwfulBskXM0CBMymXLQrpkSoDMVmJ6aA2QjGG4SJkRk38g5sd61dtYGoQ4St+jHY+U23r4aVWOEjtseoMnDgvfwCEm2+hp6r/X91AK4zYkU3HMVEaxnR3qBfqPzn+/wHPnsOreJxjYGRgYABi1vIsoXh+m68M3MwvgCIMt5YoxkDp2P9f/2exVDAHAbkcDEwgUQAz1Qu/AHicY2BkYGAO+p/FwMBS9v/r/68sFQxAERQQDACh8QbyeJxdT0sVwzAMy49AkAxAkbT3UQiAITGAISmAYQiA9th4ttUs7Q568UeSlVidiwSkB3PUPg+ESd6ZD/+8v7HyrtzwghY89ZB6BcyrYqc6RZhw48YhaA1Wc/v1PQtdeXJ/HppUmFM597nvBVK7D+Z+E8/uQZLBgDyaz3Llvxx02S3c/Hv813JrznryZP4F+6lSfQAAAAAAAAAAUAC2ATABaAGyAfoCJAKwAzYDmgQSBFwExgUyBbQF/AZOBvwHRAe2B/YISgigCPIJGglCCWQJignACgAKQAp2CroLAAtGC4oL8gxcDPINng5iDuYPag/6EF4RIBGGEeQSShKYEyQTbhOyFAoUYhS+FVoVphYoFooXHBeGGFoYnhjGGOwZChlOGXgZrBneGhwaWhqgGtIbLhvyHHQc2B1QHZ4d/wABAAAAUwBtAAYAAAAAAAIAIAAwAHMAAAB2C3AAAAAAeJx1kN9q2zAUh39q0441YxcbjN3tXJWWEcc1lEGvWkLbXZeSu8JUV/6T2VKQlY48w95ifYa9zt6jd/vFESUUYiP5O5/O8ZEE4AP+QWH9nHKsWeEdozXv4A0uIu/Sf488IN9G3sMQPyLv0/+MfICv+BV5iI/4wz+owVtGM/yNrPBZfYm8g/fqW+Rd+svIA/Jd5D18UovI+/S/Ix9gqp4iD3GoniduvvR1WQU5mhxLlmap3C/FUdVWN6IXoXK+k3MpnA2maVySuza0ZlToUZ07292YctFov6k2eWp8VzsrJ0m6qa+NNV4H87Dq1j2WWQiFFN61chX7yNy7mclDUoUwPxuPN/tjAoc5lvCoUaJCgOCI9pjfDGk/BPfMEGaus2pYaDQ0GgtWVP1Kx/ico2BkaQ0zGnKCnHNL09KNuK451721rLqhLfmfht5vzdrmp7Sr3nUfC07YL92afU1r+wrd7/Dh5WwdHrmLjDawanUK3+9acPXqPML7Wq3NaHL6pL+1QHuGMd8t5/8PvPGO3QAAAHicbZLnlpswEIV9DRiwvZtseu89Ib333vvmBWRZYMVC0pHEEufpg8BO/kTncOfTaLgMOtPr97o17P1/baKPACEiDBAjQYohRhhjDevYhu3YwA7sxC7sxh7sxT7sxwEcxCEcxhEcxTEcxwmcxCmcxhmcxTmcxwVcxCVkuIwruIpruI4buIlbuI07uIt7uI8HeIhHeIwneIpneI4XeIlXeI03eIt3eI8P+IhP+Iwv+Ipv+I5N/OiF1hEz9JKxUrtFrDl1lWF9NR9QIikToRaVjUouKxvOmNBjLxnlhgo2DbnM1djLKrNGnGPScSUzItzGv93yPP2bSQSX84z9cqFQdJ56yZRmMhW8mLlJJSaBI0XYPDaZKDUviZmvr6DrNjJMi0WcK1MTM02mqpbZlJtEsNx5SI238jSodJtoS7qv+BpPw67IY9xU+dg5TXjROTWwdGrIOzWhT+uA0jolxqjaZrSOnCF2Nmq16651EYpMm1fakAul9SJQeR5QVYQlk1VkZ8SwoVNFIVjWnKQrlBGdMToftdoZjrs77DajqXKrS02YEFxbbtdWkG0x44JJVUS5aBqKSlJwmhDrmOF2Hv9Wqsy4TNqoKhfmSrrQKuNSL5nvPG6p0s0AkEWkSWVZMy1Kx3ljk03qLuZ14lTmB8gNGmByGrGfjLrhlhJV2f7SaIneNF1ypQNbybBUSgZswQaWEUNngeay1/sD4l/60HicY/DewXAiKGIjI2Nf5AbGnRwMHAzJBRsZWJ02MTAyaIEYm7mYGDkgLD4GMIvNaRfTAaA0J5DN7rSLwQHCZmZw2ajC2BEYscGhI2Ijc4rLRjUQbxdHAwMji0NHckgESEkkEGzmYWLk0drB+L91A0vvRiYGFwAMdiP0AAA=') format('woff');\n}\n</style>\n<style id=\"style-core\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\nhtml {\n\t/*\n\t\tWe define the base font size and line height here as they affect the layout\n\t\tof the base page elements (i.e. `#ui-bar`, `#ui-dialog`, and `#story`).\n\t*/\n\tfont: 16px/1 Helmet, Freesans, sans-serif;\n}\n\n/* Story data styling. */\n#store-area, tw-storydata {\n\tdisplay: none !important;\n\tz-index: 0;\n}\n\n/* Special no transition styling. */\n.no-transition {\n\t-webkit-transition: none !important;\n\t-o-transition: none !important;\n\ttransition: none !important;\n}\n\n\n/*\n\tFullscreen appearance styles.\n*/\n*:-webkit-full-screen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\n*:-ms-fullscreen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\n*:fullscreen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\nbody::-ms-backdrop { /* Prevent IE 11 from hiding the `body` element's background. */\n\tbackground: none;\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n*:focus {\n\toutline: thin dotted;\n}\n*:disabled {\n\tcursor: not-allowed !important;\n}\nbody {\n\tcolor: #eee;\n\tbackground-color: #111;\n\toverflow: auto;\n}\na {\n\tcursor: pointer;\n\tcolor: #68d;\n\ttext-decoration: none;\n\t-webkit-transition-duration: 200ms;\n\t     -o-transition-duration: 200ms;\n\t        transition-duration: 200ms;\n}\na:hover {\n\tcolor: #8af;\n\ttext-decoration: underline;\n}\na.link-broken {\n\tcolor: #c22;\n}\na.link-broken:hover {\n\tcolor: #e44;\n}\na[disabled], span.link-disabled {\n\tcolor: #aaa;\n\tcursor: not-allowed !important;\n\t/*\n\t\tNOTE: Do not use `pointer-events` here as it disables\n\t\tthe display of a cursor in some browsers.\n\n\t\tpointer-events: none;\n\t*/\n\ttext-decoration: none;\n}\narea {\n\tcursor: pointer;\n}\nbutton {\n\tcursor: pointer;\n\tcolor: #eee;\n\tbackground-color: #35a;\n\tborder: 1px solid #57c;\n\tline-height: normal;\n\tpadding: 0.4em;\n\t-webkit-transition-duration: 200ms;\n\t     -o-transition-duration: 200ms;\n\t        transition-duration: 200ms;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\nbutton:hover {\n\tbackground-color: #57c;\n\tborder-color: #79e;\n}\nbutton:disabled {\n\tbackground-color: #444;\n\tborder: 1px solid #666;\n}\ninput, select, textarea {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tpadding: 0.4em;\n}\nselect {\n\tpadding: 0.34em 0.4em;\n}\ninput[type=\"text\"] {\n\tmin-width: 18em;\n}\ntextarea {\n\tmin-width: 30em;\n\tresize: vertical;\n}\ninput[type=\"checkbox\"], input[type=\"file\"], input[type=\"radio\"], select {\n\tcursor: pointer;\n}\n/* BEGIN: input[type=\"range\"] */\ninput[type=\"range\"] {\n\t-webkit-appearance: none;\n\tmin-height: 1.2em;\n}\ninput[type=\"range\"]:focus {\n\toutline: none;\n}\ninput[type=\"range\"]::-webkit-slider-runnable-track {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: 100%;\n}\ninput[type=\"range\"]::-webkit-slider-thumb {\n\t-webkit-appearance: none;\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 18px;\n\t/*\n\t\tNOTE: Ideally, `margin-top` should be `0` for Edge/Spartan (ca. v17), but\n\t\treal WebKit/Blink-based browsers need it.  Since there's more of them and\n\t\tEdge is co-opting the prefix anyway, we cater to them.  Edge will simply\n\t\thave to look ever so slightly off.\n\t*/\n\tmargin-top: -5px;\n\twidth: 33px;\n}\ninput[type=\"range\"]:focus::-webkit-slider-runnable-track {\n\tbackground: #222;\n}\ninput[type=\"range\"]::-moz-range-track {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: 100%;\n}\ninput[type=\"range\"]::-moz-range-thumb {\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 18px;\n\twidth: 33px;\n}\ninput[type=\"range\"]::-ms-track {\n\tbackground: transparent;\n\tborder-color: transparent;\n\tcolor: transparent;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: calc(100% - 1px);\n}\ninput[type=\"range\"]::-ms-fill-lower {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n}\ninput[type=\"range\"]::-ms-fill-upper {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n}\ninput[type=\"range\"]::-ms-thumb {\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 16px;\n\twidth: 33px;\n}\n/* END: input[type=\"range\"] */\ninput:not(:disabled):focus, select:not(:disabled):focus, textarea:not(:disabled):focus,\ninput:not(:disabled):hover, select:not(:disabled):hover, textarea:not(:disabled):hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\nhr {\n\tdisplay: block;\n\theight: 1px;\n\tborder: none;\n\tborder-top: 1px solid #eee;\n\tmargin: 1em 0;\n\tpadding: 0;\n}\naudio, canvas, progress, video {\n\tmax-width: 100%;\n\tvertical-align: middle;\n}\n\n.error-view {\n\tbackground-color: #511;\n\tborder-left: 0.5em solid #c22;\n\tdisplay: inline-block;\n\tmargin: 0.1em;\n\tmax-width: 100%;\n\tpadding: 0 0.25em;\n\tposition: relative;\n}\n.error-view > .error-toggle {\n\tbackground-color: transparent;\n\tborder: none;\n\tline-height: inherit;\n\tleft: 0;\n\tpadding: 0;\n\tposition: absolute;\n\ttop: 0;\n\twidth: 1.75em;\n}\n.error-view > .error {\n\tdisplay: inline-block;\n\tmargin-left: 0.25em;\n}\n.error-view > .error-toggle + .error {\n\tmargin-left: 1.5em;\n}\n.error-view > .error-source[hidden] {\n\tdisplay: none;\n}\n.error-view > .error-source:not([hidden]) {\n\tbackground-color: rgba(0, 0, 0, 0.2);\n\tdisplay: block;\n\tmargin: 0 0 0.25em;\n\toverflow-x: auto;\n\tpadding: 0.25em;\n}\n\n.highlight, .marked {\n\tcolor: yellow;\n\tfont-weight: bold;\n\tfont-style: italic;\n}\n.nobr {\n\twhite-space: nowrap;\n}\n\n[data-icon]:before,\n[data-icon-before]:before,\n[data-icon-after]:after,\n.error-view > .error-toggle:before,\n.error-view > .error:before,\na.link-external:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n[data-icon]:before {\n\tcontent: attr(data-icon);\n}\n[data-icon-before]:before {\n\tcontent: attr(data-icon-before) \"\\00a0\";\n}\n[data-icon-after]:after {\n\tcontent: \"\\00a0\" attr(data-icon-after);\n}\n.error-view > .error-toggle:before {\n\tcontent: \"\\e81a\";\n}\n.error-view > .error-toggle.enabled:before {\n\tcontent: \"\\e818\";\n}\n.error-view > .error:before {\n\tcontent: \"\\e80d\\00a0\\00a0\";\n}\na.link-external:after {\n\tcontent: \"\\00a0\\e80e\";\n}\n</style>\n<style id=\"style-core-display\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-display.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\n#story {\n\tz-index: 10;\n\tmargin: 2.5em;\n}\n@media screen and (max-width: 1136px) {\n\t#story {\n\t\tmargin-right: 1.5em;\n\t}\n}\n#passages {\n\tmax-width: 54em;\n\tmargin: 0 auto;\n}\n</style>\n<style id=\"style-core-passage\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-passage.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault appearance styles.\n*/\n.passage {\n\tline-height: 1.75;\n\ttext-align: left;\n\t-webkit-transition: opacity 400ms ease-in;\n\t-o-transition: opacity 400ms ease-in;\n\ttransition: opacity 400ms ease-in;\n}\n.passage-in {\n\topacity: 0;\n}\n.passage ul, .passage ol {\n\tmargin-left: 0.5em;\n\tpadding-left: 1.5em;\n}\n.passage table {\n\tmargin: 1em 0;\n\tborder-collapse: collapse;\n\tfont-size: 100%;\n}\n.passage tr, .passage th, .passage td, .passage caption {\n\tpadding: 3px;\n}\n</style>\n<style id=\"style-core-macro\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-macro.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault appearance styles.\n*/\n.macro-linkappend-insert,\n.macro-linkprepend-insert,\n.macro-linkreplace-insert,\n.macro-append-insert,\n.macro-prepend-insert,\n.macro-replace-insert,\n.macro-repeat-insert,\n.macro-timed-insert {\n\t-webkit-transition: opacity 400ms ease-in;\n\t-o-transition: opacity 400ms ease-in;\n\ttransition: opacity 400ms ease-in;\n}\n.macro-linkappend-in,\n.macro-linkprepend-in,\n.macro-linkreplace-in,\n.macro-append-in,\n.macro-prepend-in,\n.macro-replace-in,\n.macro-repeat-in,\n.macro-timed-in {\n\topacity: 0;\n}\n</style>\n<style id=\"style-ui-dialog\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-dialog.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tPatches to the core styles.\n*/\nhtml[data-dialog] body {\n\toverflow: hidden;\n}\n\n\n/*\n\tDefault structural styles.\n*/\n#ui-overlay.open {\n\tvisibility: visible;\n\t-webkit-transition: opacity 200ms ease-in;\n\t-o-transition: opacity 200ms ease-in;\n\ttransition: opacity 200ms ease-in;\n}\n#ui-overlay:not(.open) {\n\t-webkit-transition: visibility 200ms step-end, opacity 200ms ease-in;\n\t-o-transition: visibility 200ms step-end, opacity 200ms ease-in;\n\ttransition: visibility 200ms step-end, opacity 200ms ease-in;\n}\n#ui-overlay {\n\tvisibility: hidden;\n\topacity: 0;\n\tz-index: 100000;\n\tposition: fixed;\n\t/*\n\ttop: -50vh;\n\tleft: -50vw;\n\theight: 200vh;\n\twidth: 200vw;\n\t*/\n\ttop: -50%;\n\tleft: -50%;\n\theight: 200%;\n\twidth: 200%;\n}\n#ui-dialog.open {\n\tdisplay: block;\n\t-webkit-transition: opacity 200ms ease-in;\n\t-o-transition: opacity 200ms ease-in;\n\ttransition: opacity 200ms ease-in;\n}\n/*\n\tWe do not animate `#ui-dialog:not(.open)` for various reasons.  Chief among\n\tthem, however, is so that the dialog isn't in the middle of its animation\n\twhen other page updates happen.\n\n\te.g. The restoration of `overflow` on `body` would cause the still animating\n\t     dialog to jump around a little if a scrollbar were to pop in.\n\n\t     Any dialog action which performs a task which has its own animations\n\t     (e.g. passage display) or causes the page to reload in addition to\n\t     closing the dialog could cause display shenanigans.\n*/\n#ui-dialog {\n\tdisplay: none;\n\topacity: 0;\n\tz-index: 100100;\n\tposition: fixed;\n\ttop: 50px;\n\tmargin: 0;\n\tpadding: 0;\n}\n#ui-dialog > * {\n\t-webkit-box-sizing: border-box;\n\t        box-sizing: border-box;\n}\n#ui-dialog-titlebar {\n\tposition: relative;\n}\n#ui-dialog-close {\n\tdisplay: block;\n\tposition: absolute;\n\tright: 0;\n\ttop: 0;\n\twhite-space: nowrap;\n}\n#ui-dialog-body {\n\toverflow: auto;\n\tmin-width: 280px;\n\theight: 92%; /* fallback for browsers without support for calc() */\n\theight: calc(100% - 2.1em); /* parent - title(2.1em) */\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n#ui-overlay {\n\tbackground-color: #000;\n}\n#ui-overlay.open {\n\topacity: 0.8;\n}\n#ui-dialog {\n\tmax-width: 66em;\n}\n#ui-dialog.open {\n\topacity: 1;\n}\n#ui-dialog-titlebar {\n\tbackground-color: #444;\n\tmin-height: 24px;\n}\n#ui-dialog-title {\n\tmargin: 0;\n\tpadding: 0.2em 3.5em 0.2em 0.5em;\n\tfont-size: 1.5em;\n\ttext-align: center;\n\ttext-transform: uppercase;\n}\n#ui-dialog-close {\n\tcursor: pointer;\n\tfont-size: 120%;\n\tmargin: 0;\n\tpadding: 0;\n\twidth: 3.6em;\n\theight: 92%;\n\tbackground-color: transparent;\n\tborder: 1px solid transparent;\n\t-webkit-transition-duration: 200ms;\n\t     -o-transition-duration: 200ms;\n\t        transition-duration: 200ms;\n}\n#ui-dialog-close:hover {\n\tbackground-color: #b44;\n\tborder-color: #d66;\n}\n#ui-dialog-body {\n\tbackground-color: #111;\n\tborder: 1px solid #444;\n\ttext-align: left;\n\tline-height: 1.5;\n\tpadding: 1em;\n}\n#ui-dialog-body > *:first-child {\n\tmargin-top: 0;\n}\n#ui-dialog-body hr {\n\tbackground-color: #444;\n}\n\n/* Default dialog button bar styling. */\n#ui-dialog-body ul.buttons {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n#ui-dialog-body ul.buttons li {\n\tdisplay: inline-block;\n\tmargin: 0;\n\tpadding: 0.4em 0.4em 0 0;\n}\n#ui-dialog-body ul.buttons > li + li > button {\n\tmargin-left: 1em;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-dialog-close {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-dialog-close {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n</style>\n<style id=\"style-ui\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\n/* Settings dialog styling. */\n#ui-dialog-body.settings [id|=\"setting-body\"] > div:first-child {\n\tdisplay: table;\n\twidth: 100%;\n}\n#ui-dialog-body.settings [id|=\"setting-label\"] {\n\tdisplay: table-cell;\n\tpadding: 0.4em 2em 0.4em 0;\n}\n#ui-dialog-body.settings [id|=\"setting-label\"] + div {\n\tdisplay: table-cell;\n\tmin-width: 8em;\n\ttext-align: right;\n\tvertical-align: middle;\n\twhite-space: nowrap;\n}\n\n\n/*\n\tBuilt-in dialog appearance styles.\n*/\n/* List-based dialog styling (primarily for the Jumpto & Share dialogs). */\n#ui-dialog-body.list {\n\tpadding: 0;\n}\n#ui-dialog-body.list ul {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n\tborder: 1px solid transparent;\n}\n#ui-dialog-body.list li {\n\tmargin: 0;\n}\n#ui-dialog-body.list li:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.list li a {\n\tdisplay: block;\n\tpadding: 0.25em 0.75em;\n\tborder: 1px solid transparent;\n\tcolor: #eee;\n\ttext-decoration: none;\n}\n#ui-dialog-body.list li a:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n\n/* Saves dialog styling. */\n#ui-dialog-body.saves {\n\tpadding: 0 0 1px; /* Webkit/Blink need 1px bottom padding or they'll trigger the scroll bar */\n}\n#ui-dialog-body.saves > *:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.saves table {\n\tborder-spacing: 0;\n\twidth: 100%;\n}\n#ui-dialog-body.saves tr:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.saves td {\n\tpadding: 0.33em 0.33em;\n}\n#ui-dialog-body.saves td:first-child {\n\tmin-width: 1.5em;\n\ttext-align: center;\n}\n#ui-dialog-body.saves td:nth-child(3) {\n\tline-height: 1.2;\n}\n#ui-dialog-body.saves td:last-child {\n\ttext-align: right;\n}\n#ui-dialog-body.saves .empty {\n\tcolor: #999;\n\tspeak: none;\n\ttext-align: center;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n#ui-dialog-body.saves .datestamp {\n\tfont-size: 75%;\n\tmargin-left: 1em;\n}\n#ui-dialog-body.saves ul.buttons li {\n\tpadding: 0.4em;\n}\n#ui-dialog-body.saves ul.buttons > li + li > button {\n\tmargin-left: 0.2em;\n}\n#ui-dialog-body.saves ul.buttons li:last-child {\n\t/*\n\t\tUsing `position:absolute;right:0;` here can produce poor results,\n\t\tso we use `float:right` instead.\n\t*/\n\tfloat: right;\n}\n\n/* Settings dialog styling. */\n#ui-dialog-body.settings div[id|=\"header-body\"] {\n\tmargin: 1em 0;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"]:first-child {\n\tmargin-top: 0;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"]:not(:first-child) {\n\tborder-top: 1px solid #444;\n\tpadding-top: 1em;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"] > * {\n\tmargin: 0;\n}\n#ui-dialog-body.settings h2[id|=\"header-heading\"] {\n\tfont-size: 1.375em;\n}\n#ui-dialog-body.settings p[id|=\"header-desc\"],\n#ui-dialog-body.settings p[id|=\"setting-desc\"] {\n\tfont-size: 87.5%;\n\tmargin: 0 0 0 0.5em;\n}\n#ui-dialog-body.settings div[id|=\"setting-body\"] + div[id|=\"setting-body\"] {\n\tmargin: 1em 0;\n}\n#ui-dialog-body.settings [id|=\"setting-control\"] {\n\twhite-space: nowrap;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"] {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tpadding: 0.4em;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"]:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled {\n\tbackground-color: #282;\n\tborder-color: #4a4;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:hover {\n\tbackground-color: #4a4;\n\tborder-color: #6c6;\n}\n#ui-dialog-body.settings input[type=\"range\"][id|=\"setting-control\"] {\n\tmax-width: 35vw;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-dialog-body.list a,\n#ui-dialog-body.settings span[id|=\"setting-input\"] {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-dialog-body.saves button[id=\"saves-export\"]:before,\n#ui-dialog-body.saves button[id=\"saves-import\"]:before,\n#ui-dialog-body.saves button[id=\"saves-clear\"]:before,\n#ui-dialog-body.settings button[id|=\"setting-control\"]:after,\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#ui-dialog-body.saves button[id=\"saves-export\"]:before {\n\tcontent: \"\\e829\\00a0\";\n}\n#ui-dialog-body.saves button[id=\"saves-import\"]:before {\n\tcontent: \"\\e82a\\00a0\";\n}\n#ui-dialog-body.saves button[id=\"saves-clear\"]:before {\n\tcontent: \"\\e827\\00a0\";\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"]:after {\n\tcontent: \"\\00a0\\00a0\\e830\";\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:after {\n\tcontent: \"\\00a0\\00a0\\e831\";\n}\n</style>\n<style id=\"style-ui-bar\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-bar.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tPatches to the core styles.\n*/\n#story {\n\tmargin-left: 20em;\n\t-webkit-transition: margin-left 200ms ease-in;\n\t-o-transition: margin-left 200ms ease-in;\n\ttransition: margin-left 200ms ease-in;\n}\n#ui-bar.stowed ~ #story {\n\tmargin-left: 4.5em;\n}\n@media screen and (max-width: 1136px) {\n\t#story {\n\t\tmargin-left: 19em;\n\t}\n\t#ui-bar.stowed ~ #story {\n\t\tmargin-left: 3.5em;\n\t}\n}\n/*\n\tAt very narrow viewport widths, set `#story{margin-left}` equal to the value\n\tof `#ui-bar.stowed~#story{margin-left}`, so that `#ui-bar` will side over top\n\tof `#story` when unstowed, rather than shoving it over.\n*/\n@media screen and (max-width: 768px) {\n\t#story {\n\t\tmargin-left: 3.5em;\n\t}\n}\n\n\n/*\n\tDefault structural styles.\n*/\n#ui-bar {\n\tposition: fixed;\n\tz-index: 50;\n\ttop: 0;\n\tleft: 0;\n\twidth: 17.5em;\n\theight: 100%;\n\tmargin: 0;\n\tpadding: 0;\n\t-webkit-transition: left 200ms ease-in;\n\t-o-transition: left 200ms ease-in;\n\ttransition: left 200ms ease-in;\n}\n#ui-bar.stowed {\n\tleft: -15.5em;\n}\n#ui-bar-tray {\n\tposition: absolute;\n\ttop: 0.2em;\n\tleft: 0;\n\tright: 0;\n}\n#ui-bar-body {\n\theight: 90%; /* fallback for browsers without support for calc() */\n\theight: calc(100% - 2.5em);\n\tmargin: 2.5em 0;\n\tpadding: 0 1.5em;\n}\n#ui-bar.stowed #ui-bar-history,\n#ui-bar.stowed #ui-bar-body {\n\tvisibility: hidden;\n\t-webkit-transition: visibility 200ms step-end;\n\t-o-transition: visibility 200ms step-end;\n\ttransition: visibility 200ms step-end;\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n#ui-bar {\n\tbackground-color: #222;\n\tborder-right: 1px solid #444;\n\ttext-align: center;\n}\n#ui-bar a {\n\ttext-decoration: none;\n}\n#ui-bar hr {\n\tborder-color: #444;\n}\n#ui-bar-toggle,\n#ui-bar-history [id|=\"history\"] {\n\tfont-size: 1.2em;\n\tline-height: inherit;\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n}\n#ui-bar-toggle {\n\tdisplay: block;\n\tposition: absolute;\n\ttop: 0;\n\tright: 0;\n\tborder-right: none;\n\tpadding: 0.3em 0.45em 0.25em;\n}\n#ui-bar.stowed #ui-bar-toggle {\n\tpadding: 0.3em 0.35em 0.25em 0.55em;\n}\n#ui-bar-toggle:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n#ui-bar-history {\n\tmargin: 0 auto;\n}\n#ui-bar-history [id|=\"history\"] {\n\tpadding: 0.2em 0.45em 0.35em;\n}\n#ui-bar-history #history-jumpto {\n\tpadding: 0.2em 0.665em 0.35em;\n}\n#ui-bar-history [id|=\"history\"]:not(:first-child) {\n\tmargin-left: 1.2em;\n}\n#ui-bar-history [id|=\"history\"]:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n#ui-bar-history [id|=\"history\"]:disabled {\n\tcolor: #444;\n\tbackground-color: transparent;\n\tborder-color: #444;\n}\n#ui-bar-body {\n\tline-height: 1.5;\n\toverflow: auto;\n}\n#ui-bar-body > :not(:first-child) {\n\tmargin-top: 2em;\n}\n#story-title {\n\tmargin: 0;\n\tfont-size: 162.5%;\n}\n#story-author {\n\tmargin-top: 2em;\n\tfont-weight: bold;\n}\n#menu ul {\n\tmargin: 1em 0 0;\n\tpadding: 0;\n\tlist-style: none;\n\tborder: 1px solid #444;\n}\n#menu ul:empty {\n\tdisplay: none;\n}\n#menu li {\n\tmargin: 0;\n}\n#menu li:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#menu li a {\n\tdisplay: block;\n\tpadding: 0.25em 0.75em;\n\tborder: 1px solid transparent;\n\tcolor: #eee;\n\ttext-transform: uppercase;\n}\n#menu li a:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-bar-history [id|=\"history\"],\n#ui-bar-toggle,\n#menu a {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-bar-toggle:before,\n#ui-bar-history [id|=\"history\"],\n#menu-core li[id|=\"menu-item\"] a:before {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#ui-bar-toggle:before {\n\tcontent: \"\\e81d\";\n}\n#ui-bar.stowed #ui-bar-toggle:before {\n\tcontent: \"\\e81e\";\n}\n#menu-item-saves a:before {\n\tcontent: \"\\e82b\\00a0\";\n}\n#menu-item-settings a:before {\n\tcontent: \"\\e82d\\00a0\";\n}\n#menu-item-restart a:before {\n\tcontent: \"\\e82c\\00a0\";\n}\n#menu-item-share a:before {\n\tcontent: \"\\e82f\\00a0\";\n}\n</style>\n<style id=\"style-ui-debug\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-debug.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault debug bar styles.\n*/\n#debug-bar {\n\tbackground-color: #222;\n\tborder-left: 1px solid #444;\n\tborder-top: 1px solid #444;\n\tbottom: 0;\n\tmargin: 0;\n\tmax-height: 75%;\n\t/* max-width: 28em;\n\tmin-width: 22em; */\n\tpadding: 0.5em;\n\tposition: fixed;\n\tright: 0;\n\tz-index: 99900;\n}\n#debug-bar > div:not([id]) + div {\n\tmargin-top: 0.5em;\n}\n#debug-bar > div > label {\n\tmargin-right: 0.5em;\n}\n#debug-bar > div > input[type=\"text\"] {\n\tmin-width: 0;\n\twidth: 8em;\n}\n#debug-bar > div > select {\n\twidth: 15em;\n}\n\n#debug-bar-toggle {\n\tcolor: #eee;\n\tbackground-color: #222;\n\tborder: 1px solid #444;\n\theight: 101%; /* fallback for browsers without support for calc() */\n\theight: calc(100% + 1px);\n\tleft: -2em; /* fallback for browsers without support for calc() */\n\tleft: calc(-2em - 1px);\n\tposition: absolute;\n\ttop: -1px;\n\twidth: 2em;\n}\n#debug-bar-toggle:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n\n#debug-bar-hint {\n\tbottom: 0.175em;\n\tfont-size: 4.5em;\n\topacity: 0.33;\n\tpointer-events: none;\n\tposition: fixed;\n\tright: 0.6em;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n\twhite-space: nowrap;\n}\n\n#debug-bar-watch {\n\tbackground-color: #222;\n\tborder-left: 1px solid #444;\n\tborder-top: 1px solid #444;\n\tbottom: 102%; /* fallback for browsers without support for calc() */\n\tbottom: calc(100% + 1px);\n\tfont-size: 0.9em;\n\tleft: -1px;\n\tmax-height: 650%; /* fallback for browsers without support for vh units */\n\tmax-height: 65vh;\n\tposition: absolute;\n\toverflow-x: hidden;\n\toverflow-y: scroll;\n\tright: 0;\n\tz-index: 99800;\n}\n#debug-bar-watch[hidden] {\n\tdisplay: none;\n}\n#debug-bar-watch div {\n\tcolor: #999;\n\tfont-style: italic;\n\tmargin: 1em auto;\n\ttext-align: center;\n}\n#debug-bar-watch table {\n\twidth: 100%;\n}\n#debug-bar-watch tr:nth-child(2n) {\n\tbackground-color: rgba(127, 127, 127, 0.15);\n}\n#debug-bar-watch td {\n\tpadding: 0.2em 0;\n}\n#debug-bar-watch td:first-child + td {\n\tpadding: 0.2em 0.3em 0.2em 0.1em;\n}\n#debug-bar-watch .watch-delete {\n\tbackground-color: transparent;\n\tborder: none;\n\tcolor: #c00;\n}\n#debug-bar-watch-all,\n#debug-bar-watch-none {\n\tmargin-left: 0.5em;\n}\n#debug-bar-watch-toggle,\n#debug-bar-views-toggle {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tmargin-right: 1em;\n\tpadding: 0.4em;\n}\n#debug-bar-watch-toggle:hover,\n#debug-bar-views-toggle:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle,\nhtml[data-debug-view] #debug-bar-views-toggle {\n\tbackground-color: #282;\n\tborder-color: #4a4;\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle:hover,\nhtml[data-debug-view] #debug-bar-views-toggle:hover {\n\tbackground-color: #4a4;\n\tborder-color: #6c6;\n}\n\n#debug-bar-toggle:before,\n#debug-bar-hint:after,\n#debug-bar-watch .watch-delete:before,\n#debug-bar-watch-add:before,\n#debug-bar-watch-all:before,\n#debug-bar-watch-none:before,\n#debug-bar-watch-toggle:after,\n#debug-bar-views-toggle:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#debug-bar-toggle:before {\n\tcontent: \"\\e838\";\n}\n#debug-bar-hint:after {\n\tcontent: \"\\e838\\202f\\e822\";\n}\n#debug-bar-watch .watch-delete:before {\n\tcontent: \"\\e804\";\n}\n#debug-bar-watch-add:before {\n\tcontent: \"\\e805\";\n}\n#debug-bar-watch-all:before {\n\tcontent: \"\\e83a\";\n}\n#debug-bar-watch-none:before {\n\tcontent: \"\\e827\";\n}\n#debug-bar-watch-toggle:after,\n#debug-bar-views-toggle:after {\n\tcontent: \"\\00a0\\00a0\\e830\";\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle:after,\nhtml[data-debug-view] #debug-bar-views-toggle:after {\n\tcontent: \"\\00a0\\00a0\\e831\";\n}\n\n\n/*\n\tDefault debug view styles.\n*/\nhtml[data-debug-view] .debug {\n\tpadding: 0.25em;\n\tbackground-color: #234; /* #541, #151 */\n}\nhtml[data-debug-view] .debug[title] {\n\tcursor: help;\n}\nhtml[data-debug-view] .debug.block {\n\tdisplay: inline-block;\n\tvertical-align: middle;\n}\nhtml[data-debug-view] .debug.invalid {\n\ttext-decoration: line-through;\n}\nhtml[data-debug-view] .debug.hidden,\nhtml[data-debug-view] .debug.hidden .debug {\n\tbackground-color: #555;\n}\nhtml:not([data-debug-view]) .debug.hidden {\n\tdisplay: none;\n}\n\nhtml[data-debug-view] .debug[data-name][data-type]:before,\nhtml[data-debug-view] .debug[data-name][data-type].nonvoid:after {\n\tbackground-color: rgba(0,0,0,0.25);\n\tfont-family: monospace, monospace;\n\twhite-space: pre;\n}\nhtml[data-debug-view] .debug[data-name][data-type]:before {\n\tcontent: attr(data-name);\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"macro\"]:before {\n\tcontent: \"<<\" attr(data-name) \">>\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"macro\"].nonvoid:after {\n\tcontent: \"<</\" attr(data-name) \">>\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"html\"]:before {\n\tcontent: \"<\" attr(data-name) \">\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"html\"].nonvoid:after {\n\tcontent: \"</\" attr(data-name) \">\";\n}\nhtml[data-debug-view] .debug[data-name][data-type]:not(:empty):before {\n\tmargin-right: 0.25em;\n}\nhtml[data-debug-view] .debug[data-name][data-type].nonvoid:not(:empty):after {\n\tmargin-left: 0.25em;\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"special\"],\nhtml[data-debug-view] .debug[data-name][data-type|=\"special\"]:before {\n\tdisplay: block;\n}\n</style>\n</head>\n<body>\n\t<div id=\"init-screen\">\n\t\t<div id=\"init-no-js\"><noscript>JavaScript is required. Please enable it to continue.</noscript></div>\n\t\t<div id=\"init-lacking\">Your browser lacks required capabilities. Please upgrade it or switch to another to continue.</div>\n\t\t<div id=\"init-loading\"><div>Loading&hellip;</div></div>\n\t</div>\n\t{{STORY_DATA}}\n\t<script id=\"script-sugarcube\" type=\"text/javascript\">\n\t/*! SugarCube JS */\n\tif(document.documentElement.getAttribute(\"data-init\")===\"loading\"){window.TWINE1=false;\nwindow.DEBUG=false;\n(function (window, document, jQuery, undefined) {\n\"use strict\";\n\n/***********************************************************************************************************************\n\n\tlib/alert.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tTODO: This regular expression should be elsewhere.\n\n\tError prologs by engine/browser: (ca. 2018)\n\t\tChrome, Opera, & Vivaldi → `Uncaught \\w*Error: …`\n\t\tEdge & IE                → `…`\n\t\tFirefox                  → `Error: …`\n\t\tOpera (Presto)           → `Uncaught exception: \\w*(?:Error|Exception): …`\n\t\tSafari (ca. v5.1)        → `\\w*(?:Error|_ERR): …`\n*/\nvar errorPrologRegExp = /^(?:(?:uncaught\\s+(?:exception:\\s+)?)?\\w*(?:error|exception|_err):\\s+)+/i; // eslint-disable-line no-unused-vars, no-var\n\nvar Alert = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tError Functions.\n\t*******************************************************************************************************************/\n\tfunction _alertMesg(type, where, what, error) {\n\t\tconst isFatal = type === 'fatal';\n\t\tlet mesg = `Apologies! ${isFatal ? 'A fatal' : 'An'} error has occurred.`;\n\n\t\tif (isFatal) {\n\t\t\tmesg += ' Aborting.';\n\t\t}\n\t\telse {\n\t\t\tmesg += ' You may be able to continue, but some parts may not work properly.';\n\t\t}\n\n\t\tif (where != null || what != null) { // lazy equality for null\n\t\t\tmesg += '\\n\\nError';\n\n\t\t\tif (where != null) { // lazy equality for null\n\t\t\t\tmesg += ` [${where}]`;\n\t\t\t}\n\n\t\t\tif (what != null) { // lazy equality for null\n\t\t\t\tmesg += `: ${what.replace(errorPrologRegExp, '')}.`;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tmesg += ': unknown error.';\n\t\t\t}\n\t\t}\n\n\t\tif (typeof error === 'object' && error !== null && error.stack) {\n\t\t\tmesg += `\\n\\nStack Trace:\\n${error.stack}`;\n\t\t}\n\n\t\twindow.alert(mesg); // eslint-disable-line no-alert\n\t}\n\n\tfunction alertError(where, what, error) {\n\t\t_alertMesg(null, where, what, error);\n\t}\n\n\tfunction alertFatal(where, what, error) {\n\t\t_alertMesg('fatal', where, what, error);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tError Event.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSet up a global error handler for uncaught exceptions.\n\t*/\n\t(origOnError => {\n\t\twindow.onerror = function (what, source, lineNum, colNum, error) {\n\t\t\t// Uncaught exceptions during play may be recoverable/ignorable.\n\t\t\tif (document.readyState === 'complete') {\n\t\t\t\talertError(null, what, error);\n\t\t\t}\n\n\t\t\t// Uncaught exceptions during startup should be fatal.\n\t\t\telse {\n\t\t\t\talertFatal(null, what, error);\n\t\t\t\twindow.onerror = origOnError;\n\n\t\t\t\tif (typeof window.onerror === 'function') {\n\t\t\t\t\twindow.onerror.apply(this, arguments);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t})(window.onerror);\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\terror : { value : alertError },\n\t\tfatal : { value : alertFatal }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/patterns.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tTODO: Move all markup patterns into here.\n*/\n\nvar Patterns = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tPatterns.\n\t*******************************************************************************************************************/\n\t/*\n\t\tWhitespace patterns.\n\n\t\tSpace class (equivalent to `\\s`):\n\t\t\t[\\u0020\\f\\n\\r\\t\\v\\u00a0\\u1680\\u180e\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000\\ufeff]\n\t\tSpace class, sans line terminators:\n\t\t\t[\\u0020\\f\\t\\v\\u00a0\\u1680\\u180e\\u2000-\\u200a\\u202f\\u205f\\u3000\\ufeff]\n\t\tLine Terminator class:\n\t\t\t[\\n\\r\\u2028\\u2029]\n\t*/\n\tconst space = (() => {\n\t\t/*\n\t\t\tSome browsers still supported by SugarCube have faulty space classes (`\\s`).\n\t\t\tWe check for that lossage here and, if necessary, build our own class from\n\t\t\tthe component pieces.\n\t\t*/\n\t\tconst wsMap = new Map([\n\t\t\t['\\u0020', '\\\\u0020'],\n\t\t\t['\\f', '\\\\f'],\n\t\t\t['\\n', '\\\\n'],\n\t\t\t['\\r', '\\\\r'],\n\t\t\t['\\t', '\\\\t'],\n\t\t\t['\\v', '\\\\v'],\n\t\t\t['\\u00a0', '\\\\u00a0'],\n\t\t\t['\\u1680', '\\\\u1680'],\n\t\t\t['\\u180e', '\\\\u180e'],\n\t\t\t['\\u2000', '\\\\u2000'],\n\t\t\t['\\u2001', '\\\\u2001'],\n\t\t\t['\\u2002', '\\\\u2002'],\n\t\t\t['\\u2003', '\\\\u2003'],\n\t\t\t['\\u2004', '\\\\u2004'],\n\t\t\t['\\u2005', '\\\\u2005'],\n\t\t\t['\\u2006', '\\\\u2006'],\n\t\t\t['\\u2007', '\\\\u2007'],\n\t\t\t['\\u2008', '\\\\u2008'],\n\t\t\t['\\u2009', '\\\\u2009'],\n\t\t\t['\\u200a', '\\\\u200a'],\n\t\t\t['\\u2028', '\\\\u2028'],\n\t\t\t['\\u2029', '\\\\u2029'],\n\t\t\t['\\u202f', '\\\\u202f'],\n\t\t\t['\\u205f', '\\\\u205f'],\n\t\t\t['\\u3000', '\\\\u3000'],\n\t\t\t['\\ufeff', '\\\\ufeff']\n\t\t]);\n\t\tconst wsRe = /^\\s$/;\n\t\tlet missing = '';\n\n\t\twsMap.forEach((pat, char) => {\n\t\t\tif (!wsRe.test(char)) {\n\t\t\t\tmissing += pat;\n\t\t\t}\n\t\t});\n\n\t\treturn missing ? `[\\\\s${missing}]` : '\\\\s';\n\t})();\n\tconst spaceNoTerminator = '[\\\\u0020\\\\f\\\\t\\\\v\\\\u00a0\\\\u1680\\\\u180e\\\\u2000-\\\\u200a\\\\u202f\\\\u205f\\\\u3000\\\\ufeff]';\n\tconst lineTerminator    = '[\\\\n\\\\r\\\\u2028\\\\u2029]';\n\tconst notSpace          = space === '\\\\s' ? '\\\\S' : space.replace(/^\\[/, '[^');\n\n\t/*\n\t\tCharacter patterns.\n\t*/\n\tconst anyChar = `(?:.|${lineTerminator})`;\n\n\t/*\n\t\tLetter patterns.\n\n\t\tFIXME:\n\t\t\t1. The existing set, which is a TiddlyWiki holdover, should probably\n\t\t\t   encompass a significantly greater range of BMP code points.\n\t\t\t2. Should we include the surrogate pair code units (\\uD800-\\uDBFF &\n\t\t\t   \\uDC00-\\uDFFF) to handle non-BMP code points?  Further, should we\n\t\t\t   simply be checking for the code units themselves or checking for\n\t\t\t   properly mated pairs?\n\t*/\n\tconst anyLetter       = '[0-9A-Z_a-z\\\\-\\\\u00c0-\\\\u00d6\\\\u00d8-\\\\u00f6\\\\u00f8-\\\\u00ff\\\\u0150\\\\u0170\\\\u0151\\\\u0171]';\n\tconst anyLetterStrict = anyLetter.replace('\\\\-', ''); // anyLetter sans hyphen\n\n\t/*\n\t\tIdentifier patterns.\n\n\t\tNOTE: Since JavaScript's RegExp syntax does not support Unicode character\n\t\tclasses, the correct regular expression to match a valid identifier name,\n\t\twithin the scope of our needs, would be on the order of approximately 5–6\n\t\tor 11–16 KiB, depending on how the pattern was built.  That being the case,\n\t\tfor the moment we restrict valid TwineScript identifiers to US-ASCII.\n\n\t\tFIXME: Fix this to, at least, approximate the correct range.\n\t*/\n\tconst identifierFirstChar = '[$A-Z_a-z]';\n\tconst identifierNextChar  = '[$0-9A-Z_a-z]';\n\tconst identifier          = `${identifierFirstChar}${identifierNextChar}*`;\n\n\t// Variable patterns.\n\tconst variableSigil = '[$_]';\n\tconst variable      = variableSigil + identifier;\n\n\t// Macro name pattern.\n\tconst macroName = '[A-Za-z][\\\\w-]*|[=-]';\n\n\t// Template name pattern.\n\tconst templateName = '[A-Za-z][\\\\w-]*';\n\n\t// CSS ID or class sigil pattern.\n\tconst cssIdOrClassSigil = '[#.]';\n\n\t// CSS image transclusion template pattern.\n\t//\n\t// NOTE: The alignment syntax isn't supported, but removing it might break uses\n\t// of the template in the wild, so we leave it alone for now.\n\tconst cssImage = '\\\\[[<>]?[Ii][Mm][Gg]\\\\[(?:\\\\s|\\\\S)*?\\\\]\\\\]+';\n\n\t// Inline CSS pattern.\n\tconst inlineCss = (() => {\n\t\t/* legacy */\n\t\tconst twStyle   = `(${anyLetter}+)\\\\(([^\\\\)\\\\|\\\\n]+)\\\\):`;\n\t\t/* /legacy */\n\t\tconst cssStyle  = `${spaceNoTerminator}*(${anyLetter}+)${spaceNoTerminator}*:([^;\\\\|\\\\n]+);`;\n\t\tconst idOrClass = `${spaceNoTerminator}*((?:${cssIdOrClassSigil}${anyLetter}+${spaceNoTerminator}*)+);`;\n\n\t\t// [1,2] = style(value):\n\t\t// [3,4] = style:value;\n\t\t// [5]   = #id.className;\n\t\treturn `${twStyle}|${cssStyle}|${idOrClass}`;\n\t})();\n\n\t// URL pattern.\n\tconst url = '(?:file|https?|mailto|ftp|javascript|irc|news|data):[^\\\\s\\'\"]+';\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze({\n\t\tspace,\n\t\tspaceNoTerminator,\n\t\tlineTerminator,\n\t\tnotSpace,\n\t\tanyChar,\n\t\tanyLetter,\n\t\tanyLetterStrict,\n\t\tidentifierFirstChar,\n\t\tidentifierNextChar,\n\t\tidentifier,\n\t\tvariableSigil,\n\t\tvariable,\n\t\tmacroName,\n\t\ttemplateName,\n\t\tcssIdOrClassSigil,\n\t\tcssImage,\n\t\tinlineCss,\n\t\turl\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/extensions.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns */\n\n/*\n\tJavaScript Polyfills.\n\n\tNOTE: The ES5 and ES6 polyfills come from the vendored `es5-shim.js` and `es6-shim.js` libraries.\n*/\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tTrims whitespace from either the start or end of the given string.\n\t*/\n\tconst _trimString = (() => {\n\t\t// Whitespace regular expressions.\n\t\tconst startWSRe = new RegExp(`^${Patterns.space}${Patterns.space}*`);\n\t\tconst endWSRe   = new RegExp(`${Patterns.space}${Patterns.space}*$`);\n\n\t\tfunction trimString(str, where) {\n\t\t\tconst val = String(str);\n\n\t\t\tif (!val) {\n\t\t\t\treturn val;\n\t\t\t}\n\n\t\t\tswitch (where) {\n\t\t\tcase 'start':\n\t\t\t\treturn startWSRe.test(val) ? val.replace(startWSRe, '') : val;\n\n\t\t\tcase 'end':\n\t\t\t\treturn endWSRe.test(val) ? val.replace(endWSRe, '') : val;\n\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`_trimString called with incorrect where parameter value: \"${where}\"`);\n\t\t\t}\n\t\t}\n\n\t\treturn trimString;\n\t})();\n\n\t/*\n\t\tGenerates a pad string based upon the given string and length.\n\t*/\n\tfunction _createPadString(length, padding) {\n\t\tconst targetLength = Number.parseInt(length, 10) || 0;\n\n\t\tif (targetLength < 1) {\n\t\t\treturn '';\n\t\t}\n\n\t\tlet padString = typeof padding === 'undefined' ? '' : String(padding);\n\n\t\tif (padString === '') {\n\t\t\tpadString = ' ';\n\t\t}\n\n\t\twhile (padString.length < targetLength) {\n\t\t\tconst curPadLength    = padString.length;\n\t\t\tconst remainingLength = targetLength - curPadLength;\n\n\t\t\tpadString += curPadLength > remainingLength\n\t\t\t\t? padString.slice(0, remainingLength)\n\t\t\t\t: padString;\n\t\t}\n\n\t\tif (padString.length > targetLength) {\n\t\t\tpadString = padString.slice(0, targetLength);\n\t\t}\n\n\t\treturn padString;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPolyfills.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[ES2019] Returns a new array consisting of the source array with all sub-array elements\n\t\tconcatenated into it recursively up to the given depth.\n\t*/\n\tif (!Array.prototype.flat) {\n\t\tObject.defineProperty(Array.prototype, 'flat', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\t\t\tvalue        : (() => {\n\t\t\t\tfunction flat(/* depth */) {\n\t\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\t\tthrow new TypeError('Array.prototype.flat called on null or undefined');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst depth = arguments.length === 0 ? 1 : Number(arguments[0]) || 0;\n\n\t\t\t\t\tif (depth < 1) {\n\t\t\t\t\t\treturn Array.prototype.slice.call(this);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn Array.prototype.reduce.call(\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\t(acc, cur) => {\n\t\t\t\t\t\t\tif (cur instanceof Array) {\n\t\t\t\t\t\t\t\t// acc.push.apply(acc, flat.call(cur, depth - 1));\n\t\t\t\t\t\t\t\tacc.push(...flat.call(cur, depth - 1));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tacc.push(cur);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn acc;\n\t\t\t\t\t\t},\n\t\t\t\t\t\t[]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn flat;\n\t\t\t})()\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a new array consisting of the result of calling the given mapping function\n\t\ton every element in the source array and then concatenating all sub-array elements into it\n\t\trecursively up to a depth of `1`.  Identical to calling `<Array>.map(fn).flat()`.\n\t*/\n\tif (!Array.prototype.flatMap) {\n\t\tObject.defineProperty(Array.prototype, 'flatMap', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(/* callback [, thisArg] */) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Array.prototype.flatMap called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.map.apply(this, arguments).flat();\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2016] Returns whether the given element was found within the array.\n\t*/\n\tif (!Array.prototype.includes) {\n\t\tObject.defineProperty(Array.prototype, 'includes', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Array.prototype.includes called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tif (arguments.length === 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst length = this.length >>> 0;\n\n\t\t\t\tif (length === 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst needle = arguments[0];\n\t\t\t\tlet i = Number(arguments[1]) || 0;\n\n\t\t\t\tif (i < 0) {\n\t\t\t\t\ti = Math.max(0, length + i);\n\t\t\t\t}\n\n\t\t\t\tfor (/* empty */; i < length; ++i) {\n\t\t\t\t\tconst value = this[i];\n\n\t\t\t\t\tif (value === needle || value !== value && needle !== needle) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a new array consisting of the given object's own enumerable property/value\n\t\tpairs as `[key, value]` arrays.\n\t*/\n\tif (!Object.entries) {\n\t\tObject.defineProperty(Object, 'entries', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (typeof obj !== 'object' || obj === null) {\n\t\t\t\t\tthrow new TypeError('Object.entries object parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\treturn Object.keys(obj).map(key => [key, obj[key]]);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a new generic object consisting of the given list's key/value pairs.\n\t*/\n\tif (!Object.fromEntries) {\n\t\tObject.defineProperty(Object, 'fromEntries', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(iter) {\n\t\t\t\treturn Array.from(iter).reduce(\n\t\t\t\t\t(acc, pair) => {\n\t\t\t\t\t\tif (Object(pair) !== pair) {\n\t\t\t\t\t\t\tthrow new TypeError('Object.fromEntries iterable parameter must yield objects');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (pair[0] in acc) {\n\t\t\t\t\t\t\tObject.defineProperty(acc, pair[0], {\n\t\t\t\t\t\t\t\tconfigurable : true,\n\t\t\t\t\t\t\t\tenumerable   : true,\n\t\t\t\t\t\t\t\twritable     : true,\n\t\t\t\t\t\t\t\tvalue        : pair[1]\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tacc[pair[0]] = pair[1]; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{}\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns all own property descriptors of the given object.\n\t*/\n\tif (!Object.getOwnPropertyDescriptors) {\n\t\tObject.defineProperty(Object, 'getOwnPropertyDescriptors', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (obj == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Object.getOwnPropertyDescriptors object parameter is null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst O = Object(obj);\n\n\t\t\t\treturn Reflect.ownKeys(O).reduce(\n\t\t\t\t\t(acc, key) => {\n\t\t\t\t\t\tconst desc = Object.getOwnPropertyDescriptor(O, key);\n\n\t\t\t\t\t\tif (typeof desc !== 'undefined') {\n\t\t\t\t\t\t\tif (key in acc) {\n\t\t\t\t\t\t\t\tObject.defineProperty(acc, key, {\n\t\t\t\t\t\t\t\t\tconfigurable : true,\n\t\t\t\t\t\t\t\t\tenumerable   : true,\n\t\t\t\t\t\t\t\t\twritable     : true,\n\t\t\t\t\t\t\t\t\tvalue        : desc\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tacc[key] = desc; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{}\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a new array consisting of the given object's own enumerable property values.\n\t*/\n\tif (!Object.values) {\n\t\tObject.defineProperty(Object, 'values', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (typeof obj !== 'object' || obj === null) {\n\t\t\t\t\tthrow new TypeError('Object.values object parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\treturn Object.keys(obj).map(key => obj[key]);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a string based on concatenating the given padding, repeated as necessary,\n\t\tto the start of the string so that the given length is reached.\n\n\t\tNOTE: This pads based upon Unicode code units, rather than code points.\n\t*/\n\tif (!String.prototype.padStart) {\n\t\tObject.defineProperty(String.prototype, 'padStart', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(length, padding) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.padStart called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst baseString   = String(this);\n\t\t\t\tconst baseLength   = baseString.length;\n\t\t\t\tconst targetLength = Number.parseInt(length, 10);\n\n\t\t\t\tif (targetLength <= baseLength) {\n\t\t\t\t\treturn baseString;\n\t\t\t\t}\n\n\t\t\t\treturn _createPadString(targetLength - baseLength, padding) + baseString;\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a string based on concatenating the given padding, repeated as necessary,\n\t\tto the end of the string so that the given length is reached.\n\n\t\tNOTE: This pads based upon Unicode code units, rather than code points.\n\t*/\n\tif (!String.prototype.padEnd) {\n\t\tObject.defineProperty(String.prototype, 'padEnd', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(length, padding) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.padEnd called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst baseString   = String(this);\n\t\t\t\tconst baseLength   = baseString.length;\n\t\t\t\tconst targetLength = Number.parseInt(length, 10);\n\n\t\t\t\tif (targetLength <= baseLength) {\n\t\t\t\t\treturn baseString;\n\t\t\t\t}\n\n\t\t\t\treturn baseString + _createPadString(targetLength - baseLength, padding);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a string with all whitespace removed from the start of the string.\n\t*/\n\tif (!String.prototype.trimStart) {\n\t\tObject.defineProperty(String.prototype, 'trimStart', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimStart called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'start');\n\t\t\t}\n\t\t});\n\t}\n\n\tif (!String.prototype.trimLeft) {\n\t\tObject.defineProperty(String.prototype, 'trimLeft', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimLeft called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'start');\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a string with all whitespace removed from the end of the string.\n\t*/\n\tif (!String.prototype.trimEnd) {\n\t\tObject.defineProperty(String.prototype, 'trimEnd', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimEnd called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'end');\n\t\t\t}\n\t\t});\n\t}\n\n\tif (!String.prototype.trimRight) {\n\t\tObject.defineProperty(String.prototype, 'trimRight', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimRight called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'end');\n\t\t\t}\n\t\t});\n\t}\n})();\n\n\n/*\n\tJavaScript Extensions.\n*/\n(() => {\n\t'use strict';\n\n\tconst _nativeMathRandom = Math.random;\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a pseudo-random whole number (integer) within the given bounds.\n\t*/\n\tfunction _random(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('_random called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = arguments[0];\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = arguments[0];\n\t\t\tmax = arguments[1];\n\t\t\tbreak;\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn Math.floor(_nativeMathRandom() * (max - min + 1)) + min;\n\t}\n\n\t/*\n\t\tReturns a randomly selected index within the given length and bounds.\n\t\tBounds may be negative.\n\t*/\n\tfunction _randomIndex(length, boundsArgs) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (boundsArgs.length) {\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = length - 1;\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tmin = 0;\n\t\t\tmax = Math.trunc(boundsArgs[1]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Math.trunc(boundsArgs[1]);\n\t\t\tmax = Math.trunc(boundsArgs[2]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (Number.isNaN(min)) {\n\t\t\tmin = 0;\n\t\t}\n\t\telse if (!Number.isFinite(min) || min >= length) {\n\t\t\tmin = length - 1;\n\t\t}\n\t\telse if (min < 0) {\n\t\t\tmin = length + min;\n\n\t\t\tif (min < 0) {\n\t\t\t\tmin = 0;\n\t\t\t}\n\t\t}\n\n\t\tif (Number.isNaN(max)) {\n\t\t\tmax = 0;\n\t\t}\n\t\telse if (!Number.isFinite(max) || max >= length) {\n\t\t\tmax = length - 1;\n\t\t}\n\t\telse if (max < 0) {\n\t\t\tmax = length + max;\n\n\t\t\tif (max < 0) {\n\t\t\t\tmax = length - 1;\n\t\t\t}\n\t\t}\n\n\t\treturn _random(min, max);\n\t}\n\n\t/*\n\t\tReturns an object (`{ char, start, end }`) containing the Unicode character at\n\t\tposition `pos`, its starting position, and its ending position—surrogate pairs\n\t\tare properly handled.  If `pos` is out-of-bounds, returns an object containing\n\t\tthe empty string and start/end positions of `-1`.\n\n\t\tThis function is necessary because JavaScript strings are sequences of UTF-16\n\t\tcode units, so surrogate pairs are exposed and thus must be handled.  While the\n\t\tES6/2015 standard does improve the situation somewhat, it does not alleviate\n\t\tthe need for this function.\n\n\t\tNOTE: Will throw exceptions on invalid surrogate pairs.\n\n\t\tIDEA: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt\n\t*/\n\tfunction _getCodePointStartAndEnd(str, pos) {\n\t\tconst code = str.charCodeAt(pos);\n\n\t\t// Given position was out-of-bounds.\n\t\tif (Number.isNaN(code)) {\n\t\t\treturn { char : '', start : -1, end : -1 };\n\t\t}\n\n\t\t// Code unit is not a UTF-16 surrogate.\n\t\tif (code < 0xD800 || code > 0xDFFF) {\n\t\t\treturn {\n\t\t\t\tchar  : str.charAt(pos),\n\t\t\t\tstart : pos,\n\t\t\t\tend   : pos\n\t\t\t};\n\t\t}\n\n\t\t// Code unit is a high surrogate (D800–DBFF).\n\t\tif (code >= 0xD800 && code <= 0xDBFF) {\n\t\t\tconst nextPos = pos + 1;\n\n\t\t\t// End of string.\n\t\t\tif (nextPos >= str.length) {\n\t\t\t\tthrow new Error('high surrogate without trailing low surrogate');\n\t\t\t}\n\n\t\t\tconst nextCode = str.charCodeAt(nextPos);\n\n\t\t\t// Next code unit is not a low surrogate (DC00–DFFF).\n\t\t\tif (nextCode < 0xDC00 || nextCode > 0xDFFF) {\n\t\t\t\tthrow new Error('high surrogate without trailing low surrogate');\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tchar  : str.charAt(pos) + str.charAt(nextPos),\n\t\t\t\tstart : pos,\n\t\t\t\tend   : nextPos\n\t\t\t};\n\t\t}\n\n\t\t// Code unit is a low surrogate (DC00–DFFF) in the first position.\n\t\tif (pos === 0) {\n\t\t\tthrow new Error('low surrogate without leading high surrogate');\n\t\t}\n\n\t\tconst prevPos  = pos - 1;\n\t\tconst prevCode = str.charCodeAt(prevPos);\n\n\t\t// Previous code unit is not a high surrogate (D800–DBFF).\n\t\tif (prevCode < 0xD800 || prevCode > 0xDBFF) {\n\t\t\tthrow new Error('low surrogate without leading high surrogate');\n\t\t}\n\n\t\treturn {\n\t\t\tchar  : str.charAt(prevPos) + str.charAt(pos),\n\t\t\tstart : prevPos,\n\t\t\tend   : pos\n\t\t};\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, General.\n\t*******************************************************************************************************************/\n\t/*\n\t\tRandomly selects an element from the given array, or array-like object, and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array, 'random', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(array /* DEPRECATED: [, [min ,] max] */) {\n\t\t\tif (\n\t\t\t\t   typeof array !== 'object'\n\t\t\t\t|| array === null\n\t\t\t\t|| !Object.prototype.hasOwnProperty.call(array, 'length')\n\t\t\t) {\n\t\t\t\tthrow new TypeError('Array.random array parameter must be an array or array-lke object');\n\t\t\t}\n\n\t\t\tconst length = array.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, Array.prototype.slice.call(arguments, 1));\n\n\t\t\treturn array[index];\n\t\t}\n\t});\n\n\t/*\n\t\tConcatenates one or more unique elements to the end of the base array\n\t\tand returns the result as a new array.  Elements which are arrays will\n\t\tbe merged—i.e. their elements will be concatenated, rather than the\n\t\tarray itself.\n\t*/\n\tObject.defineProperty(Array.prototype, 'concatUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.concatUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst result = Array.from(this);\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tconst items   = Array.prototype.reduce.call(arguments, (prev, cur) => prev.concat(cur), []);\n\t\t\tconst addSize = items.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst push    = Array.prototype.push;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = items[i];\n\n\t\t\t\tif (indexOf.call(result, value) === -1) {\n\t\t\t\t\tpush.call(result, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number of times the given element was found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'count', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex ] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.count called on null or undefined');\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst needle  = arguments[0];\n\t\t\tlet pos   = Number(arguments[1]) || 0;\n\t\t\tlet count = 0;\n\n\t\t\twhile ((pos = indexOf.call(this, needle, pos)) !== -1) {\n\t\t\t\t++count;\n\t\t\t\t++pos;\n\t\t\t}\n\n\t\t\treturn count;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the given elements from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'delete', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.delete called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst needles       = Array.prototype.concat.apply([], arguments);\n\t\t\tconst needlesLength = needles.length;\n\t\t\tconst indices       = [];\n\n\t\t\tfor (let i = 0; i < length; ++i) {\n\t\t\t\tconst value = this[i];\n\n\t\t\t\tfor (let j = 0; j < needlesLength; ++j) {\n\t\t\t\t\tconst needle = needles[j];\n\n\t\t\t\t\tif (value === needle || value !== value && needle !== needle) {\n\t\t\t\t\t\tindices.push(i);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst result = [];\n\n\t\t\t// Copy the elements (in original order).\n\t\t\tfor (let i = 0, iend = indices.length; i < iend; ++i) {\n\t\t\t\tresult[i] = this[indices[i]];\n\t\t\t}\n\n\t\t\tconst splice = Array.prototype.splice;\n\n\t\t\t// Delete the elements (in reverse order).\n\t\t\tfor (let i = indices.length - 1; i >= 0; --i) {\n\t\t\t\tsplice.call(this, indices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the elements at the given indices from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'deleteAt', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* indices */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.deleteAt called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst splice     = Array.prototype.splice;\n\t\t\tconst cpyIndices = [\n\t\t\t\t...(new Set(\n\t\t\t\t\tArray.prototype.concat.apply([], arguments)\n\t\t\t\t\t\t// Map negative indices to their positive counterparts,\n\t\t\t\t\t\t// so the Set can properly filter out duplicates.\n\t\t\t\t\t\t.map(x => x < 0 ? Math.max(0, length + x) : x)\n\t\t\t\t)).values()\n\t\t\t];\n\t\t\tconst delIndices = [...cpyIndices].sort((a, b) => b - a);\n\t\t\tconst result     = [];\n\n\t\t\t// Copy the elements (in originally specified order).\n\t\t\tfor (let i = 0, iend = cpyIndices.length; i < iend; ++i) {\n\t\t\t\tresult[i] = this[cpyIndices[i]];\n\t\t\t}\n\n\t\t\t// Delete the elements (in descending numeric order).\n\t\t\tfor (let i = 0, iend = delIndices.length; i < iend; ++i) {\n\t\t\t\tsplice.call(this, delIndices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the elements that pass the test implemented\n\t\tby the given predicate function from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'deleteWith', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(predicate, thisArg) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.deleteWith called on null or undefined');\n\t\t\t}\n\t\t\tif (typeof predicate !== 'function') {\n\t\t\t\tthrow new Error('Array.prototype.deleteWith predicate parameter must be a function');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst splice  = Array.prototype.splice;\n\t\t\tconst indices = [];\n\t\t\tconst result  = [];\n\n\t\t\t// Copy the elements (in original order).\n\t\t\tfor (let i = 0; i < length; ++i) {\n\t\t\t\tif (predicate.call(thisArg, this[i], i, this)) {\n\t\t\t\t\tresult.push(this[i]);\n\t\t\t\t\tindices.push(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Delete the elements (in reverse order).\n\t\t\tfor (let i = indices.length - 1; i >= 0; --i) {\n\t\t\t\tsplice.call(this, indices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the first element from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'first', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.first called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn this[0];\n\t\t}\n\t});\n\n\t/*\n\t\tReturns whether all of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'includesAll', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.includesAll called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 1) {\n\t\t\t\tif (Array.isArray(arguments[0])) {\n\t\t\t\t\treturn Array.prototype.includesAll.apply(this, arguments[0]);\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = arguments.length; i < iend; ++i) {\n\t\t\t\tif (\n\t\t\t\t\t!Array.prototype.some.call(this, function (val) {\n\t\t\t\t\t\treturn val === this.val || val !== val && this.val !== this.val;\n\t\t\t\t\t}, { val : arguments[i] })\n\t\t\t\t) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns whether any of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'includesAny', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.includesAny called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 1) {\n\t\t\t\tif (Array.isArray(arguments[0])) {\n\t\t\t\t\treturn Array.prototype.includesAny.apply(this, arguments[0]);\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = arguments.length; i < iend; ++i) {\n\t\t\t\tif (\n\t\t\t\t\tArray.prototype.some.call(this, function (val) {\n\t\t\t\t\t\treturn val === this.val || val !== val && this.val !== this.val;\n\t\t\t\t\t}, { val : arguments[i] })\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the last element from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'last', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.last called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn this[length - 1];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly removes an element from the base array and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pluck', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* DEPRECATED: [min ,] max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pluck called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, [...arguments]);\n\n\t\t\treturn Array.prototype.splice.call(this, index, 1)[0];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly removes the given number of unique elements from the base array\n\t\tand returns the removed elements as a new array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pluckMany', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(wantSize) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pluckMany called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tlet want = Math.trunc(wantSize);\n\n\t\t\tif (!Number.isInteger(want)) {\n\t\t\t\tthrow new Error('Array.prototype.pluckMany want parameter must be an integer');\n\t\t\t}\n\n\t\t\tif (want < 1) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif (want > length) {\n\t\t\t\twant = length;\n\t\t\t}\n\n\t\t\tconst splice = Array.prototype.splice;\n\t\t\tconst result = [];\n\t\t\tlet max = length - 1;\n\n\t\t\tdo {\n\t\t\t\tresult.push(splice.call(this, _random(0, max--), 1)[0]);\n\t\t\t} while (result.length < want);\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tAppends one or more unique elements to the end of the base array and\n\t\treturns its new length.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pushUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pushUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst addSize = arguments.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn this.length >>> 0;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst push    = Array.prototype.push;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = arguments[i];\n\n\t\t\t\tif (indexOf.call(this, value) === -1) {\n\t\t\t\t\tpush.call(this, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.length >>> 0;\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly selects an element from the base array and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array.prototype, 'random', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* DEPRECATED: [min ,] max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.random called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, [...arguments]);\n\n\t\t\treturn this[index];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly selects the given number of unique elements from the base array\n\t\tand returns the selected elements as a new array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'randomMany', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(wantSize) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.randomMany called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tlet want = Math.trunc(wantSize);\n\n\t\t\tif (!Number.isInteger(want)) {\n\t\t\t\tthrow new Error('Array.prototype.randomMany want parameter must be an integer');\n\t\t\t}\n\n\t\t\tif (want < 1) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif (want > length) {\n\t\t\t\twant = length;\n\t\t\t}\n\n\t\t\tconst picked = new Map();\n\t\t\tconst result = [];\n\t\t\tconst max    = length - 1;\n\n\t\t\tdo {\n\t\t\t\tlet i;\n\t\t\t\tdo {\n\t\t\t\t\ti = _random(0, max);\n\t\t\t\t} while (picked.has(i));\n\t\t\t\tpicked.set(i, true);\n\t\t\t\tresult.push(this[i]);\n\t\t\t} while (result.length < want);\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly shuffles the array and returns it.\n\t*/\n\tObject.defineProperty(Array.prototype, 'shuffle', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.shuffle called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tfor (let i = length - 1; i > 0; --i) {\n\t\t\t\tconst j = Math.floor(_nativeMathRandom() * (i + 1));\n\n\t\t\t\tif (i === j) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// [this[i], this[j]] = [this[j], this[i]];\n\t\t\t\tconst swap = this[i];\n\t\t\t\tthis[i] = this[j];\n\t\t\t\tthis[j] = swap;\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\t});\n\n\t/*\n\t\tPrepends one or more unique elements to the beginning of the base array\n\t\tand returns its new length.\n\t*/\n\tObject.defineProperty(Array.prototype, 'unshiftUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.unshiftUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst addSize = arguments.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn this.length >>> 0;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst unshift = Array.prototype.unshift;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = arguments[i];\n\n\t\t\t\tif (indexOf.call(this, value) === -1) {\n\t\t\t\t\tunshift.call(this, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.length >>> 0;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a bound function that supplies the given arguments to the base\n\t\tfunction, followed by the arguments are supplied to the bound function,\n\t\twhenever it is called.\n\t*/\n\tObject.defineProperty(Function.prototype, 'partial', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Function.prototype.partial called on null or undefined');\n\t\t\t}\n\n\t\t\tconst slice = Array.prototype.slice;\n\t\t\tconst fn    = this;\n\t\t\tconst bound = slice.call(arguments, 0);\n\n\t\t\treturn function () {\n\t\t\t\tconst applied = [];\n\t\t\t\tlet argc = 0;\n\n\t\t\t\tfor (let i = 0; i < bound.length; ++i) {\n\t\t\t\t\tapplied.push(bound[i] === undefined ? arguments[argc++] : bound[i]);\n\t\t\t\t}\n\n\t\t\t\treturn fn.apply(this, applied.concat(slice.call(arguments, argc)));\n\t\t\t};\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the given numerical clamped to the specified bounds.\n\t*/\n\tObject.defineProperty(Math, 'clamp', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(num, min, max) {\n\t\t\tconst value = Number(num);\n\t\t\treturn Number.isNaN(value) ? NaN : value.clamp(min, max);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a decimal number eased from 0 to 1.\n\n\t\tNOTE: The magnitude of the returned value decreases if num < 0.5 or increases if num > 0.5.\n\t*/\n\tObject.defineProperty(Math, 'easeInOut', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(num) {\n\t\t\treturn 1 - (Math.cos(Number(num) * Math.PI) + 1) / 2;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number clamped to the specified bounds.\n\t*/\n\tObject.defineProperty(Number.prototype, 'clamp', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* min, max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Number.prototype.clamp called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length !== 2) {\n\t\t\t\tthrow new Error('Number.prototype.clamp called with an incorrect number of parameters');\n\t\t\t}\n\n\t\t\tlet min = Number(arguments[0]);\n\t\t\tlet max = Number(arguments[1]);\n\n\t\t\tif (min > max) {\n\t\t\t\t[min, max] = [max, min];\n\t\t\t}\n\n\t\t\treturn Math.min(Math.max(this, min), max);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the given string with all RegExp metacharacters escaped.\n\t*/\n\tif (!RegExp.escape) {\n\t\t(() => {\n\t\t\tconst _regExpMetaCharsRe    = /[\\\\^$*+?.()|[\\]{}]/g;\n\t\t\tconst _hasRegExpMetaCharsRe = new RegExp(_regExpMetaCharsRe.source); // to drop the global flag\n\n\t\t\tObject.defineProperty(RegExp, 'escape', {\n\t\t\t\tconfigurable : true,\n\t\t\t\twritable     : true,\n\n\t\t\t\tvalue(str) {\n\t\t\t\t\tconst val = String(str);\n\t\t\t\t\treturn val && _hasRegExpMetaCharsRe.test(val)\n\t\t\t\t\t\t? val.replace(_regExpMetaCharsRe, '\\\\$&')\n\t\t\t\t\t\t: val;\n\t\t\t\t}\n\t\t\t});\n\t\t})();\n\t}\n\n\t/*\n\t\tReturns a formatted string, after replacing each format item in the given\n\t\tformat string with the text equivalent of the corresponding argument's value.\n\t*/\n\t(() => {\n\t\tconst _formatRegExp    = /{(\\d+)(?:,([+-]?\\d+))?}/g;\n\t\tconst _hasFormatRegExp = new RegExp(_formatRegExp.source); // to drop the global flag\n\n\t\tObject.defineProperty(String, 'format', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(format) {\n\t\t\t\tfunction padString(str, align, pad) {\n\t\t\t\t\tif (!align) {\n\t\t\t\t\t\treturn str;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst plen = Math.abs(align) - str.length;\n\n\t\t\t\t\tif (plen < 1) {\n\t\t\t\t\t\treturn str;\n\t\t\t\t\t}\n\n\t\t\t\t\t// const padding = Array(plen + 1).join(pad);\n\t\t\t\t\tconst padding = String(pad).repeat(plen);\n\t\t\t\t\treturn align < 0 ? str + padding : padding + str;\n\t\t\t\t}\n\n\t\t\t\tif (arguments.length < 2) {\n\t\t\t\t\treturn arguments.length === 0 ? '' : format;\n\t\t\t\t}\n\n\t\t\t\tconst args = arguments.length === 2 && Array.isArray(arguments[1])\n\t\t\t\t\t? [...arguments[1]]\n\t\t\t\t\t: Array.prototype.slice.call(arguments, 1);\n\n\t\t\t\tif (args.length === 0) {\n\t\t\t\t\treturn format;\n\t\t\t\t}\n\n\t\t\t\tif (!_hasFormatRegExp.test(format)) {\n\t\t\t\t\treturn format;\n\t\t\t\t}\n\n\t\t\t\t// Possibly required by some old buggy browsers.\n\t\t\t\t_formatRegExp.lastIndex = 0;\n\n\t\t\t\treturn format.replace(_formatRegExp, (match, index, align) => {\n\t\t\t\t\tlet retval = args[index];\n\n\t\t\t\t\tif (retval == null) { // lazy equality for null\n\t\t\t\t\t\treturn '';\n\t\t\t\t\t}\n\n\t\t\t\t\twhile (typeof retval === 'function') {\n\t\t\t\t\t\tretval = retval();\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (typeof retval) {\n\t\t\t\t\tcase 'string': /* no-op */ break;\n\t\t\t\t\tcase 'object': retval = JSON.stringify(retval); break;\n\t\t\t\t\tdefault:       retval = String(retval); break;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn padString(retval, !align ? 0 : Number.parseInt(align, 10), ' ');\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t})();\n\n\t/*\n\t\tReturns whether the given string was found within the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'contains', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.contains called on null or undefined');\n\t\t\t}\n\n\t\t\treturn String.prototype.indexOf.apply(this, arguments) !== -1;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number of times the given substring was found within the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'count', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex ] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.count called on null or undefined');\n\t\t\t}\n\n\t\t\tconst needle = String(arguments[0] || '');\n\n\t\t\tif (needle === '') {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tconst indexOf = String.prototype.indexOf;\n\t\t\tconst step    = needle.length;\n\t\t\tlet pos     = Number(arguments[1]) || 0;\n\t\t\tlet count   = 0;\n\n\t\t\twhile ((pos = indexOf.call(this, needle, pos)) !== -1) {\n\t\t\t\t++count;\n\t\t\t\tpos += step;\n\t\t\t}\n\n\t\t\treturn count;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the first Unicode code point from the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'first', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.first called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn char;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the last Unicode code point from the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'last', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.last called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the last code point—may be one or two code units—and its end position.\n\t\t\tconst { char } = _getCodePointStartAndEnd(str, str.length - 1);\n\n\t\t\treturn char;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with `delCount` characters replaced with\n\t\t`replacement`, starting at `startAt`.\n\t*/\n\tObject.defineProperty(String.prototype, 'splice', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(startAt, delCount, replacement) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.splice called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tlet start = Number(startAt);\n\n\t\t\tif (!Number.isSafeInteger(start)) {\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t\telse if (start < 0) {\n\t\t\t\tstart += length;\n\n\t\t\t\tif (start < 0) {\n\t\t\t\t\tstart = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (start > length) {\n\t\t\t\tstart = length;\n\t\t\t}\n\n\t\t\tlet count = Number(delCount);\n\n\t\t\tif (!Number.isSafeInteger(count) || count < 0) {\n\t\t\t\tcount = 0;\n\t\t\t}\n\n\t\t\tlet res = this.slice(0, start);\n\n\t\t\tif (typeof replacement !== 'undefined') {\n\t\t\t\tres += replacement;\n\t\t\t}\n\n\t\t\tif (start + count < length) {\n\t\t\t\tres += this.slice(start + count);\n\t\t\t}\n\n\t\t\treturn res;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns an array of strings, split from the string, or an empty array if the\n\t\tstring is empty.\n\t*/\n\tObject.defineProperty(String.prototype, 'splitOrEmpty', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* [ separator [, limit ]] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.splitOrEmpty called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tif (String(this) === '') {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\treturn String.prototype.split.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with the first Unicode code point uppercased,\n\t\taccording to any locale-specific rules.\n\t*/\n\tObject.defineProperty(String.prototype, 'toLocaleUpperFirst', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.toLocaleUpperFirst called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char, end } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn end === -1 ? '' : char.toLocaleUpperCase() + str.slice(end + 1);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with the first Unicode code point uppercased.\n\t*/\n\tObject.defineProperty(String.prototype, 'toUpperFirst', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.toUpperFirst called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char, end } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn end === -1 ? '' : char.toUpperCase() + str.slice(end + 1);\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, JSON.\n\t*******************************************************************************************************************/\n\t/*\n\t\tDefine `toJSON()` methods on each prototype we wish to support.\n\t*/\n\tObject.defineProperty(Date.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:date)', this.toISOString()];\n\t\t}\n\t});\n\tObject.defineProperty(Function.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\t/*\n\t\t\t\tThe enclosing parenthesis here are necessary to force the function expression code\n\t\t\t\tstring, returned by `this.toString()`, to be evaluated as an expression during\n\t\t\t\trevival.  Without them, the function expression, which is likely nameless, will be\n\t\t\t\tevaluated as a function definition—which will throw a syntax error exception, since\n\t\t\t\tfunction definitions must have a name.\n\t\t\t*/\n\t\t\treturn ['(revive:eval)', `(${this.toString()})`];\n\t\t}\n\t});\n\tObject.defineProperty(Map.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:map)', [...this]];\n\t\t}\n\t});\n\tObject.defineProperty(RegExp.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:eval)', this.toString()];\n\t\t}\n\t});\n\tObject.defineProperty(Set.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:set)', [...this]];\n\t\t}\n\t});\n\n\t/*\n\t\tUtility method to allow users to easily wrap their code in the revive wrapper.\n\t*/\n\tObject.defineProperty(JSON, 'reviveWrapper', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(code, data) {\n\t\t\tif (typeof code !== 'string') {\n\t\t\t\tthrow new TypeError('JSON.reviveWrapper code parameter must be a string');\n\t\t\t}\n\n\t\t\treturn ['(revive:eval)', [code, data]];\n\t\t}\n\t});\n\n\t/*\n\t\tBackup the original `JSON.parse()` and replace it with a revive wrapper aware version.\n\t*/\n\tObject.defineProperty(JSON, '_real_parse', {\n\t\tvalue : JSON.parse\n\t});\n\tObject.defineProperty(JSON, 'parse', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(text, reviver) {\n\t\t\treturn JSON._real_parse(text, (key, val) => {\n\t\t\t\tlet value = val;\n\n\t\t\t\t/*\n\t\t\t\t\tAttempt to revive wrapped values.\n\t\t\t\t*/\n\t\t\t\tif (Array.isArray(value) && value.length === 2) {\n\t\t\t\t\tswitch (value[0]) {\n\t\t\t\t\tcase '(revive:set)':\n\t\t\t\t\t\tvalue = new Set(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:map)':\n\t\t\t\t\t\tvalue = new Map(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:date)':\n\t\t\t\t\t\tvalue = new Date(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:eval)':\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t/* eslint-disable no-eval */\n\t\t\t\t\t\t\t// For post-v2.9.0 `JSON.reviveWrapper()`.\n\t\t\t\t\t\t\tif (Array.isArray(value[1])) {\n\t\t\t\t\t\t\t\tconst $ReviveData$ = value[1][1]; // eslint-disable-line no-unused-vars\n\t\t\t\t\t\t\t\tvalue = eval(value[1][0]);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// For regular expressions, functions, and pre-v2.9.0 `JSON.reviveWrapper()`.\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tvalue = eval(value[1]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/* eslint-enable no-eval */\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* legacy */\n\t\t\t\telse if (typeof value === 'string' && value.slice(0, 10) === '@@revive@@') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvalue = eval(value.slice(10)); // eslint-disable-line no-eval\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t}\n\t\t\t\t/* /legacy */\n\n\t\t\t\t/*\n\t\t\t\t\tCall the custom reviver, if specified.\n\t\t\t\t*/\n\t\t\t\tif (typeof reviver === 'function') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvalue = reviver(key, value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t}\n\n\t\t\t\treturn value;\n\t\t\t});\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, Deprecated.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Returns whether the given element was found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'contains', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.contains called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns whether all of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'containsAll', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.containsAll called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includesAll.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns whether any of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'containsAny', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.containsAny called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includesAny.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns a new array consisting of the flattened source array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'flatten', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.flatten called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.flat.call(this, Infinity);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns an array of link titles, parsed from the string.\n\n\t\tNOTE: Unused in SugarCube, only included for compatibility.\n\t*/\n\tObject.defineProperty(String.prototype, 'readBracketedList', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.readBracketedList called on null or undefined');\n\t\t\t}\n\n\t\t\t// RegExp groups: Double-square-bracket quoted | Unquoted.\n\t\t\tconst re    = new RegExp('(?:\\\\[\\\\[((?:\\\\s|\\\\S)*?)\\\\]\\\\])|([^\"\\'\\\\s]\\\\S*)', 'gm');\n\t\t\tconst names = [];\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this)) !== null) {\n\t\t\t\tif (match[1]) { // double-square-bracket quoted\n\t\t\t\t\tnames.push(match[1]);\n\t\t\t\t}\n\t\t\t\telse if (match[2]) { // unquoted\n\t\t\t\t\tnames.push(match[2]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn names;\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/browser.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar Browser = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/* eslint-disable max-len */\n\tconst userAgent = navigator.userAgent.toLowerCase();\n\n\tconst winPhone = userAgent.includes('windows phone');\n\tconst isMobile = Object.freeze({\n\t\tAndroid    : !winPhone && userAgent.includes('android'),\n\t\tBlackBerry : /blackberry|bb10/.test(userAgent),\n\t\tiOS        : !winPhone && /ip(?:hone|ad|od)/.test(userAgent),\n\t\tOpera      : !winPhone && (typeof window.operamini === 'object' || userAgent.includes('opera mini')),\n\t\tWindows    : winPhone || /iemobile|wpdesktop/.test(userAgent),\n\n\t\tany() {\n\t\t\treturn isMobile.Android || isMobile.BlackBerry || isMobile.iOS || isMobile.Opera || isMobile.Windows;\n\t\t}\n\t});\n\n\tconst isGecko = !isMobile.Windows && !/khtml|trident|edge/.test(userAgent) && userAgent.includes('gecko');\n\n\tconst isIE      = !userAgent.includes('opera') && /msie|trident/.test(userAgent);\n\tconst ieVersion = isIE\n\t\t? (() => {\n\t\t\tconst ver = /(?:msie\\s+|rv:)(\\d+\\.\\d)/.exec(userAgent);\n\t\t\treturn ver ? Number(ver[1]) : 0;\n\t\t})()\n\t\t: null;\n\n\t// opera <= 12: \"opera/9.80 (windows nt 6.1; wow64) presto/2.12.388 version/12.16\"\n\t// opera >= 15: \"mozilla/5.0 (windows nt 6.1; wow64) applewebkit/537.36 (khtml, like gecko) chrome/28.0.1500.52 safari/537.36 opr/15.0.1147.130\"\n\tconst isOpera      = userAgent.includes('opera') || userAgent.includes(' opr/');\n\tconst operaVersion = isOpera\n\t\t? (() => {\n\t\t\tconst re  = new RegExp(`${/khtml|chrome/.test(userAgent) ? 'opr' : 'version'}\\\\/(\\\\d+\\\\.\\\\d+)`);\n\t\t\tconst ver = re.exec(userAgent);\n\t\t\treturn ver ? Number(ver[1]) : 0;\n\t\t})()\n\t\t: null;\n\n\tconst isVivaldi = userAgent.includes('vivaldi');\n\t/* eslint-enable max-len */\n\n\t// Module Exports.\n\treturn Object.freeze({\n\t\tuserAgent,\n\t\tisMobile,\n\t\tisGecko,\n\t\tisIE,\n\t\tieVersion,\n\t\tisOpera,\n\t\toperaVersion,\n\t\tisVivaldi\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/has.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser */\n\nvar Has = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tNOTE: The aggressive try/catch feature tests are necessitated by implementation\n\t\tbugs in various browsers.\n\t*/\n\n\t// Is the `HTMLAudioElement` API available?\n\tconst hasAudioElement = (() => {\n\t\ttry {\n\t\t\treturn typeof document.createElement('audio').canPlayType === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `File` API available?\n\tconst hasFile = (() => {\n\t\ttry {\n\t\t\treturn 'Blob' in window &&\n\t\t\t\t'File' in window &&\n\t\t\t\t'FileList' in window &&\n\t\t\t\t'FileReader' in window &&\n\t\t\t\t!Browser.isMobile.any() &&\n\t\t\t\t(!Browser.isOpera || Browser.operaVersion >= 15);\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `geolocation` API available?\n\tconst hasGeolocation = (() => {\n\t\ttry {\n\t\t\treturn 'geolocation' in navigator &&\n\t\t\t\ttypeof navigator.geolocation.getCurrentPosition === 'function' &&\n\t\t\t\ttypeof navigator.geolocation.watchPosition === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `MutationObserver` API available?\n\tconst hasMutationObserver = (() => {\n\t\ttry {\n\t\t\treturn 'MutationObserver' in window &&\n\t\t\t\ttypeof window.MutationObserver === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `performance` API available?\n\tconst hasPerformance = (() => {\n\t\ttry {\n\t\t\treturn 'performance' in window &&\n\t\t\t\ttypeof window.performance.now === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the platform a touch device?\n\tconst hasTouch = (() => {\n\t\ttry {\n\t\t\treturn 'ontouchstart' in window ||\n\t\t\t\t!!window.DocumentTouch &&\n\t\t\t\tdocument instanceof window.DocumentTouch ||\n\t\t\t\t!!navigator.maxTouchPoints ||\n\t\t\t\t!!navigator.msMaxTouchPoints;\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the transition end event available and by what name?\n\tconst hasTransitionEndEvent = (() => {\n\t\ttry {\n\t\t\tconst teMap = new Map([\n\t\t\t\t['transition',       'transitionend'],\n\t\t\t\t['MSTransition',     'msTransitionEnd'],\n\t\t\t\t['WebkitTransition', 'webkitTransitionEnd'],\n\t\t\t\t['MozTransition',    'transitionend']\n\t\t\t]);\n\t\t\tconst teKeys = [...teMap.keys()];\n\t\t\tconst el     = document.createElement('div');\n\n\t\t\tfor (let i = 0; i < teKeys.length; ++i) {\n\t\t\t\tif (el.style[teKeys[i]] !== undefined) {\n\t\t\t\t\treturn teMap.get(teKeys[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Module Exports.\n\treturn Object.freeze({\n\t\taudio              : hasAudioElement,\n\t\tfileAPI            : hasFile,\n\t\tgeolocation        : hasGeolocation,\n\t\tmutationObserver   : hasMutationObserver,\n\t\tperformance        : hasPerformance,\n\t\ttouch              : hasTouch,\n\t\ttransitionEndEvent : hasTransitionEndEvent\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/visibility.js\n\n\tCopyright © 2018–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar Visibility = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tThere are two versions of the Page Visibility API: First Edition and, the current,\n\t\tSecond Edition (i.e. \"Level 2\").  First Edition is mentioned here only because some\n\t\tolder browsers implement it, rather than the current specification.\n\n\t\tSEE:\n\t\t\tSecond Edition : https://www.w3.org/TR/page-visibility/\n\t\t\tFirst Edition  : https://www.w3.org/TR/2013/REC-page-visibility-20130514/\n\n\t\tNOTE: Generally, all supported browsers change the visibility state when either switching tabs\n\t\twithin the browser or minimizing the browser window.  Exceptions are noted below:\n\t\t\t* IE 9 doesn't support either version of the Page Visibility API.\n\t\t\t* Opera 12 (Presto) doesn't change the visibility state when the browser is minimized.\n\t*/\n\n\t// Vendor properties object.\n\tconst vendor = (() => {\n\t\ttry {\n\t\t\treturn Object.freeze([\n\t\t\t\t// Specification.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'hidden',          // boolean; historical in 2nd edition\n\t\t\t\t\tstateProperty  : 'visibilityState', // string, values: 'hidden', 'visible'; 1st edition had more values\n\t\t\t\t\tchangeEvent    : 'visibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `webkit` prefixed: old Blink & WebKit.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'webkitHidden',\n\t\t\t\t\tstateProperty  : 'webkitVisibilityState',\n\t\t\t\t\tchangeEvent    : 'webkitvisibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `moz` prefixed: old Gecko, maybe Seamonkey.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'mozHidden',\n\t\t\t\t\tstateProperty  : 'mozVisibilityState',\n\t\t\t\t\tchangeEvent    : 'mozvisibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `ms` prefixed: IE 10.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'msHidden',\n\t\t\t\t\tstateProperty  : 'msVisibilityState',\n\t\t\t\t\tchangeEvent    : 'msvisibilitychange'\n\t\t\t\t}\n\t\t\t].find(vnd => vnd.hiddenProperty in document));\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn undefined;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tAPI Functions.\n\t*******************************************************************************/\n\n\tfunction getVendor() {\n\t\treturn vendor;\n\t}\n\n\tfunction getVisibility() {\n\t\treturn vendor && document[vendor.stateProperty] || 'visible';\n\t}\n\n\tfunction isEnabled() {\n\t\treturn Boolean(vendor);\n\t}\n\n\tfunction isHidden() {\n\t\t// return Boolean(vendor && document[vendor.stateProperty] === 'hidden');\n\t\treturn Boolean(vendor && document[vendor.hiddenProperty]); // NOTE: Historical, but probably better for 1st edition.\n\t}\n\n\n\t/*******************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Functions.\n\t\tvendor    : { get : getVendor },\n\t\tstate     : { get : getVisibility },\n\t\tisEnabled : { value : isEnabled },\n\t\tisHidden  : { value : isHidden },\n\n\t\t// Properties.\n\t\thiddenProperty : { value : vendor && vendor.hiddenProperty },\n\t\tstateProperty  : { value : vendor && vendor.stateProperty },\n\t\tchangeEvent    : { value : vendor && vendor.changeEvent }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/fullscreen.js\n\n\tCopyright © 2018–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser */\n\nvar Fullscreen = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tSEE:\n\t\t\thttps://fullscreen.spec.whatwg.org\n\t\t\thttps://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API\n\t*/\n\n\t// Vendor properties object.\n\tconst vendor = (() => {\n\t\ttry {\n\t\t\treturn Object.freeze([\n\t\t\t\t// Specification.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'fullscreenEnabled',\n\t\t\t\t\telement     : 'fullscreenElement',\n\t\t\t\t\trequestFn   : 'requestFullscreen',\n\t\t\t\t\texitFn      : 'exitFullscreen',\n\t\t\t\t\tchangeEvent : 'fullscreenchange', // prop: onfullscreenchange\n\t\t\t\t\terrorEvent  : 'fullscreenerror'   // prop: onfullscreenerror\n\t\t\t\t},\n\n\t\t\t\t// `webkit` prefixed: old Blink, WebKit, & Edge.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'webkitFullscreenEnabled',\n\t\t\t\t\telement     : 'webkitFullscreenElement',\n\t\t\t\t\trequestFn   : 'webkitRequestFullscreen',\n\t\t\t\t\texitFn      : 'webkitExitFullscreen',\n\t\t\t\t\tchangeEvent : 'webkitfullscreenchange',\n\t\t\t\t\terrorEvent  : 'webkitfullscreenerror'\n\t\t\t\t},\n\n\t\t\t\t// `moz` prefixed: old Gecko, maybe Seamonkey.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'mozFullScreenEnabled',\n\t\t\t\t\telement     : 'mozFullScreenElement',\n\t\t\t\t\trequestFn   : 'mozRequestFullScreen',\n\t\t\t\t\texitFn      : 'mozCancelFullScreen',\n\t\t\t\t\tchangeEvent : 'mozfullscreenchange',\n\t\t\t\t\terrorEvent  : 'mozfullscreenerror'\n\t\t\t\t},\n\n\t\t\t\t// `ms` prefixed: IE 11.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'msFullscreenEnabled',\n\t\t\t\t\telement     : 'msFullscreenElement',\n\t\t\t\t\trequestFn   : 'msRequestFullscreen',\n\t\t\t\t\texitFn      : 'msExitFullscreen',\n\t\t\t\t\tchangeEvent : 'MSFullscreenChange',\n\t\t\t\t\terrorEvent  : 'MSFullscreenError'\n\t\t\t\t}\n\t\t\t].find(vnd => vnd.isEnabled in document));\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn undefined;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tFeature Detection Functions.\n\t*******************************************************************************/\n\n\t// Return whether the request and exit fullscreen methods return a `Promise`.\n\t//\n\t// NOTE: The initial result is cached for future calls.\n\tconst _returnsPromise = (function () {\n\t\t// Cache of whether the request and exit methods return a `Promise`.\n\t\tlet _hasPromise = null;\n\n\t\tfunction _returnsPromise() {\n\t\t\tif (_hasPromise !== null) {\n\t\t\t\treturn _hasPromise;\n\t\t\t}\n\n\t\t\t_hasPromise = false;\n\n\t\t\tif (vendor) {\n\t\t\t\ttry {\n\t\t\t\t\tconst value = document.exitFullscreen();\n\n\t\t\t\t\t// Silence \"Uncaught (in promise)\" console errors from Blink.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: Swallowing errors is generally bad, but in this case we know there's\n\t\t\t\t\t// going to be an error regardless, since we shouldn't be in fullscreen yet,\n\t\t\t\t\t// and we don't actually care about the error, since we just want the return\n\t\t\t\t\t// value, so we consign it to the bit bucket.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: We don't ensure that the return value is not `undefined` here because\n\t\t\t\t\t// having the attempted call to `<Promise>.catch()` on an `undefined` value throw\n\t\t\t\t\t// is acceptable, since it will be caught and `false` eventually returned.\n\t\t\t\t\tvalue.catch(() => { /* no-op */ });\n\n\t\t\t\t\t_hasPromise = value instanceof Promise;\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t}\n\n\t\t\treturn _hasPromise;\n\t\t}\n\n\t\treturn _returnsPromise;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************/\n\n\tfunction _selectElement(requestedEl) {\n\t\tlet selectedEl = requestedEl || document.documentElement;\n\n\t\t// Document element scrolling workaround for older browsers.\n\t\tif (\n\t\t\t   selectedEl === document.documentElement\n\t\t\t&& (\n\t\t\t\t   vendor.requestFn === 'msRequestFullscreen'   // IE 11\n\t\t\t\t|| Browser.isOpera && Browser.operaVersion < 15 // Opera 12 (Presto)\n\t\t\t)\n\t\t) {\n\t\t\tselectedEl = document.body;\n\t\t}\n\n\t\treturn selectedEl;\n\t}\n\n\n\t/*******************************************************************************\n\t\tAPI Functions.\n\t*******************************************************************************/\n\n\tfunction getVendor() {\n\t\treturn vendor;\n\t}\n\n\tfunction getElement() {\n\t\treturn (vendor || null) && document[vendor.element];\n\t}\n\n\tfunction isEnabled() {\n\t\treturn Boolean(vendor && document[vendor.isEnabled]);\n\t}\n\n\tfunction isFullscreen() {\n\t\treturn Boolean(vendor && document[vendor.element]);\n\t}\n\n\tfunction requestFullscreen(options, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn Promise.reject(new Error('fullscreen not supported'));\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (typeof element[vendor.requestFn] !== 'function') {\n\t\t\treturn Promise.reject(new Error('fullscreen not supported'));\n\t\t}\n\t\tif (isFullscreen()) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tif (_returnsPromise()) {\n\t\t\treturn element[vendor.requestFn](options);\n\t\t}\n\t\telse { // eslint-disable-line no-else-return\n\t\t\tconst namespace = '.Fullscreen_requestFullscreen';\n\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tjQuery(element)\n\t\t\t\t\t.off(namespace)\n\t\t\t\t\t.one(`${vendor.errorEvent}${namespace} ${vendor.changeEvent}${namespace}`, ev => {\n\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\tif (ev.type === vendor.errorEvent) {\n\t\t\t\t\t\t\treject(new Error('unknown fullscreen request error'));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\telement[vendor.requestFn](options);\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction exitFullscreen() {\n\t\tif (!vendor || typeof document[vendor.exitFn] !== 'function') {\n\t\t\treturn Promise.reject(new TypeError('fullscreen not supported'));\n\t\t}\n\t\tif (!isFullscreen()) {\n\t\t\treturn Promise.reject(new TypeError('fullscreen mode not active'));\n\t\t}\n\n\t\tif (_returnsPromise()) {\n\t\t\treturn document[vendor.exitFn]();\n\t\t}\n\t\telse { // eslint-disable-line no-else-return\n\t\t\tconst namespace = '.Fullscreen_exitFullscreen';\n\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tjQuery(document)\n\t\t\t\t\t.off(namespace)\n\t\t\t\t\t.one(`${vendor.errorEvent}${namespace} ${vendor.changeEvent}${namespace}`, ev => {\n\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\tif (ev.type === vendor.errorEvent) {\n\t\t\t\t\t\t\treject(new Error('unknown fullscreen exit error'));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tdocument[vendor.exitFn]();\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction toggleFullscreen(options, requestedEl) {\n\t\treturn isFullscreen() ? exitFullscreen() : requestFullscreen(options, requestedEl);\n\t}\n\n\tfunction onChange(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\t$(element).on(vendor.changeEvent, handlerFn);\n\t}\n\n\tfunction offChange(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (handlerFn) {\n\t\t\t$(element).off(vendor.changeEvent, handlerFn);\n\t\t}\n\t\telse {\n\t\t\t$(element).off(vendor.changeEvent);\n\t\t}\n\t}\n\n\tfunction onError(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\t$(element).on(vendor.errorEvent, handlerFn);\n\t}\n\n\tfunction offError(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (handlerFn) {\n\t\t\t$(element).off(vendor.errorEvent, handlerFn);\n\t\t}\n\t\telse {\n\t\t\t$(element).off(vendor.errorEvent);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tvendor       : { get : getVendor },\n\t\telement      : { get : getElement },\n\t\tisEnabled    : { value : isEnabled },\n\t\tisFullscreen : { value : isFullscreen },\n\t\trequest      : { value : requestFullscreen },\n\t\texit         : { value : exitFullscreen },\n\t\ttoggle       : { value : toggleFullscreen },\n\t\tonChange     : { value : onChange },\n\t\toffChange    : { value : offChange },\n\t\tonError      : { value : onError },\n\t\toffError     : { value : offError }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/helpers.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, L10n, State, Story, Util, Wikifier */\n\nvar { // eslint-disable-line no-var\n\t/* eslint-disable no-unused-vars */\n\tclone,\n\tconvertBreaks,\n\tsafeActiveElement,\n\tsetDisplayTitle,\n\tsetPageElement,\n\tthrowError,\n\ttoStringOrDefault\n\t/* eslint-enable no-unused-vars */\n} = (() => {\n\t'use strict';\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _getTextContent(source) {\n\t\tconst copy = source.cloneNode(true);\n\t\tconst frag = document.createDocumentFragment();\n\t\tlet node;\n\n\t\twhile ((node = copy.firstChild) !== null) {\n\t\t\t// Insert spaces before various elements.\n\t\t\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tswitch (node.nodeName.toUpperCase()) {\n\t\t\t\tcase 'BR':\n\t\t\t\tcase 'DIV':\n\t\t\t\tcase 'P':\n\t\t\t\t\tfrag.appendChild(document.createTextNode(' '));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfrag.appendChild(node);\n\t\t}\n\n\t\treturn frag.textContent;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tHelper Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a deep copy of the given object.\n\n\t\tNOTE:\n\t\t\t1. `clone()` does not clone functions, however, since function definitions\n\t\t\t   are immutable, the only issues are with expando properties and scope.\n\t\t\t   The former really should not be done.  The latter is problematic either\n\t\t\t   way—damned if you do, damned if you don't.\n\t\t\t2. `clone()` does not maintain referential relationships—e.g. multiple\n\t\t\t   references to the same object will, post-cloning, refer to different\n\t\t\t   equivalent objects; i.e. each reference will receive its own clone\n\t\t\t   of the original object.\n\t*/\n\tfunction clone(orig) {\n\t\t/*\n\t\t\tImmediately return the primitives and functions.\n\t\t*/\n\t\tif (typeof orig !== 'object' || orig === null) {\n\t\t\treturn orig;\n\t\t}\n\n\t\t/*\n\t\t\tUnbox instances of the primitive exemplar objects.\n\t\t*/\n\t\tif (orig instanceof String) {\n\t\t\treturn String(orig);\n\t\t}\n\t\tif (orig instanceof Number) {\n\t\t\treturn Number(orig);\n\t\t}\n\t\tif (orig instanceof Boolean) {\n\t\t\treturn Boolean(orig);\n\t\t}\n\n\t\t/*\n\t\t\tHonor native clone methods.\n\t\t*/\n\t\tif (typeof orig.clone === 'function') {\n\t\t\treturn orig.clone(true);\n\t\t}\n\t\tif (orig.nodeType && typeof orig.cloneNode === 'function') {\n\t\t\treturn orig.cloneNode(true);\n\t\t}\n\n\t\t/*\n\t\t\tCreate a copy of the original object.\n\n\t\t\tNOTE: Each non-generic object that we wish to support must be\n\t\t\texplicitly handled below.\n\t\t*/\n\t\tlet copy;\n\n\t\t// Handle instances of the core supported object types.\n\t\tif (orig instanceof Array) {\n\t\t\tcopy = new Array(orig.length);\n\t\t}\n\t\telse if (orig instanceof Date) {\n\t\t\tcopy = new Date(orig.getTime());\n\t\t}\n\t\telse if (orig instanceof Map) {\n\t\t\tcopy = new Map();\n\t\t\torig.forEach((val, key) => copy.set(key, clone(val)));\n\t\t}\n\t\telse if (orig instanceof RegExp) {\n\t\t\tcopy = new RegExp(orig);\n\t\t}\n\t\telse if (orig instanceof Set) {\n\t\t\tcopy = new Set();\n\t\t\torig.forEach(val => copy.add(clone(val)));\n\t\t}\n\n\t\t// Handle instances of unknown or generic objects.\n\t\telse {\n\t\t\t// We try to ensure that the returned copy has the same prototype as\n\t\t\t// the original, but this will probably produce less than satisfactory\n\t\t\t// results on non-generics.\n\t\t\tcopy = Object.create(Object.getPrototypeOf(orig));\n\t\t}\n\n\t\t/*\n\t\t\tDuplicate the original object's own enumerable properties, which will\n\t\t\tinclude expando properties on non-generic objects.\n\n\t\t\tNOTE: This preserves neither symbol properties nor ES5 property attributes.\n\t\t\tNeither does the delta coding or serialization code, however, so it's not\n\t\t\treally an issue at the moment.\n\t\t*/\n\t\tObject.keys(orig).forEach(name => copy[name] = clone(orig[name]));\n\n\t\treturn copy;\n\t}\n\n\t/*\n\t\tConverts <br> elements to <p> elements within the given node tree.\n\t*/\n\tfunction convertBreaks(source) {\n\t\tconst output = document.createDocumentFragment();\n\t\tlet para = document.createElement('p');\n\t\tlet node;\n\n\t\twhile ((node = source.firstChild) !== null) {\n\t\t\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tconst tagName = node.nodeName.toUpperCase();\n\n\t\t\t\tswitch (tagName) {\n\t\t\t\tcase 'BR':\n\t\t\t\t\tif (\n\t\t\t\t\t\t   node.nextSibling !== null\n\t\t\t\t\t\t&& node.nextSibling.nodeType === Node.ELEMENT_NODE\n\t\t\t\t\t\t&& node.nextSibling.nodeName.toUpperCase() === 'BR'\n\t\t\t\t\t) {\n\t\t\t\t\t\tsource.removeChild(node.nextSibling);\n\t\t\t\t\t\tsource.removeChild(node);\n\t\t\t\t\t\toutput.appendChild(para);\n\t\t\t\t\t\tpara = document.createElement('p');\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\telse if (!para.hasChildNodes()) {\n\t\t\t\t\t\tsource.removeChild(node);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'ADDRESS':\n\t\t\t\tcase 'ARTICLE':\n\t\t\t\tcase 'ASIDE':\n\t\t\t\tcase 'BLOCKQUOTE':\n\t\t\t\tcase 'CENTER':\n\t\t\t\tcase 'DIV':\n\t\t\t\tcase 'DL':\n\t\t\t\tcase 'FIGURE':\n\t\t\t\tcase 'FOOTER':\n\t\t\t\tcase 'FORM':\n\t\t\t\tcase 'H1':\n\t\t\t\tcase 'H2':\n\t\t\t\tcase 'H3':\n\t\t\t\tcase 'H4':\n\t\t\t\tcase 'H5':\n\t\t\t\tcase 'H6':\n\t\t\t\tcase 'HEADER':\n\t\t\t\tcase 'HR':\n\t\t\t\tcase 'MAIN':\n\t\t\t\tcase 'NAV':\n\t\t\t\tcase 'OL':\n\t\t\t\tcase 'P':\n\t\t\t\tcase 'PRE':\n\t\t\t\tcase 'SECTION':\n\t\t\t\tcase 'TABLE':\n\t\t\t\tcase 'UL':\n\t\t\t\t\tif (para.hasChildNodes()) {\n\t\t\t\t\t\toutput.appendChild(para);\n\t\t\t\t\t\tpara = document.createElement('p');\n\t\t\t\t\t}\n\n\t\t\t\t\toutput.appendChild(node);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpara.appendChild(node);\n\t\t}\n\n\t\tif (para.hasChildNodes()) {\n\t\t\toutput.appendChild(para);\n\t\t}\n\n\t\tsource.appendChild(output);\n\t}\n\n\t/*\n\t\tReturns `document.activeElement` or `null`.\n\t*/\n\tfunction safeActiveElement() {\n\t\t/*\n\t\t\tIE9 contains a bug where trying to access the active element of an iframe's\n\t\t\tparent document (i.e. `window.parent.document.activeElement`) will throw an\n\t\t\texception, so we must allow for an exception to be thrown.\n\n\t\t\tWe could simply return `undefined` here, but since the API's default behavior\n\t\t\tshould be to return `document.body` or `null` when there is no selection, we\n\t\t\tchoose to return `null` in all non-element cases (i.e. whether it returns\n\t\t\t`null` or throws an exception).  Just a bit of normalization.\n\t\t*/\n\t\ttry {\n\t\t\treturn document.activeElement || null;\n\t\t}\n\t\tcatch (ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/*\n\t\tSets the display title.\n\t*/\n\tfunction setDisplayTitle(title) {\n\t\tif (typeof title !== 'string') {\n\t\t\tthrow new TypeError(`story display title must be a string (received: ${Util.getType(title)})`);\n\t\t}\n\n\t\tconst render = document.createDocumentFragment();\n\t\tnew Wikifier(render, title);\n\n\t\tconst text = _getTextContent(render).trim();\n\n\t\t// if (text === '') {\n\t\t// \tthrow new Error('story display title must not render to an empty string or consist solely of whitespace');\n\t\t// }\n\n\t\tdocument.title = Config.passages.displayTitles && State.passage !== '' && State.passage !== Config.passages.start\n\t\t\t? `${State.passage} | ${text}`\n\t\t\t: text;\n\n\t\tconst storyTitle = document.getElementById('story-title');\n\n\t\tif (storyTitle !== null) {\n\t\t\tjQuery(storyTitle).empty().append(render);\n\t\t}\n\t}\n\n\t/*\n\t\tWikifies a passage into a DOM element corresponding to the passed ID and returns the element.\n\t*/\n\tfunction setPageElement(idOrElement, titles, defaultText) {\n\t\tconst el = typeof idOrElement === 'object'\n\t\t\t? idOrElement\n\t\t\t: document.getElementById(idOrElement);\n\n\t\tif (el == null) { // lazy equality for null\n\t\t\treturn null;\n\t\t}\n\n\t\tconst ids = Array.isArray(titles) ? titles : [titles];\n\n\t\tjQuery(el).empty();\n\n\t\tfor (let i = 0, iend = ids.length; i < iend; ++i) {\n\t\t\tif (Story.has(ids[i])) {\n\t\t\t\tnew Wikifier(el, Story.get(ids[i]).processText().trim());\n\t\t\t\treturn el;\n\t\t\t}\n\t\t}\n\n\t\tif (defaultText != null) { // lazy equality for null\n\t\t\tconst text = String(defaultText).trim();\n\n\t\t\tif (text !== '') {\n\t\t\t\tnew Wikifier(el, text);\n\t\t\t}\n\t\t}\n\n\t\treturn el;\n\t}\n\n\t/*\n\t\tAppends an error view to the passed DOM element.\n\t*/\n\tfunction throwError(place, message, source, stack) {\n\t\tconst $wrapper = jQuery(document.createElement('div'));\n\t\tconst $toggle  = jQuery(document.createElement('button'));\n\t\tconst $source  = jQuery(document.createElement('pre'));\n\t\tconst mesg     = `${L10n.get('errorTitle')}: ${message || 'unknown error'}`;\n\n\t\t$toggle\n\t\t\t.addClass('error-toggle')\n\t\t\t.ariaClick({\n\t\t\t\tlabel : L10n.get('errorToggle')\n\t\t\t}, () => {\n\t\t\t\tif ($toggle.hasClass('enabled')) {\n\t\t\t\t\t$toggle.removeClass('enabled');\n\t\t\t\t\t$source.attr({\n\t\t\t\t\t\t'aria-hidden' : true,\n\t\t\t\t\t\thidden        : 'hidden'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$toggle.addClass('enabled');\n\t\t\t\t\t$source.removeAttr('aria-hidden hidden');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.appendTo($wrapper);\n\t\tjQuery(document.createElement('span'))\n\t\t\t.addClass('error')\n\t\t\t.text(mesg)\n\t\t\t.appendTo($wrapper);\n\t\tjQuery(document.createElement('code'))\n\t\t\t.text(source)\n\t\t\t.appendTo($source);\n\t\t$source\n\t\t\t.addClass('error-source')\n\t\t\t.attr({\n\t\t\t\t'aria-hidden' : true,\n\t\t\t\thidden        : 'hidden'\n\t\t\t})\n\t\t\t.appendTo($wrapper);\n\t\tif (stack) {\n\t\t\tconst lines = stack.split('\\n');\n\t\t\tfor (const ll of lines) {\n\t\t\t\tconst div = document.createElement('div');\n\t\t\t\tdiv.append(ll.replace(/file:.*\\//, '<path>/'));\n\t\t\t\t$source.append(div);\n\t\t\t}\n\t\t}\n\t\t$wrapper\n\t\t\t.addClass('error-view')\n\t\t\t.appendTo(place);\n\n\t\tconsole.warn(`${mesg}\\n\\t${source.replace(/\\n/g, '\\n\\t')}`);\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tReturns the simple string representation of the passed value or, if there is none,\n\t\tthe passed default value.\n\t*/\n\tfunction toStringOrDefault(value, defValue) {\n\t\tconst tSOD = toStringOrDefault;\n\n\t\tswitch (typeof value) {\n\t\tcase 'number':\n\t\t\t// TODO: Perhaps NaN should be printed instead?\n\t\t\tif (Number.isNaN(value)) {\n\t\t\t\treturn defValue;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\tif (value === null) {\n\t\t\t\treturn defValue;\n\t\t\t}\n\t\t\telse if (Array.isArray(value)) {\n\t\t\t\treturn value.map(val => tSOD(val, defValue)).join(', ');\n\t\t\t}\n\t\t\telse if (value instanceof Set) {\n\t\t\t\treturn [...value].map(val => tSOD(val, defValue)).join(', ');\n\t\t\t}\n\t\t\telse if (value instanceof Map) {\n\t\t\t\tconst result = [...value].map(([key, val]) => `${tSOD(key, defValue)} \\u2192 ${tSOD(val, defValue)}`);\n\t\t\t\treturn `{\\u202F${result.join(', ')}\\u202F}`;\n\t\t\t}\n\t\t\telse if (value instanceof Date) {\n\t\t\t\treturn value.toLocaleString();\n\t\t\t}\n\t\t\telse if (typeof value.toString === 'function') {\n\t\t\t\treturn value.toString();\n\t\t\t}\n\t\t\treturn Object.prototype.toString.call(value);\n\n\t\tcase 'function':\n\t\tcase 'undefined':\n\t\t\treturn defValue;\n\t\t}\n\n\t\treturn String(value);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tclone             : { value : clone },\n\t\tconvertBreaks     : { value : convertBreaks },\n\t\tsafeActiveElement : { value : safeActiveElement },\n\t\tsetDisplayTitle   : { value : setDisplayTitle },\n\t\tsetPageElement    : { value : setPageElement },\n\t\tthrowError        : { value : throwError },\n\t\ttoStringOrDefault : { value : toStringOrDefault }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/jquery-plugins.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Wikifier, errorPrologRegExp, safeActiveElement */\n\n/*\n\tWAI-ARIA methods plugin.\n\n\t`<jQuery>.ariaClick([options,] handler)`\n\t    Makes the target element(s) WAI-ARIA compatible clickables.\n\n\t`<jQuery>.ariaDisabled(state)`\n\t    Changes the disabled state of the target WAI-ARIA-compatible clickable element(s).\n\n\t`<jQuery>.ariaIsDisabled()`\n\t    Checks the disabled status of the target WAI-ARIA-compatible clickable element(s).\n*/\n(() => {\n\t'use strict';\n\n\t/*\n\t\tEvent handler & utility functions.\n\n\t\tNOTE: Do not replace the anonymous functions herein with arrow functions.\n\t*/\n\tfunction onKeypressFn(ev) {\n\t\t// 13 is Enter/Return, 32 is Space.\n\t\tif (ev.which === 13 || ev.which === 32) {\n\t\t\tev.preventDefault();\n\n\t\t\t// To allow delegation, attempt to trigger the event on `document.activeElement`,\n\t\t\t// if possible, elsewise on `this`.\n\t\t\tjQuery(safeActiveElement() || this).trigger('click');\n\t\t}\n\t}\n\n\tfunction onClickFnWrapper(fn) {\n\t\treturn function () {\n\t\t\tconst $this = jQuery(this);\n\n\t\t\tconst dataPassage = $this.attr('data-passage');\n\t\t\tconst initialDataPassage = window && window.SugarCube && window.SugarCube.State && window.SugarCube.State.passage;\n\t\t\tconst savedYOffset = window.pageYOffset;\n\n\t\t\t// Toggle \"aria-pressed\" status, if the attribute exists.\n\t\t\tif ($this.is('[aria-pressed]')) {\n\t\t\t\t$this.attr('aria-pressed', $this.attr('aria-pressed') === 'true' ? 'false' : 'true');\n\t\t\t}\n\n\t\t\t// Call the true handler.\n\t\t\tfn.apply(this, arguments);\n\n\t\t\tconst doJump = function(){ window.scrollTo(0, savedYOffset); }\n\t\t\tif ( dataPassage && (window.lastDataPassageLink === dataPassage || initialDataPassage === dataPassage))\n\t\t\t\tdoJump();\n\t\t\twindow.lastDataPassageLink = dataPassage;\n\t\t};\n\t}\n\n\tfunction oneClickFnWrapper(fn) {\n\t\treturn onClickFnWrapper(function () {\n\t\t\t// Remove both event handlers (keypress & click) and the other components.\n\t\t\tjQuery(this)\n\t\t\t\t.off('.aria-clickable')\n\t\t\t\t.removeAttr('tabindex aria-controls aria-pressed')\n\t\t\t\t.not('a,button')\n\t\t\t\t.removeAttr('role')\n\t\t\t\t.end()\n\t\t\t\t.filter('button')\n\t\t\t\t.prop('disabled', true);\n\n\t\t\t// Call the true handler.\n\t\t\tfn.apply(this, arguments);\n\t\t});\n\t}\n\n\tjQuery.fn.extend({\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaClick()` method.\n\t\t*/\n\t\tariaClick(options, handler) {\n\t\t\t// Bail out if there are no target element(s) or parameters.\n\t\t\tif (this.length === 0 || arguments.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tlet opts = options;\n\t\t\tlet fn   = handler;\n\n\t\t\tif (fn == null) { // lazy equality for null\n\t\t\t\tfn   = opts;\n\t\t\t\topts = undefined;\n\t\t\t}\n\n\t\t\topts = jQuery.extend({\n\t\t\t\tnamespace : undefined,\n\t\t\t\tone       : false,\n\t\t\t\tselector  : undefined,\n\t\t\t\tdata      : undefined,\n\t\t\t\tcontrols  : undefined,\n\t\t\t\tpressed   : undefined,\n\t\t\t\tlabel     : undefined\n\t\t\t}, opts);\n\n\t\t\tif (typeof opts.namespace !== 'string') {\n\t\t\t\topts.namespace = '';\n\t\t\t}\n\t\t\telse if (opts.namespace[0] !== '.') {\n\t\t\t\topts.namespace = `.${opts.namespace}`;\n\t\t\t}\n\n\t\t\tif (typeof opts.pressed === 'boolean') {\n\t\t\t\topts.pressed = opts.pressed ? 'true' : 'false';\n\t\t\t}\n\n\t\t\t// Set `type` to `button` to suppress \"submit\" semantics, for <button> elements.\n\t\t\tthis.filter('button').prop('type', 'button');\n\n\t\t\t// Set `role` to `button`, for non-<a>/-<button> elements.\n\t\t\tthis.not('a,button').attr('role', 'button');\n\n\t\t\t// Set `tabindex` to `0` to make them focusable (unnecessary on <button> elements, but it doesn't hurt).\n\t\t\tthis.attr('tabindex', 0);\n\n\t\t\t// Set `aria-controls`.\n\t\t\tif (opts.controls != null) { // lazy equality for null\n\t\t\t\tthis.attr('aria-controls', opts.controls);\n\t\t\t}\n\n\t\t\t// Set `aria-pressed`.\n\t\t\tif (opts.pressed != null) { // lazy equality for null\n\t\t\t\tthis.attr('aria-pressed', opts.pressed);\n\t\t\t}\n\n\t\t\t// Set `aria-label` and `title`.\n\t\t\tif (opts.label != null) { // lazy equality for null\n\t\t\t\tthis.attr({\n\t\t\t\t\t'aria-label' : opts.label,\n\t\t\t\t\ttitle        : opts.label\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Set the keypress handlers, for non-<button> elements.\n\t\t\t// NOTE: For the single-use case, the click handler will also remove this handler.\n\t\t\tthis.not('button').on(\n\t\t\t\t`keypress.aria-clickable${opts.namespace}`,\n\t\t\t\topts.selector,\n\t\t\t\tonKeypressFn\n\t\t\t);\n\n\t\t\t// Set the click handlers.\n\t\t\t// NOTE: To ensure both handlers are properly removed, `one()` must not be used here.\n\t\t\tthis.on(\n\t\t\t\t`click.aria-clickable${opts.namespace}`,\n\t\t\t\topts.selector,\n\t\t\t\topts.data,\n\t\t\t\topts.one ? oneClickFnWrapper(fn) : onClickFnWrapper(fn)\n\t\t\t);\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaDisabled()` method.\n\t\t*/\n\t\tariaDisabled(disable) {\n\t\t\t// Bail out if there are no target element(s) or parameters.\n\t\t\tif (this.length === 0 || arguments.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tNOTE: We use `<jQuery>.each()` callbacks to invoke the `<Element>.setAttribute()`\n\t\t\t\tmethods in the following because the `<jQuery>.attr()` method does not allow you\n\t\t\t\tto set a content attribute without a value, which is recommended for boolean\n\t\t\t\tcontent attributes by the HTML specification.\n\t\t\t*/\n\n\t\t\tconst $nonDisableable = this.not('button,fieldset,input,menuitem,optgroup,option,select,textarea');\n\t\t\tconst $disableable    = this.filter('button,fieldset,input,menuitem,optgroup,option,select,textarea');\n\n\t\t\tif (disable) {\n\t\t\t\t// Add boolean content attribute `disabled` and set non-boolean content attribute\n\t\t\t\t// `aria-disabled` to `'true'`, for non-disableable elements.\n\t\t\t\t$nonDisableable.each(function () {\n\t\t\t\t\tthis.setAttribute('disabled', '');\n\t\t\t\t\tthis.setAttribute('aria-disabled', 'true');\n\t\t\t\t});\n\n\t\t\t\t// Set IDL attribute `disabled` to `true` and set non-boolean content attribute\n\t\t\t\t// `aria-disabled` to `'true'`, for disableable elements.\n\t\t\t\t$disableable.each(function () {\n\t\t\t\t\tthis.disabled = true;\n\t\t\t\t\tthis.setAttribute('aria-disabled', 'true');\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Remove content attributes `disabled` and `aria-disabled`, for non-disableable elements.\n\t\t\t\t$nonDisableable.each(function () {\n\t\t\t\t\tthis.removeAttribute('disabled');\n\t\t\t\t\tthis.removeAttribute('aria-disabled');\n\t\t\t\t});\n\n\t\t\t\t// Set IDL attribute `disabled` to `false` and remove content attribute `aria-disabled`,\n\t\t\t\t// for disableable elements.\n\t\t\t\t$disableable.each(function () {\n\t\t\t\t\tthis.disabled = false;\n\t\t\t\t\tthis.removeAttribute('aria-disabled');\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaIsDisabled()` method.\n\t\t*/\n\t\tariaIsDisabled() {\n\t\t\t// Check content attribute `disabled`.\n\t\t\t//\n\t\t\t// NOTE: We simply check the `disabled` content attribute for all elements\n\t\t\t// since we have to check it for non-disableable elements and it may also\n\t\t\t// be used for disableable elements since their `disabled` IDL attribute\n\t\t\t// is required to reflect the status of their `disabled` content attribute,\n\t\t\t// and vice versa, by the HTML specification.\n\t\t\t// return this.toArray().some(el => el.hasAttribute('disabled'));\n\t\t\treturn this.is('[disabled]');\n\t\t}\n\t});\n})();\n\n/*\n\tWikifier methods plugin.\n\n\t`jQuery.wikiWithOptions(options, sources…)`\n\t    Wikifies the given content source(s), as directed by the given options.\n\n\t`jQuery.wiki(sources…)`\n\t    Wikifies the given content source(s).\n\n\t`<jQuery>.wikiWithOptions(options, sources…)`\n\t    Wikifies the given content source(s) and appends the result to the target\n\t    element(s), as directed by the given options.\n\n\t`<jQuery>.wiki(sources…)`\n\t    Wikifies the given content source(s) and appends the result to the target\n\t    element(s).\n*/\n(() => {\n\t'use strict';\n\n\tjQuery.extend({\n\t\t/*\n\t\t\tExtend jQuery's static methods with a `wikiWithOptions()` method.\n\t\t*/\n\t\twikiWithOptions(options, ...sources) {\n\t\t\t// Bail out, if there are no content sources.\n\t\t\tif (sources.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Wikify the content sources into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tsources.forEach(content => new Wikifier(frag, content, options));\n\n\t\t\t// Gather the text of any error elements within the fragment…\n\t\t\tconst errors = [...frag.querySelectorAll('.error')]\n\t\t\t\t.map(errEl => errEl.textContent.replace(errorPrologRegExp, ''));\n\n\t\t\t// …and throw an exception, if there were any errors.\n\t\t\tif (errors.length > 0) {\n\t\t\t\tthrow new Error(errors.join('; '));\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's static methods with a `wiki()` method.\n\t\t*/\n\t\twiki(...sources) {\n\t\t\tthis.wikiWithOptions(undefined, ...sources);\n\t\t}\n\t});\n\n\tjQuery.fn.extend({\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with a `wikiWithOptions()` method.\n\t\t*/\n\t\twikiWithOptions(options, ...sources) {\n\t\t\t// Bail out if there are no target element(s) or content sources.\n\t\t\tif (this.length === 0 || sources.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t// Wikify the content sources into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tsources.forEach(content => new Wikifier(frag, content, options));\n\n\t\t\t// Append the fragment to the target element(s).\n\t\t\tthis.append(frag);\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with a `wiki()` method.\n\t\t*/\n\t\twiki(...sources) {\n\t\t\treturn this.wikiWithOptions(undefined, ...sources);\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/util.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Has, Scripting */\n\nvar Util = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tType Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the value yielded by `typeof` (for primitives), the `@@toStringTag`\n\t\tinternal property (for objects), and `'null'` for `null`.\n\n\t\tNOTE: In ≤ES5, returns the value of the `[[Class]]` internal slot for objects.\n\t*/\n\tfunction utilGetType(obj) {\n\t\tif (obj === null) { return 'null'; }\n\n\t\tconst baseType = typeof obj;\n\t\treturn baseType === 'object'\n\t\t\t? Object.prototype.toString.call(obj).slice(8, -1)\n\t\t\t: baseType;\n\t}\n\n\t/*\n\t\tReturns whether the passed value is a boolean or one of the strings \"true\"\n\t\tor \"false\".\n\t*/\n\tfunction utilIsBoolean(obj) {\n\t\treturn typeof obj === 'boolean' || typeof obj === 'string' && (obj === 'true' || obj === 'false');\n\t}\n\n\t/*\n\t\tReturns whether the passed value is iterable.\n\t*/\n\tfunction utilIsIterable(obj) {\n\t\treturn obj != null && typeof obj[Symbol.iterator] === 'function'; // lazy equality for null\n\t}\n\n\t/*\n\t\tReturns whether the passed value is a finite number or a numeric string which\n\t\tyields a finite number when parsed.\n\t*/\n\tfunction utilIsNumeric(obj) {\n\t\tlet num;\n\n\t\tswitch (typeof obj) {\n\t\tcase 'number':\n\t\t\tnum = obj;\n\t\t\tbreak;\n\n\t\tcase 'string':\n\t\t\tnum = Number(obj);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !Number.isNaN(num) && Number.isFinite(num);\n\t}\n\n\t/*\n\t\tReturns whether the passed values pass a SameValueZero comparison.\n\n\t\tSEE: http://ecma-international.org/ecma-262/8.0/#sec-samevaluezero\n\t*/\n\tfunction utilSameValueZero(a, b) {\n\t\t/*\n\t\t\tNOTE: This comparison could also be implemented thus:\n\n\t\t\t\t```\n\t\t\t\ta === b ||\n\t\t\t\ttypeof a === 'number' && typeof b === 'number' &&\n\t\t\t\tNumber.isNaN(a) && Number.isNaN(b)\n\t\t\t\t```\n\n\t\t\tThat's needlessly verbose, however, as `NaN` is the only value in\n\t\t\tthe language which is not reflexive.\n\t\t*/\n\t\treturn a === b || a !== a && b !== b;\n\t}\n\n\t/*\n\t\tReturns a pseudo-enumeration created from the given Array, Map, Set, or generic object.\n\t*/\n\tfunction utilToEnum(obj) {\n\t\tconst pEnum = Object.create(null);\n\n\t\tif (obj instanceof Array) {\n\t\t\tobj.forEach((val, i) => pEnum[String(val)] = i);\n\t\t}\n\t\telse if (obj instanceof Set) {\n\t\t\t// NOTE: Use `<Array>.forEach()` here rather than `<Set>.forEach()`\n\t\t\t// as the latter does not provide the indices we require.\n\t\t\tArray.from(obj).forEach((val, i) => pEnum[String(val)] = i);\n\t\t}\n\t\telse if (obj instanceof Map) {\n\t\t\tobj.forEach((val, key) => pEnum[String(key)] = val);\n\t\t}\n\t\telse if (\n\t\t\t   typeof obj === 'object'\n\t\t\t&& obj !== null\n\t\t\t&& Object.getPrototypeOf(obj) === Object.prototype\n\t\t) {\n\t\t\tObject.assign(pEnum, obj);\n\t\t}\n\t\telse {\n\t\t\tthrow new TypeError('Util.toEnum obj parameter must be an Array, Map, Set, or generic object');\n\t\t}\n\n\t\treturn Object.freeze(pEnum);\n\t}\n\n\t/*\n\t\tReturns the value of the `@@toStringTag` property of the given object.\n\n\t\tNOTE: In ≤ES5, returns the value of the `[[Class]]` internal slot.\n\t*/\n\tfunction utilToStringTag(obj) {\n\t\treturn Object.prototype.toString.call(obj).slice(8, -1);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tString Encoding Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a trimmed and encoded slug of the passed string that should be safe\n\t\tfor use as a DOM ID or class name.\n\n\t\tNOTE: The range of illegal characters consists of: C0 controls, space, exclamation,\n\t\tdouble quote, number, dollar, percent, ampersand, single quote, left paren, right\n\t\tparen, asterisk, plus, comma, hyphen, period, forward slash, colon, semi-colon,\n\t\tless-than, equals, greater-than, question, at, left bracket, backslash, right\n\t\tbracket, caret, backquote/grave, left brace, pipe/vertical-bar, right brace, tilde,\n\t\tdelete, C1 controls.\n\t*/\n\tconst _illegalSlugCharsRe = /[\\x00-\\x20!-/:-@[-^`{-\\x9f]+/g; // eslint-disable-line no-control-regex\n\t/* legacy */\n\tconst _isInvalidSlugRe = /^-*$/; // Matches the empty string or one comprised solely of hyphens.\n\t/* /legacy */\n\n\tfunction utilSlugify(str) {\n\t\tconst base = String(str).trim();\n\n\t\t/* legacy */\n\t\tconst _legacy = base\n\t\t\t.replace(/[^\\w\\s\\u2013\\u2014-]+/g, '')\n\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-')\n\t\t\t.toLocaleLowerCase();\n\n\t\tif (!_isInvalidSlugRe.test(_legacy)) {\n\t\t\treturn _legacy;\n\t\t}\n\t\t/* /legacy */\n\n\t\treturn base\n\t\t\t.replace(_illegalSlugCharsRe, '')\n\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-');\n\n\t\t// For v3.\n\t\t// return base.replace(_illegalSlugCharsRe, '-');\n\t}\n\n\t/*\n\t\tReturns an entity encoded version of the passed string.\n\n\t\tNOTE: Only escapes the five primary special characters and the backquote.\n\t*/\n\tconst _htmlCharsRe    = /[&<>\"'`]/g;\n\tconst _hasHtmlCharsRe = new RegExp(_htmlCharsRe.source); // to drop the global flag\n\tconst _htmlCharsMap   = Object.freeze({\n\t\t'&' : '&amp;',\n\t\t'<' : '&lt;',\n\t\t'>' : '&gt;',\n\t\t'\"' : '&quot;',\n\t\t\"'\" : '&#39;',\n\t\t'`' : '&#96;'\n\t});\n\n\tfunction utilEscape(str) {\n\t\tif (str == null) { // lazy equality for null\n\t\t\treturn '';\n\t\t}\n\n\t\tconst val = String(str);\n\t\treturn val && _hasHtmlCharsRe.test(val)\n\t\t\t? val.replace(_htmlCharsRe, ch => _htmlCharsMap[ch])\n\t\t\t: val;\n\t}\n\n\t/*\n\t\tReturns a decoded version of the passed entity encoded string.\n\n\t\tNOTE: The extended replacement set here, in contrast to `utilEscape()`,\n\t\tis required due to observed stupidity from various sources.\n\t*/\n\tconst _escapedHtmlRe    = /&(?:amp|#38|#x26|lt|#60|#x3c|gt|#62|#x3e|quot|#34|#x22|apos|#39|#x27|#96|#x60);/gi;\n\tconst _hasEscapedHtmlRe = new RegExp(_escapedHtmlRe.source, 'i'); // to drop the global flag\n\tconst _escapedHtmlMap   = Object.freeze({\n\t\t'&amp;'  : '&', // ampersand (HTML character entity, XML predefined entity)\n\t\t'&#38;'  : '&', // ampersand (decimal numeric character reference)\n\t\t'&#x26;' : '&', // ampersand (hexadecimal numeric character reference)\n\t\t'&lt;'   : '<', // less-than (HTML character entity, XML predefined entity)\n\t\t'&#60;'  : '<', // less-than (decimal numeric character reference)\n\t\t'&#x3c;' : '<', // less-than (hexadecimal numeric character reference)\n\t\t'&gt;'   : '>', // greater-than (HTML character entity, XML predefined entity)\n\t\t'&#62;'  : '>', // greater-than (decimal numeric character reference)\n\t\t'&#x3e;' : '>', // greater-than (hexadecimal numeric character reference)\n\t\t'&quot;' : '\"', // double quote (HTML character entity, XML predefined entity)\n\t\t'&#34;'  : '\"', // double quote (decimal numeric character reference)\n\t\t'&#x22;' : '\"', // double quote (hexadecimal numeric character reference)\n\t\t'&apos;' : \"'\", // apostrophe (XML predefined entity)\n\t\t'&#39;'  : \"'\", // apostrophe (decimal numeric character reference)\n\t\t'&#x27;' : \"'\", // apostrophe (hexadecimal numeric character reference)\n\t\t'&#96;'  : '`', // backquote (decimal numeric character reference)\n\t\t'&#x60;' : '`'  // backquote (hexadecimal numeric character reference)\n\t});\n\n\tfunction utilUnescape(str) {\n\t\tif (str == null) { // lazy equality for null\n\t\t\treturn '';\n\t\t}\n\n\t\tconst val = String(str);\n\t\treturn val && _hasEscapedHtmlRe.test(val)\n\t\t\t? val.replace(_escapedHtmlRe, entity => _escapedHtmlMap[entity.toLowerCase()])\n\t\t\t: val;\n\t}\n\n\t/*\n\t\tReturns an object (`{ char, start, end }`) containing the Unicode character at\n\t\tposition `pos`, its starting position, and its ending position—surrogate pairs\n\t\tare properly handled.  If `pos` is out-of-bounds, returns an object containing\n\t\tthe empty string and start/end positions of `-1`.\n\n\t\tThis function is necessary because JavaScript strings are sequences of UTF-16\n\t\tcode units, so surrogate pairs are exposed and thus must be handled.  While the\n\t\tES6/2015 standard does improve the situation somewhat, it does not alleviate\n\t\tthe need for this function.\n\n\t\tNOTE: Returns the individual code units of invalid surrogate pairs as-is.\n\n\t\tIDEA: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt\n\t*/\n\tfunction utilCharAndPosAt(text, position) {\n\t\tconst str  = String(text);\n\t\tconst pos  = Math.trunc(position);\n\t\tconst code = str.charCodeAt(pos);\n\n\t\t// Given position was out-of-bounds.\n\t\tif (Number.isNaN(code)) {\n\t\t\treturn { char : '', start : -1, end : -1 };\n\t\t}\n\n\t\tconst retval = {\n\t\t\tchar  : str.charAt(pos),\n\t\t\tstart : pos,\n\t\t\tend   : pos\n\t\t};\n\n\t\t// Code unit is not a UTF-16 surrogate.\n\t\tif (code < 0xD800 || code > 0xDFFF) {\n\t\t\treturn retval;\n\t\t}\n\n\t\t// Code unit is a high surrogate (D800–DBFF).\n\t\tif (code >= 0xD800 && code <= 0xDBFF) {\n\t\t\tconst nextPos = pos + 1;\n\n\t\t\t// End of string.\n\t\t\tif (nextPos >= str.length) {\n\t\t\t\treturn retval;\n\t\t\t}\n\n\t\t\tconst nextCode = str.charCodeAt(nextPos);\n\n\t\t\t// Next code unit is not a low surrogate (DC00–DFFF).\n\t\t\tif (nextCode < 0xDC00 || nextCode > 0xDFFF) {\n\t\t\t\treturn retval;\n\t\t\t}\n\n\t\t\tretval.char = retval.char + str.charAt(nextPos);\n\t\t\tretval.end = nextPos;\n\t\t\treturn retval;\n\t\t}\n\n\t\t// Code unit is a low surrogate (DC00–DFFF) in the first position.\n\t\tif (pos === 0) {\n\t\t\treturn retval;\n\t\t}\n\n\t\tconst prevPos  = pos - 1;\n\t\tconst prevCode = str.charCodeAt(prevPos);\n\n\t\t// Previous code unit is not a high surrogate (D800–DBFF).\n\t\tif (prevCode < 0xD800 || prevCode > 0xDBFF) {\n\t\t\treturn retval;\n\t\t}\n\n\t\tretval.char = str.charAt(prevPos) + retval.char;\n\t\tretval.start = prevPos;\n\t\treturn retval;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTime Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the number of milliseconds elapsed since a reference epoch.\n\n\t\tNOTE: Use the Performance API, if available, elsewise use Date as a\n\t\tfailover.  The Performance API is preferred for its monotonic clock—\n\t\tmeaning, it's not subject to the vagaries of timezone changes and leap\n\t\tperiods, as is Date.\n\t*/\n\tconst _nowSource = Has.performance ? performance : Date;\n\n\tfunction utilNow() {\n\t\treturn _nowSource.now();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tConversion Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the number of miliseconds represented by the passed CSS time string.\n\t*/\n\tconst _cssTimeRe = /^([+-]?(?:\\d*\\.)?\\d+)([Mm]?[Ss])$/;\n\n\tfunction utilFromCssTime(cssTime) {\n\t\tconst match = _cssTimeRe.exec(String(cssTime));\n\n\t\tif (match === null) {\n\t\t\tthrow new SyntaxError(`invalid time value syntax: \"${cssTime}\"`);\n\t\t}\n\n\t\tlet msec = Number(match[1]);\n\n\t\tif (match[2].length === 1) {\n\t\t\tmsec *= 1000;\n\t\t}\n\n\t\tif (Number.isNaN(msec) || !Number.isFinite(msec)) {\n\t\t\tthrow new RangeError(`invalid time value: \"${cssTime}\"`);\n\t\t}\n\n\t\treturn msec;\n\t}\n\n\t/*\n\t\tReturns the CSS time string represented by the passed number of milliseconds.\n\t*/\n\tfunction utilToCssTime(msec) {\n\t\tif (typeof msec !== 'number' || Number.isNaN(msec) || !Number.isFinite(msec)) {\n\t\t\tlet what;\n\n\t\t\tswitch (typeof msec) {\n\t\t\tcase 'string':\n\t\t\t\twhat = `\"${msec}\"`;\n\t\t\t\tbreak;\n\n\t\t\tcase 'number':\n\t\t\t\twhat = String(msec);\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\twhat = utilToStringTag(msec);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tthrow new Error(`invalid milliseconds: ${what}`);\n\t\t}\n\n\t\treturn `${msec}ms`;\n\t}\n\n\t/*\n\t\tReturns the DOM property name represented by the passed CSS property name.\n\t*/\n\tfunction utilFromCssProperty(cssName) {\n\t\tif (!cssName.includes('-')) {\n\t\t\tswitch (cssName) {\n\t\t\tcase 'bgcolor': return 'backgroundColor';\n\t\t\tcase 'float':   return 'cssFloat';\n\t\t\tdefault:        return cssName;\n\t\t\t}\n\t\t}\n\n\t\t// Strip the leading hyphen from the `-ms-` vendor prefix, so it stays lowercased.\n\t\tconst normalized = cssName.slice(0, 4) === '-ms-' ? cssName.slice(1) : cssName;\n\n\t\treturn normalized\n\t\t\t.split('-')\n\t\t\t.map((part, i) => i === 0 ? part : part.toUpperFirst())\n\t\t\t.join('');\n\t}\n\n\t/*\n\t\tReturns an object containing the component properties parsed from the passed URL.\n\t*/\n\tfunction utilParseUrl(url) {\n\t\tconst el       = document.createElement('a');\n\t\tconst queryObj = Object.create(null);\n\n\t\t// Let the `<a>` element parse the URL.\n\t\tel.href = url;\n\n\t\t// Populate the `queryObj` object with the query string attributes.\n\t\tif (el.search) {\n\t\t\tel.search\n\t\t\t\t.replace(/^\\?/, '')\n\t\t\t\t.splitOrEmpty(/(?:&(?:amp;)?|;)/)\n\t\t\t\t.forEach(query => {\n\t\t\t\t\tconst [key, value] = query.split('=');\n\t\t\t\t\tqueryObj[key] = value;\n\t\t\t\t});\n\t\t}\n\n\t\t/*\n\t\t\tCaveats by browser:\n\t\t\t\tEdge and Internet Explorer (≥8) do not support authentication\n\t\t\t\tinformation within a URL at all and will throw a security exception\n\t\t\t\ton *any* property access if it's included.\n\n\t\t\t\tInternet Explorer does not include the leading forward slash on\n\t\t\t\t`pathname` when required.\n\n\t\t\t\tOpera (Presto) strips the authentication information from `href`\n\t\t\t\tand does not supply `username` or `password`.\n\n\t\t\t\tSafari (ca. v5.1.x) does not supply `username` or `password` and\n\t\t\t\tpeforms URI decoding on `pathname`.\n\t\t*/\n\n\t\t// Patch for IE not including the leading slash on `pathname` when required.\n\t\tconst pathname = el.host && el.pathname[0] !== '/' ? `/${el.pathname}` : el.pathname;\n\n\t\treturn {\n\t\t\t// The full URL that was originally parsed.\n\t\t\thref : el.href,\n\n\t\t\t// The request protocol, lowercased.\n\t\t\tprotocol : el.protocol,\n\n\t\t\t// // The full authentication information.\n\t\t\t// auth : el.username || el.password // eslint-disable-line no-nested-ternary\n\t\t\t// \t? `${el.username}:${el.password}`\n\t\t\t// \t: typeof el.username === 'string' ? '' : undefined,\n\t\t\t//\n\t\t\t// // The username portion of the auth info.\n\t\t\t// username : el.username,\n\t\t\t//\n\t\t\t// // The password portion of the auth info.\n\t\t\t// password : el.password,\n\n\t\t\t// The full host information, including port number, lowercased.\n\t\t\thost : el.host,\n\n\t\t\t// The hostname portion of the host info, lowercased.\n\t\t\thostname : el.hostname,\n\n\t\t\t// The port number portion of the host info.\n\t\t\tport : el.port,\n\n\t\t\t// The full path information, including query info.\n\t\t\tpath : `${pathname}${el.search}`,\n\n\t\t\t// The pathname portion of the path info.\n\t\t\tpathname,\n\n\t\t\t// The query string portion of the path info, including the leading question mark.\n\t\t\tquery  : el.search,\n\t\t\tsearch : el.search,\n\n\t\t\t// The attributes portion of the query string, parsed into an object.\n\t\t\tqueries  : queryObj,\n\t\t\tsearches : queryObj,\n\n\t\t\t// The fragment string, including the leading hash/pound sign.\n\t\t\thash : el.hash\n\t\t};\n\t}\n\n\t/*\n\t\tReturns a new exception based on the given exception.\n\n\t\tNOTE: Mostly useful for making a standard JavaScript exception type copy\n\t\tof a host exception type—e.g. `DOMException` → `Error`.\n\t*/\n\tfunction utilNewExceptionFrom(original, exceptionType, override) {\n\t\tif (typeof original !== 'object' || original === null) {\n\t\t\tthrow new Error('Util.newExceptionFrom original parameter must be an object');\n\t\t}\n\t\tif (typeof exceptionType !== 'function') {\n\t\t\tthrow new Error('Util.newExceptionFrom exceptionType parameter must be an error type constructor');\n\t\t}\n\n\t\tconst ex = new exceptionType(original.message); // eslint-disable-line new-cap\n\n\t\tif (typeof original.name !== 'undefined') {\n\t\t\tex.name = original.name;\n\t\t}\n\t\tif (typeof original.code !== 'undefined') {\n\t\t\tex.code = original.code;\n\t\t}\n\t\tif (typeof original.columnNumber !== 'undefined') {\n\t\t\tex.columnNumber = original.columnNumber;\n\t\t}\n\t\tif (typeof original.description !== 'undefined') {\n\t\t\tex.description = original.description;\n\t\t}\n\t\tif (typeof original.fileName !== 'undefined') {\n\t\t\tex.fileName = original.fileName;\n\t\t}\n\t\tif (typeof original.lineNumber !== 'undefined') {\n\t\t\tex.lineNumber = original.lineNumber;\n\t\t}\n\t\tif (typeof original.number !== 'undefined') {\n\t\t\tex.number = original.number;\n\t\t}\n\t\tif (typeof original.stack !== 'undefined') {\n\t\t\tex.stack = original.stack;\n\t\t}\n\n\t\tconst overrideType = typeof override;\n\n\t\tif (overrideType !== 'undefined') {\n\t\t\tif (overrideType === 'object' && override !== null) {\n\t\t\t\tObject.assign(ex, override);\n\t\t\t}\n\t\t\telse if (overrideType === 'string') {\n\t\t\t\tex.message = override;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('Util.newExceptionFrom override parameter must be an object or string');\n\t\t\t}\n\t\t}\n\n\t\treturn ex;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tType Functions.\n\t\t*/\n\t\tgetType       : { value : utilGetType },\n\t\tisBoolean     : { value : utilIsBoolean },\n\t\tisIterable    : { value : utilIsIterable },\n\t\tisNumeric     : { value : utilIsNumeric },\n\t\tsameValueZero : { value : utilSameValueZero },\n\t\ttoEnum        : { value : utilToEnum },\n\t\ttoStringTag   : { value : utilToStringTag },\n\n\t\t/*\n\t\t\tString Encoding Functions.\n\t\t*/\n\t\tslugify      : { value : utilSlugify },\n\t\tescape       : { value : utilEscape },\n\t\tunescape     : { value : utilUnescape },\n\t\tcharAndPosAt : { value : utilCharAndPosAt },\n\n\t\t/*\n\t\t\tConversion Functions.\n\t\t*/\n\t\tfromCssTime      : { value : utilFromCssTime },\n\t\ttoCssTime        : { value : utilToCssTime },\n\t\tfromCssProperty  : { value : utilFromCssProperty },\n\t\tparseUrl         : { value : utilParseUrl },\n\t\tnewExceptionFrom : { value : utilNewExceptionFrom },\n\n\t\t/*\n\t\t\tTime Functions.\n\t\t*/\n\t\tnow : { value : utilNow },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\trandom         : { value : Math.random },\n\t\tentityEncode   : { value : utilEscape },\n\t\tentityDecode   : { value : utilUnescape },\n\t\tevalExpression : { value : (...args) => Scripting.evalJavaScript(...args) }, // SEE: `markup/scripting.js`.\n\t\tevalStatements : { value : (...args) => Scripting.evalJavaScript(...args) }  // SEE: `markup/scripting.js`.\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/simplestore.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar SimpleStore = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// In-order list of database adapters.\n\tconst _adapters = [];\n\n\t// The initialized adapter.\n\tlet _initialized = null;\n\n\n\t/*******************************************************************************************************************\n\t\tSimpleStore Functions.\n\t*******************************************************************************************************************/\n\tfunction storeCreate(storageId, persistent) {\n\t\tif (_initialized) {\n\t\t\treturn _initialized.create(storageId, persistent);\n\t\t}\n\n\t\t// Return the first adapter which successfully initializes, elsewise throw an exception.\n\t\tfor (let i = 0; i < _adapters.length; ++i) {\n\t\t\tif (_adapters[i].init(storageId, persistent)) {\n\t\t\t\t_initialized = _adapters[i];\n\t\t\t\treturn _initialized.create(storageId, persistent);\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error('no valid storage adapters found');\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tAdapters List.\n\n\t\t\tTODO: This should probably have a getter, rather than being exported directly.\n\t\t*/\n\t\tadapters : { value : _adapters },\n\n\t\t/*\n\t\t\tCore Functions.\n\t\t*/\n\t\tcreate : { value : storeCreate }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/FCHost.Storage.js\n\n\tCopyright © 2013–2019 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_FCHostStorageAdapter Class.\n        Note that FCHost is only intended for a single document, so we ignore both prefixing and storageID\n\t*******************************************************************************************************************/\n\tclass _FCHostStorageAdapter {\n\t\tconstructor(persistent) {\n\t\t\tlet engine = null;\n\t\t\tlet name   = null;\n\n\t\t\tif (persistent) {\n\t\t\t\tengine = window.FCHostPersistent;\n\t\t\t\tname   = 'FCHostPersistent';\n\t\t\t}\n\t\t\telse {\n\t\t\t    engine = window.FCHostSession;\n\t\t\t\tname   = 'FCHostSession';\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_engine : {\n\t\t\t\t\tvalue : engine\n\t\t\t\t},\n                \n\t\t\t\tname : {\n\t\t\t\t\tvalue : name\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\treturn this._engine.size();\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\treturn this._engine.size();\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\treturn this._engine.keys();\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn this._engine.has(key);\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = this._engine.get(key);\n\n\t\t\treturn value == null ? null : _FCHostStorageAdapter._deserialize(value); // lazy equality for null\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.set(key, _FCHostStorageAdapter._serialize(value));\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.remove(key);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tthis._engine.clear();\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn JSON.stringify(obj);\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse(str);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit() {\n\t\t// FCHost feature test.\n\t\tfunction hasFCHostStorage() {\n\t\t\ttry {\n\t\t\t    if (typeof window.FCHostPersistent !== 'undefined')\n\t\t\t        return true;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn false;\n\t\t}\n\n\t\t_ok = hasFCHostStorage();\n\t\t\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _FCHostStorageAdapter(persistent);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/webstorage.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_WebStorageAdapter Class.\n\t*******************************************************************************************************************/\n\tclass _WebStorageAdapter {\n\t\tconstructor(storageId, persistent) {\n\t\t\tconst prefix = `${storageId}.`;\n\t\t\tlet engine = null;\n\t\t\tlet name   = null;\n\n\t\t\tif (persistent) {\n\t\t\t\tengine = window.localStorage;\n\t\t\t\tname   = 'localStorage';\n\t\t\t}\n\t\t\telse {\n\t\t\t\tengine = window.sessionStorage;\n\t\t\t\tname   = 'sessionStorage';\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_engine : {\n\t\t\t\t\tvalue : engine\n\t\t\t\t},\n\n\t\t\t\t_prefix : {\n\t\t\t\t\tvalue : prefix\n\t\t\t\t},\n\n\t\t\t\t_prefixRe : {\n\t\t\t\t\tvalue : new RegExp(`^${RegExp.escape(prefix)}`)\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : name\n\t\t\t\t},\n\n\t\t\t\tid : {\n\t\t\t\t\tvalue : storageId\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\t/*\n\t\t\t\tNOTE: DO NOT do something like `return this._engine.length;` here,\n\t\t\t\tas that will return the length of the entire store, rather than\n\t\t\t\tjust our prefixed keys.\n\t\t\t*/\n\t\t\treturn this.keys().length;\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\t/*\n\t\t\t\tNOTE: DO NOT do something like `return this._engine.length;` here,\n\t\t\t\tas that will return the length of the entire store, rather than\n\t\t\t\tjust our prefixed keys.\n\t\t\t*/\n\t\t\treturn this.keys().length;\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\tconst keys = [];\n\n\t\t\tfor (let i = 0; i < this._engine.length; ++i) {\n\t\t\t\tconst key = this._engine.key(i);\n\n\t\t\t\tif (this._prefixRe.test(key)) {\n\t\t\t\t\tkeys.push(key.replace(this._prefixRe, ''));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn keys;\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// // FIXME: This method should probably check for the key, rather than comparing its value.\n\t\t\t// return this._engine.getItem(this._prefix + key) != null; // lazy equality for null\n\n\t\t\treturn this._engine.hasOwnProperty(this._prefix + key);\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = this._engine.getItem(this._prefix + key);\n\n\t\t\treturn value == null ? null : _WebStorageAdapter._deserialize(value); // lazy equality for null\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tthis._engine.setItem(this._prefix + key, _WebStorageAdapter._serialize(value));\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t/*\n\t\t\t\t\tIf the exception is a quota exceeded error, massage it into something\n\t\t\t\t\ta bit nicer for the player.\n\n\t\t\t\t\tNOTE: Ideally, we could simply do something like checking `ex.code`, but\n\t\t\t\t\tit's a non-standard property and not supported in all browsers.  Thus,\n\t\t\t\t\twe have to resort to pattern matching the name and message—the latter being\n\t\t\t\t\trequired by Opera (Presto).  I hate the parties responsible for this snafu\n\t\t\t\t\tso much.\n\t\t\t\t*/\n\t\t\t\tif (/quota.?(?:exceeded|reached)/i.test(ex.name + ex.message)) {\n\t\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `${this.name} quota exceeded`);\n\t\t\t\t}\n\n\t\t\t\tthrow ex;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.removeItem(this._prefix + key);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tconst keys = this.keys();\n\n\t\t\tfor (let i = 0, iend = keys.length; i < iend; ++i) {\n\t\t\t\tif (DEBUG) { console.log('\\tdeleting key:', keys[i]); }\n\n\t\t\t\tthis.delete(keys[i]);\n\t\t\t}\n\n\t\t\t// return this.keys().forEach(key => {\n\t\t\t// \tif (DEBUG) { console.log('\\tdeleting key:', key); }\n\t\t\t//\n\t\t\t// \tthis.delete(key);\n\t\t\t// });\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn JSON.stringify(obj);\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse((!str || str[0] == \"{\") ? str : LZString.decompressFromUTF16(str));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit() {\n\t\t// Web Storage feature test.\n\t\tfunction hasWebStorage(storeId) {\n\t\t\ttry {\n\t\t\t\tconst store = window[storeId];\n\t\t\t\tconst tid   = `_sc_${String(Date.now())}`;\n\t\t\t\tstore.setItem(tid, tid);\n\t\t\t\tconst result = store.getItem(tid) === tid;\n\t\t\t\tstore.removeItem(tid);\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn false;\n\t\t}\n\n\t\t/*\n\t\t\tJust to be safe, we feature test for both `localStorage` and `sessionStorage`,\n\t\t\tas you never know what browser implementation bugs you're going to run into.\n\t\t*/\n\t\t_ok = hasWebStorage('localStorage') && hasWebStorage('sessionStorage');\n\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _WebStorageAdapter(storageId, persistent);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/cookie.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Expiry constants.\n\tconst _MAX_EXPIRY = 'Tue, 19 Jan 2038 03:14:07 GMT'; // (new Date((Math.pow(2, 31) - 1) * 1000)).toUTCString()\n\tconst _MIN_EXPIRY = 'Thu, 01 Jan 1970 00:00:00 GMT'; // (new Date(0)).toUTCString()\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_CookieAdapter Class.\n\t*******************************************************************************************************************/\n\tclass _CookieAdapter {\n\t\tconstructor(storageId, persistent) {\n\t\t\tconst prefix = `${storageId}${persistent ? '!' : '*'}.`;\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_prefix : {\n\t\t\t\t\tvalue : prefix\n\t\t\t\t},\n\n\t\t\t\t_prefixRe : {\n\t\t\t\t\tvalue : new RegExp(`^${RegExp.escape(prefix)}`)\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : 'cookie'\n\t\t\t\t},\n\n\t\t\t\tid : {\n\t\t\t\t\tvalue : storageId\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\treturn this.keys().length;\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\treturn this.keys().length;\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\tif (document.cookie === '') {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst cookies = document.cookie.split(/;\\s*/);\n\t\t\tconst keys    = [];\n\n\t\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\t\tif (this._prefixRe.test(key)) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\t\tnot a serialized empty string, so we should omit such pairs.\n\t\t\t\t\t*/\n\t\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\t\tif (value !== '') {\n\t\t\t\t\t\tkeys.push(key.replace(this._prefixRe, ''));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn keys;\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn _CookieAdapter._getCookie(this._prefix + key) !== null;\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = _CookieAdapter._getCookie(this._prefix + key);\n\n\t\t\treturn value === null ? null : _CookieAdapter._deserialize(value);\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\tthis._prefix + key,\n\t\t\t\t\t_CookieAdapter._serialize(value),\n\n\t\t\t\t\t// An undefined expiry denotes a session cookie.\n\t\t\t\t\tthis.persistent ? _MAX_EXPIRY : undefined\n\t\t\t\t);\n\n\t\t\t\tif (!this.has(key)) {\n\t\t\t\t\tthrow new Error('unknown validation error during set');\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t// Massage the cookie exception into something a bit nicer for the player.\n\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `cookie error: ${ex.message}`);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\t/*\n\t\t\t\tAttempting to delete a cookie implies setting it, so we test for its existence\n\t\t\t\tbeforehand, to avoid creating it in the event that it does not already exist.\n\t\t\t*/\n\t\t\tif (typeof key !== 'string' || !key || !this.has(key)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\tthis._prefix + key,\n\n\t\t\t\t\t// Use `undefined` as the value.\n\t\t\t\t\tundefined,\n\n\t\t\t\t\t// Use the epoch as the expiry.\n\t\t\t\t\t_MIN_EXPIRY\n\t\t\t\t);\n\n\t\t\t\tif (this.has(key)) {\n\t\t\t\t\tthrow new Error('unknown validation error during delete');\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t// Massage the cookie exception into something a bit nicer for the player.\n\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `cookie error: ${ex.message}`);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tconst keys = this.keys();\n\n\t\t\tfor (let i = 0, iend = keys.length; i < iend; ++i) {\n\t\t\t\tif (DEBUG) { console.log('\\tdeleting key:', keys[i]); }\n\n\t\t\t\tthis.delete(keys[i]);\n\t\t\t}\n\n\t\t\t// this.keys().forEach(key => {\n\t\t\t// \tif (DEBUG) { console.log('\\tdeleting key:', key); }\n\t\t\t//\n\t\t\t// \tthis.delete(key);\n\t\t\t// });\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _getCookie(prefixedKey) {\n\t\t\tif (!prefixedKey || document.cookie === '') {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst cookies = document.cookie.split(/;\\s*/);\n\n\t\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\t\tif (prefixedKey === key) {\n\t\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\t\tnot a serialized empty string, so we should yield `null` for such pairs.\n\t\t\t\t\t*/\n\t\t\t\t\treturn value || null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tstatic _setCookie(prefixedKey, value, expiry) {\n\t\t\tif (!prefixedKey) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet payload = `${encodeURIComponent(prefixedKey)}=`;\n\n\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\tpayload += encodeURIComponent(value);\n\t\t\t}\n\n\t\t\tif (expiry != null) { // lazy equality for null\n\t\t\t\tpayload += `; expires=${expiry}`;\n\t\t\t}\n\n\t\t\tpayload += '; path=/';\n\t\t\tdocument.cookie = payload;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn LZString.compressToBase64(JSON.stringify(obj));\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse(LZString.decompressFromBase64(str));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit(\n\t\t// Only used for stores updates.\n\t\tstorageId\n\t) {\n\t\t// Cookie feature test.\n\t\ttry {\n\t\t\tconst tid = `_sc_${String(Date.now())}`;\n\n\t\t\t// We only test a session cookie as that should suffice.\n\t\t\t_CookieAdapter._setCookie(tid, _CookieAdapter._serialize(tid), undefined);\n\t\t\t_ok = _CookieAdapter._deserialize(_CookieAdapter._getCookie(tid)) === tid;\n\t\t\t_CookieAdapter._setCookie(tid, undefined, _MIN_EXPIRY);\n\t\t}\n\t\tcatch (ex) {\n\t\t\t_ok = false;\n\t\t}\n\n\t\t/* legacy */\n\t\t// Attempt to update the cookie stores, if necessary.  This should happen only during initialization.\n\t\tif (_ok) {\n\t\t\t_updateCookieStores(storageId);\n\t\t}\n\t\t/* /legacy */\n\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _CookieAdapter(storageId, persistent);\n\t}\n\n\t/* legacy */\n\t// Updates old non-segmented cookie stores into segmented stores.\n\tfunction _updateCookieStores(storageId) {\n\t\tif (document.cookie === '') {\n\t\t\treturn;\n\t\t}\n\n\t\tconst oldPrefix     = `${storageId}.`;\n\t\tconst oldPrefixRe   = new RegExp(`^${RegExp.escape(oldPrefix)}`);\n\t\tconst persistPrefix = `${storageId}!.`;\n\t\tconst sessionPrefix = `${storageId}*.`;\n\t\tconst sessionTestRe = /\\.(?:state|rcWarn)$/;\n\t\tconst cookies       = document.cookie.split(/;\\s*/);\n\n\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\tif (oldPrefixRe.test(key)) {\n\t\t\t\t/*\n\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\tnot a serialized empty string, so we should skip processing such pairs.\n\t\t\t\t*/\n\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\tif (value !== '') {\n\t\t\t\t\tconst persist = !sessionTestRe.test(key);\n\n\t\t\t\t\t// Delete the old k/v pair.\n\t\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t_MIN_EXPIRY\n\t\t\t\t\t);\n\n\t\t\t\t\t// Set the new k/v pair.\n\t\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\t\tkey.replace(oldPrefixRe, () => persist ? persistPrefix : sessionPrefix),\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tpersist ? _MAX_EXPIRY : undefined\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t/* /legacy */\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/debugview.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tTODO: Make this use jQuery throughout.\n*/\nvar DebugView = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tDebugView Class.\n\t*******************************************************************************************************************/\n\tclass DebugView {\n\t\tconstructor(parent, type, name, title) {\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tparent : {\n\t\t\t\t\tvalue : parent\n\t\t\t\t},\n\n\t\t\t\tview : {\n\t\t\t\t\tvalue : document.createElement('span')\n\t\t\t\t},\n\n\t\t\t\tbreak : {\n\t\t\t\t\tvalue : document.createElement('wbr')\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Set up the wrapper (`<span>`) element.\n\t\t\tjQuery(this.view)\n\t\t\t\t.attr({\n\t\t\t\t\ttitle,\n\t\t\t\t\t'aria-label' : title,\n\t\t\t\t\t'data-type'  : type != null ? type : '', // lazy equality for null\n\t\t\t\t\t'data-name'  : name != null ? name : ''  // lazy equality for null\n\t\t\t\t})\n\t\t\t\t.addClass('debug');\n\n\t\t\t// Set up the word break (`<wbr>`) element.\n\t\t\tjQuery(this.break).addClass('debug hidden');\n\n\t\t\t// Add the wrapper (`<span>`) and word break (`<wbr>`) elements to the `parent` element.\n\t\t\tthis.parent.appendChild(this.view);\n\t\t\tthis.parent.appendChild(this.break);\n\t\t}\n\n\t\tget output() {\n\t\t\treturn this.view;\n\t\t}\n\n\t\tget type() {\n\t\t\treturn this.view.getAttribute('data-type');\n\t\t}\n\t\tset type(type) {\n\t\t\tthis.view.setAttribute('data-type', type != null ? type : ''); // lazy equality for null\n\t\t}\n\n\t\tget name() {\n\t\t\treturn this.view.getAttribute('data-name');\n\t\t}\n\t\tset name(name) {\n\t\t\tthis.view.setAttribute('data-name', name != null ? name : ''); // lazy equality for null\n\t\t}\n\n\t\tget title() {\n\t\t\treturn this.view.title;\n\t\t}\n\t\tset title(title) {\n\t\t\tthis.view.title = title;\n\t\t}\n\n\t\tappend(el) {\n\t\t\tjQuery(this.view).append(el);\n\t\t\treturn this;\n\t\t}\n\n\t\tmodes(options) {\n\t\t\tif (options == null) { // lazy equality for null\n\t\t\t\tconst current = {};\n\n\t\t\t\tthis.view.className.splitOrEmpty(/\\s+/).forEach(name => {\n\t\t\t\t\tif (name !== 'debug') {\n\t\t\t\t\t\tcurrent[name] = true;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\treturn current;\n\t\t\t}\n\t\t\telse if (typeof options === 'object') {\n\t\t\t\tObject.keys(options).forEach(function (name) {\n\t\t\t\t\tthis[options[name] ? 'addClass' : 'removeClass'](name);\n\t\t\t\t}, jQuery(this.view));\n\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tthrow new Error('DebugView.prototype.modes options parameter must be an object or null/undefined');\n\t\t}\n\n\t\tremove() {\n\t\t\tconst $view = jQuery(this.view);\n\n\t\t\tif (this.view.hasChildNodes()) {\n\t\t\t\t$view.contents().appendTo(this.parent);\n\t\t\t}\n\n\t\t\t$view.remove();\n\t\t\tjQuery(this.break).remove();\n\t\t}\n\n\t\tstatic isEnabled() {\n\t\t\treturn jQuery(document.documentElement).attr('data-debug-view') === 'enabled';\n\t\t}\n\n\t\tstatic enable() {\n\t\t\tjQuery(document.documentElement).attr('data-debug-view', 'enabled');\n\t\t\tjQuery.event.trigger(':debugviewupdate');\n\t\t}\n\n\t\tstatic disable() {\n\t\t\tjQuery(document.documentElement).removeAttr('data-debug-view');\n\t\t\tjQuery.event.trigger(':debugviewupdate');\n\t\t}\n\n\t\tstatic toggle() {\n\t\t\tif (jQuery(document.documentElement).attr('data-debug-view') === 'enabled') {\n\t\t\t\tDebugView.disable();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tDebugView.enable();\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn DebugView;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/prngwrapper.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar PRNGWrapper = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tPRNGWrapper Class.\n\t*******************************************************************************************************************/\n\tclass PRNGWrapper {\n\t\tconstructor(seed, useEntropy) {\n\t\t\t/* eslint-disable new-cap */\n\t\t\tObject.defineProperties(this, new Math.seedrandom(seed, useEntropy, (prng, seed) => ({\n\t\t\t\t_prng : {\n\t\t\t\t\tvalue : prng\n\t\t\t\t},\n\n\t\t\t\tseed : {\n\t\t\t\t\t/*\n\t\t\t\t\t\tTODO: Make this non-writable.\n\t\t\t\t\t*/\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : seed\n\t\t\t\t},\n\n\t\t\t\tpull : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\trandom : {\n\t\t\t\t\tvalue() {\n\t\t\t\t\t\t++this.pull;\n\t\t\t\t\t\treturn this._prng();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})));\n\t\t\t/* eslint-enable new-cap */\n\t\t}\n\n\t\tstatic marshal(prng) {\n\t\t\tif (!prng || !prng.hasOwnProperty('seed') || !prng.hasOwnProperty('pull')) {\n\t\t\t\tthrow new Error('PRNG is missing required data');\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tseed : prng.seed,\n\t\t\t\tpull : prng.pull\n\t\t\t};\n\t\t}\n\n\t\tstatic unmarshal(prngObj) {\n\t\t\tif (!prngObj || !prngObj.hasOwnProperty('seed') || !prngObj.hasOwnProperty('pull')) {\n\t\t\t\tthrow new Error('PRNG object is missing required data');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tCreate a new PRNG using the original seed and pull values from it until it\n\t\t\t\thas reached the original pull count.\n\t\t\t*/\n\t\t\tconst prng = new PRNGWrapper(prngObj.seed, false);\n\n\t\t\tfor (let i = prngObj.pull; i > 0; --i) {\n\t\t\t\tprng.random();\n\t\t\t}\n\n\t\t\treturn prng;\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn PRNGWrapper;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/stylewrapper.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns, Story, Wikifier */\n\nvar StyleWrapper = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tconst _imageMarkupRe    = new RegExp(Patterns.cssImage, 'g');\n\tconst _hasImageMarkupRe = new RegExp(Patterns.cssImage);\n\n\n\t/*******************************************************************************************************************\n\t\tStyleWrapper Class.\n\t*******************************************************************************************************************/\n\tclass StyleWrapper {\n\t\tconstructor(style) {\n\t\t\tif (style == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('StyleWrapper style parameter must be an HTMLStyleElement object');\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tstyle : {\n\t\t\t\t\tvalue : style\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tisEmpty() {\n\t\t\t// This should work in all supported browsers.\n\t\t\treturn this.style.cssRules.length === 0;\n\t\t}\n\n\t\tset(rawCss) {\n\t\t\tthis.clear();\n\t\t\tthis.add(rawCss);\n\t\t}\n\n\t\tadd(rawCss) {\n\t\t\tlet css = rawCss;\n\n\t\t\t// Check for wiki image transclusion.\n\t\t\tif (_hasImageMarkupRe.test(css)) {\n\t\t\t\t/*\n\t\t\t\t\tThe JavaScript specifications, since at least ES3, say that `<String>.replace()`\n\t\t\t\t\tshould reset a global-flagged regular expression's `lastIndex` property to `0`\n\t\t\t\t\tupon invocation.  Buggy browser versions exist, however, which do not reset\n\t\t\t\t\t`lastIndex`, so we should do so manually to support those browsers.\n\n\t\t\t\t\tNOTE: I do not think this is actually necessary, since `_imageMarkupRe` is\n\t\t\t\t\tscoped to this module—meaning users should not be able to access it.  That\n\t\t\t\t\tbeing the case, and since we search to exhaustion which should also cause\n\t\t\t\t\t`lastIndex` to be reset, there should never be an instance where we invoke\n\t\t\t\t\t`css.replace()` and `_imageMarkupRe.lastIndex` is not already `0`.  Still,\n\t\t\t\t\tconsidering the other bug, better safe than sorry.\n\t\t\t\t*/\n\t\t\t\t_imageMarkupRe.lastIndex = 0;\n\n\t\t\t\tcss = css.replace(_imageMarkupRe, wikiImage => {\n\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\tsource     : wikiImage,\n\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t});\n\n\t\t\t\t\tif (markup.hasOwnProperty('error') || markup.pos < wikiImage.length) {\n\t\t\t\t\t\treturn wikiImage;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet source = markup.source;\n\n\t\t\t\t\t// Handle image passage transclusion.\n\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\tsource = passage.text.trim();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tThe source may be URI- or Base64-encoded, so we cannot use `encodeURIComponent()`\n\t\t\t\t\t\there.  Instead, we simply encode any double quotes, since the URI will be\n\t\t\t\t\t\tdelimited by them.\n\t\t\t\t\t*/\n\t\t\t\t\treturn `url(\"${source.replace(/\"/g, '%22')}\")`;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// For IE ≤ 10.\n\t\t\tif (this.style.styleSheet) {\n\t\t\t\tthis.style.styleSheet.cssText += css;\n\t\t\t}\n\n\t\t\t// For all other browsers (incl. IE ≥ 11).\n\t\t\telse {\n\t\t\t\tthis.style.appendChild(document.createTextNode(css));\n\t\t\t}\n\t\t}\n\n\t\tclear() {\n\t\t\t// For IE ≤10.\n\t\t\tif (this.style.styleSheet) {\n\t\t\t\tthis.style.styleSheet.cssText = '';\n\t\t\t}\n\n\t\t\t// For all other browsers (incl. IE ≥11).\n\t\t\telse {\n\t\t\t\tjQuery(this.style).empty();\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn StyleWrapper;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/diff.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util, clone */\n\nvar Diff = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tDiff Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tDiff operations object (pseudo-enumeration).\n\t*/\n\tconst Op = Util.toEnum({\n\t\tDelete      : 0,\n\t\tSpliceArray : 1,\n\t\tCopy        : 2,\n\t\tCopyDate    : 3\n\t});\n\n\t/*\n\t\tReturns a difference object generated from comparing the the orig and dest objects.\n\t*/\n\tfunction diff(orig, dest) /* diff object */ {\n\t\tconst objToString = Object.prototype.toString;\n\t\tconst origIsArray = orig instanceof Array;\n\t\tconst keys        = []\n\t\t\t.concat(Object.keys(orig), Object.keys(dest))\n\t\t\t.sort()\n\t\t\t.filter((val, i, arr) => i === 0 || arr[i - 1] !== val);\n\t\tconst diffed      = {};\n\t\tlet aOpRef;\n\n\t\tconst keyIsAOpRef = key => key === aOpRef;\n\n\t\t/* eslint-disable max-depth */\n\t\tfor (let i = 0, klen = keys.length; i < klen; ++i) {\n\t\t\tconst key   = keys[i];\n\t\t\tconst origP = orig[key];\n\t\t\tconst destP = dest[key];\n\n\t\t\tif (orig.hasOwnProperty(key)) {\n\t\t\t\t// Key exists in both.\n\t\t\t\tif (dest.hasOwnProperty(key)) {\n\t\t\t\t\t// Values are exactly the same, so do nothing.\n\t\t\t\t\tif (origP === destP) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Values are of the same basic type.\n\t\t\t\t\tif (typeof origP === typeof destP) { // eslint-disable-line valid-typeof\n\t\t\t\t\t\t// Values are functions.\n\t\t\t\t\t\tif (typeof origP === 'function') {\n\t\t\t\t\t\t\t/* diffed[key] = [Op.Copy, destP]; */\n\t\t\t\t\t\t\tif (origP.toString() !== destP.toString()) {\n\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, destP];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Values are primitives.\n\t\t\t\t\t\telse if (typeof origP !== 'object' || origP === null) {\n\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, destP];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Values are objects.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst origPType = objToString.call(origP);\n\t\t\t\t\t\t\tconst destPType = objToString.call(destP);\n\n\t\t\t\t\t\t\t// Values are objects of the same reported type.\n\t\t\t\t\t\t\tif (origPType === destPType) {\n\t\t\t\t\t\t\t\t// Various special cases to handle supported non-generic objects.\n\t\t\t\t\t\t\t\tif (origP instanceof Date) {\n\t\t\t\t\t\t\t\t\tif (Number(origP) !== Number(destP)) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof Map) {\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof RegExp) {\n\t\t\t\t\t\t\t\t\tif (origP.toString() !== destP.toString()) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof Set) {\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Unknown non-generic objects (custom or unsupported natives).\n\t\t\t\t\t\t\t\telse if (origPType !== '[object Object]') {\n\t\t\t\t\t\t\t\t\t// We cannot know how to process these objects,\n\t\t\t\t\t\t\t\t\t// so we simply accept them as-is.\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Generic objects.\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tconst recurse = diff(origP, destP);\n\n\t\t\t\t\t\t\t\t\tif (recurse !== null) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = recurse;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Values are objects of different reported types.\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Values are of different types.\n\t\t\t\t\telse {\n\t\t\t\t\t\tdiffed[key] = [\n\t\t\t\t\t\t\tOp.Copy,\n\t\t\t\t\t\t\ttypeof destP !== 'object' || destP === null ? destP : clone(destP)\n\t\t\t\t\t\t];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Key only exists in orig.\n\t\t\t\telse {\n\t\t\t\t\tif (origIsArray && Util.isNumeric(key)) {\n\t\t\t\t\t\tconst nKey = Number(key);\n\n\t\t\t\t\t\tif (!aOpRef) {\n\t\t\t\t\t\t\taOpRef = '';\n\n\t\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\t\taOpRef += '~';\n\t\t\t\t\t\t\t} while (keys.some(keyIsAOpRef));\n\n\t\t\t\t\t\t\tdiffed[aOpRef] = [Op.SpliceArray, nKey, nKey];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (nKey < diffed[aOpRef][1]) {\n\t\t\t\t\t\t\tdiffed[aOpRef][1] = nKey;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (nKey > diffed[aOpRef][2]) {\n\t\t\t\t\t\t\tdiffed[aOpRef][2] = nKey;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdiffed[key] = Op.Delete;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Key only exists in dest.\n\t\t\telse {\n\t\t\t\tdiffed[key] = [\n\t\t\t\t\tOp.Copy,\n\t\t\t\t\ttypeof destP !== 'object' || destP === null ? destP : clone(destP)\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\t\t/* eslint-enable max-depth */\n\n\t\treturn Object.keys(diffed).length > 0 ? diffed : null;\n\t}\n\n\t/*\n\t\tReturns the object resulting from updating the orig object with the diffed object.\n\t*/\n\tfunction patch(orig, diffed) /* patched object */ {\n\t\tconst keys    = Object.keys(diffed || {});\n\t\tconst patched = clone(orig);\n\n\t\tfor (let i = 0, klen = keys.length; i < klen; ++i) {\n\t\t\tconst key     = keys[i];\n\t\t\tconst diffedP = diffed[key];\n\n\t\t\tif (diffedP === Op.Delete) {\n\t\t\t\tdelete patched[key];\n\t\t\t}\n\t\t\telse if (diffedP instanceof Array) {\n\t\t\t\tswitch (diffedP[0]) {\n\t\t\t\tcase Op.SpliceArray:\n\t\t\t\t\tpatched.splice(diffedP[1], 1 + (diffedP[2] - diffedP[1]));\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase Op.Copy:\n\t\t\t\t\tpatched[key] = clone(diffedP[1]);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase Op.CopyDate:\n\t\t\t\t\tpatched[key] = new Date(diffedP[1]);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tpatched[key] = patch(patched[key], diffedP);\n\t\t\t}\n\t\t}\n\n\t\treturn patched;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tOp    : { value : Op },\n\t\tdiff  : { value : diff },\n\t\tpatch : { value : patch }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tl10n/l10n.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global l10nStrings, strings */\n\nvar L10n = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Replacement pattern regular expressions.\n\tconst _patternRe    = /\\{\\w+\\}/g;\n\tconst _hasPatternRe = new RegExp(_patternRe.source); // to drop the global flag\n\n\n\t/*******************************************************************************************************************\n\t\tLocalization Functions.\n\t*******************************************************************************************************************/\n\tfunction l10nInit() {\n\t\t/* legacy */\n\t\t_mapStringsToL10nStrings();\n\t\t/* /legacy */\n\t}\n\n\t/*******************************************************************************************************************\n\t\tLocalized String Functions.\n\t*******************************************************************************************************************/\n\tfunction l10nGet(ids, overrides) {\n\t\tif (!ids) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst id = (idList => {\n\t\t\tlet selectedId;\n\t\t\tidList.some(id => {\n\t\t\t\tif (l10nStrings.hasOwnProperty(id)) {\n\t\t\t\t\tselectedId = id;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\treturn selectedId;\n\t\t})(Array.isArray(ids) ? ids : [ids]);\n\n\t\tif (!id) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst maxIterations = 50;\n\t\tlet processed = l10nStrings[id];\n\t\tlet iteration = 0;\n\n\t\twhile (_hasPatternRe.test(processed)) {\n\t\t\tif (++iteration > maxIterations) {\n\t\t\t\tthrow new Error('L10n.get exceeded maximum replacement iterations, probable infinite loop');\n\t\t\t}\n\n\t\t\t// Possibly required by some old buggy browsers.\n\t\t\t_patternRe.lastIndex = 0;\n\n\t\t\tprocessed = processed.replace(_patternRe, pat => {\n\t\t\t\tconst subId = pat.slice(1, -1);\n\n\t\t\t\tif (overrides && overrides.hasOwnProperty(subId)) {\n\t\t\t\t\treturn overrides[subId];\n\t\t\t\t}\n\t\t\t\telse if (l10nStrings.hasOwnProperty(subId)) {\n\t\t\t\t\treturn l10nStrings[subId];\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treturn processed;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tLegacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tAttempt to map legacy `strings` object properties to the `l10nStrings` object.\n\t*/\n\tfunction _mapStringsToL10nStrings() {\n\t\tif (strings && Object.keys(strings).length > 0) {\n\t\t\tObject.keys(l10nStrings).forEach(id => {\n\t\t\t\ttry {\n\t\t\t\t\tlet value;\n\n\t\t\t\t\tswitch (id) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tGeneral.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'identity': value = strings.identity; break;\n\t\t\t\t\tcase 'aborting': value = strings.aborting; break;\n\t\t\t\t\tcase 'cancel':   value = strings.cancel; break;\n\t\t\t\t\tcase 'close':    value = strings.close; break;\n\t\t\t\t\tcase 'ok':       value = strings.ok; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tErrors.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'errorTitle':              value = strings.errors.title; break;\n\t\t\t\t\tcase 'errorNonexistentPassage': value = strings.errors.nonexistentPassage; break;\n\t\t\t\t\tcase 'errorSaveMissingData':    value = strings.errors.saveMissingData; break;\n\t\t\t\t\tcase 'errorSaveIdMismatch':     value = strings.errors.saveIdMismatch; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tWarnings.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'warningDegraded': value = strings.warnings.degraded; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tDebug View.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'debugViewTitle':  value = strings.debugView.title; break;\n\t\t\t\t\tcase 'debugViewToggle': value = strings.debugView.toggle; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tUI bar.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'uiBarToggle':   value = strings.uiBar.toggle; break;\n\t\t\t\t\tcase 'uiBarBackward': value = strings.uiBar.backward; break;\n\t\t\t\t\tcase 'uiBarForward':  value = strings.uiBar.forward; break;\n\t\t\t\t\tcase 'uiBarJumpto':   value = strings.uiBar.jumpto; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tJump To.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'jumptoTitle':       value = strings.jumpto.title; break;\n\t\t\t\t\tcase 'jumptoTurn':        value = strings.jumpto.turn; break;\n\t\t\t\t\tcase 'jumptoUnavailable': value = strings.jumpto.unavailable; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tSaves.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'savesTitle':       value = strings.saves.title; break;\n\t\t\t\t\tcase 'savesDisallowed':  value = strings.saves.disallowed; break;\n\t\t\t\t\tcase 'savesIncapable':   value = strings.saves.incapable; break;\n\t\t\t\t\tcase 'savesLabelAuto':   value = strings.saves.labelAuto; break;\n\t\t\t\t\tcase 'savesLabelDelete': value = strings.saves.labelDelete; break;\n\t\t\t\t\tcase 'savesLabelExport': value = strings.saves.labelExport; break;\n\t\t\t\t\tcase 'savesLabelImport': value = strings.saves.labelImport; break;\n\t\t\t\t\tcase 'savesLabelLoad':   value = strings.saves.labelLoad; break;\n\t\t\t\t\tcase 'savesLabelClear':  value = strings.saves.labelClear; break;\n\t\t\t\t\tcase 'savesLabelSave':   value = strings.saves.labelSave; break;\n\t\t\t\t\tcase 'savesLabelSlot':   value = strings.saves.labelSlot; break;\n\t\t\t\t\tcase 'savesUnavailable': value = strings.saves.unavailable; break;\n\t\t\t\t\tcase 'savesUnknownDate': value = strings.saves.unknownDate; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tSettings.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'settingsTitle': value = strings.settings.title; break;\n\t\t\t\t\tcase 'settingsOff':   value = strings.settings.off; break;\n\t\t\t\t\tcase 'settingsOn':    value = strings.settings.on; break;\n\t\t\t\t\tcase 'settingsReset': value = strings.settings.reset; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tRestart.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'restartTitle':  value = strings.restart.title; break;\n\t\t\t\t\tcase 'restartPrompt': value = strings.restart.prompt; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tShare.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'shareTitle': value = strings.share.title; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAlert.\n\t\t\t\t\t*/\n\t\t\t\t\t/* none */\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAutoload.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'autoloadTitle':  value = strings.autoload.title; break;\n\t\t\t\t\tcase 'autoloadCancel': value = strings.autoload.cancel; break;\n\t\t\t\t\tcase 'autoloadOk':     value = strings.autoload.ok; break;\n\t\t\t\t\tcase 'autoloadPrompt': value = strings.autoload.prompt; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tMacros.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'macroBackText':   value = strings.macros.back.text; break;\n\t\t\t\t\tcase 'macroReturnText': value = strings.macros.return.text; break;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (value) {\n\t\t\t\t\t\tl10nStrings[id] = value.replace(/%\\w+%/g, pat => `{${pat.slice(1, -1)}}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t});\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tLocalization Functions.\n\t\t*/\n\t\tinit : { value : l10nInit },\n\n\t\t/*\n\t\t\tLocalized String Functions.\n\t\t*/\n\t\tget : { value : l10nGet }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tl10n/legacy.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\t[DEPRECATED] The `strings` object is deprecated and should no longer be used.\n\tAll new or updated translations should be based upon the `l10nStrings` object\n\t(see: `l10n/strings.js`).\n\n\tLegacy/existing uses of the `strings` object will be mapped to the `l10nStrings`\n\tobject after user script evaluation.\n*/\nvar strings = { // eslint-disable-line no-unused-vars, no-var\n\terrors    : {},\n\twarnings  : {},\n\tdebugView : {},\n\tuiBar     : {},\n\tjumpto    : {},\n\tsaves     : {},\n\tsettings  : {},\n\trestart   : {},\n\tshare     : {},\n\tautoload  : {},\n\tmacros    : {\n\t\tback   : {},\n\t\treturn : {}\n\t}\n};\n\n/***********************************************************************************************************************\n\n\tl10n/strings.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* eslint-disable max-len, prefer-template */\n\n/*\n\tATTENTION TRANSLATORS\n\n\tPlease use the `locale/l10n-template.js` file, from the root of the repository,\n\tas the template for your translation rather than this file.\n\n\tSEE: https://github.com/tmedwards/sugarcube-2/tree/develop/locale\n*/\nvar l10nStrings = { // eslint-disable-line no-unused-vars, no-var\n\t/*\n\t\tGeneral.\n\t*/\n\tidentity : 'game',\n\taborting : 'Aborting',\n\tcancel   : 'Cancel',\n\tclose    : 'Close',\n\tok       : 'OK',\n\n\t/*\n\t\tErrors.\n\t*/\n\terrorTitle              : 'Error',\n\terrorToggle             : 'Toggle the error view',\n\terrorNonexistentPassage : 'the passage \"{passage}\" does not exist', // NOTE: `passage` is supplied locally\n\terrorSaveMissingData    : 'save is missing required data. Either the loaded file is not a save or the save has become corrupted',\n\terrorSaveIdMismatch     : 'save is from the wrong {identity}',\n\n\t/*\n\t\tWarnings.\n\t*/\n\t_warningIntroLacking  : 'Your browser either lacks or has disabled',\n\t_warningOutroDegraded : ', so this {identity} is running in a degraded mode. You may be able to continue, however, some parts may not work properly.',\n\twarningNoWebStorage   : '{_warningIntroLacking} the Web Storage API{_warningOutroDegraded}',\n\twarningDegraded       : '{_warningIntroLacking} some of the capabilities required by this {identity}{_warningOutroDegraded}',\n\n\t/*\n\t\tDebug bar.\n\t*/\n\tdebugBarToggle      : 'Toggle the debug bar',\n\tdebugBarNoWatches   : '\\u2014 no watches set \\u2014',\n\tdebugBarAddWatch    : 'Add watch',\n\tdebugBarDeleteWatch : 'Delete watch',\n\tdebugBarWatchAll    : 'Watch all',\n\tdebugBarWatchNone   : 'Delete all',\n\tdebugBarLabelAdd    : 'Add',\n\tdebugBarLabelWatch  : 'Watch',\n\tdebugBarLabelTurn   : 'Turn', // (noun) chance to act (in a game), moment, period\n\tdebugBarLabelViews  : 'Views',\n\tdebugBarViewsToggle : 'Toggle the debug views',\n\tdebugBarWatchToggle : 'Toggle the watch panel',\n\n\t/*\n\t\tUI bar.\n\t*/\n\tuiBarToggle   : 'Toggle the UI bar',\n\tuiBarBackward : 'Go backward within the {identity} history',\n\tuiBarForward  : 'Go forward within the {identity} history',\n\tuiBarJumpto   : 'Jump to a specific point within the {identity} history',\n\n\t/*\n\t\tJump To.\n\t*/\n\tjumptoTitle       : 'Jump To',\n\tjumptoTurn        : 'Turn', // (noun) chance to act (in a game), moment, period\n\tjumptoUnavailable : 'No jump points currently available\\u2026',\n\n\t/*\n\t\tSaves.\n\t*/\n\tsavesTitle       : 'Saves',\n\tsavesDisallowed  : 'Saving has been disallowed on this passage.',\n\tsavesIncapable   : '{_warningIntroLacking} the capabilities required to support saves, so saves have been disabled for this session.',\n\tsavesLabelAuto   : 'Autosave',\n\tsavesLabelDelete : 'Delete',\n\tsavesLabelExport : 'Save to Disk\\u2026',\n\tsavesLabelImport : 'Load from Disk\\u2026',\n\tsavesLabelLoad   : 'Load',\n\tsavesLabelClear  : 'Delete All',\n\tsavesLabelSave   : 'Save',\n\tsavesLabelSlot   : 'Slot',\n\tsavesUnavailable : 'No save slots found\\u2026',\n\tsavesUnknownDate : 'unknown',\n\n\t/*\n\t\tSettings.\n\t*/\n\tsettingsTitle : 'Settings',\n\tsettingsOff   : 'Off',\n\tsettingsOn    : 'On',\n\tsettingsReset : 'Reset to Defaults',\n\n\t/*\n\t\tRestart.\n\t*/\n\trestartTitle  : 'Restart',\n\trestartPrompt : 'Are you sure that you want to restart? Unsaved progress will be lost.',\n\n\t/*\n\t\tShare.\n\t*/\n\tshareTitle : 'Share',\n\n\t/*\n\t\tAlert.\n\t*/\n\t/* none */\n\n\t/*\n\t\tAutoload.\n\t*/\n\tautoloadTitle  : 'Autoload',\n\tautoloadCancel : 'Go to start',\n\tautoloadOk     : 'Load autosave',\n\tautoloadPrompt : 'An autosave exists. Load it now or go to the start?',\n\n\t/*\n\t\tMacros.\n\t*/\n\tmacroBackText   : 'Back',  // (verb) rewind, revert\n\tmacroReturnText : 'Return' // (verb) go/send back\n};\n\n/***********************************************************************************************************************\n\n\tconfig.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util */\n\nvar Config = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// General settings.\n\tlet _debug                 = false;\n\tlet _addVisitedLinkClass   = false;\n\tlet _cleanupWikifierOutput = false;\n\tlet _loadDelay             = 0;\n\n\t// Audio settings.\n\tlet _audioPauseOnFadeToZero = true;\n\tlet _audioPreloadMetadata   = true;\n\n\t// State history settings.\n\tlet _historyControls  = true;\n\tlet _historyMaxStates = 100;\n\n\t// Macros settings.\n\tlet _macrosIfAssignmentError = true;\n\tlet _macrosMaxLoopIterations = 1000;\n\n\t// Navigation settings.\n\tlet _navigationOverride;\n\n\t// Passages settings.\n\tlet _passagesDescriptions;\n\tlet _passagesDisplayTitles = false;\n\tlet _passagesNobr          = false;\n\tlet _passagesStart; // set by `Story.load()`\n\tlet _passagesOnProcess;\n\tlet _passagesTransitionOut;\n\n\t// Saves settings.\n\tlet _savesAutoload;\n\tlet _savesAutosave;\n\tlet _savesId        = 'untitled-story';\n\tlet _savesIsAllowed;\n\tlet _savesOnLoad;\n\tlet _savesOnSave;\n\tlet _savesSlots     = 8;\n\tlet _savesVersion;\n\n\t// UI settings.\n\tlet _uiStowBarInitially    = 800;\n\tlet _uiUpdateStoryElements = true;\n\n\n\t/*******************************************************************************\n\t\tError Constants.\n\t*******************************************************************************/\n\n\tconst _errHistoryModeDeprecated     = 'Config.history.mode has been deprecated and is no longer used by SugarCube, please remove it from your code';\n\tconst _errHistoryTrackingDeprecated = 'Config.history.tracking has been deprecated, use Config.history.maxStates instead';\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze({\n\t\t/*\n\t\t\tGeneral settings.\n\t\t*/\n\t\tget debug() { return _debug; },\n\t\tset debug(value) { _debug = Boolean(value); },\n\n\t\tget addVisitedLinkClass() { return _addVisitedLinkClass; },\n\t\tset addVisitedLinkClass(value) { _addVisitedLinkClass = Boolean(value); },\n\n\t\tget cleanupWikifierOutput() { return _cleanupWikifierOutput; },\n\t\tset cleanupWikifierOutput(value) { _cleanupWikifierOutput = Boolean(value); },\n\n\t\tget loadDelay() { return _loadDelay; },\n\t\tset loadDelay(value) {\n\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\tthrow new RangeError('Config.loadDelay must be a non-negative integer');\n\t\t\t}\n\n\t\t\t_loadDelay = value;\n\t\t},\n\n\t\t/*\n\t\t\tAudio settings.\n\t\t*/\n\t\taudio : Object.freeze({\n\t\t\tget pauseOnFadeToZero() { return _audioPauseOnFadeToZero; },\n\t\t\tset pauseOnFadeToZero(value) { _audioPauseOnFadeToZero = Boolean(value); },\n\n\t\t\tget preloadMetadata() { return _audioPreloadMetadata; },\n\t\t\tset preloadMetadata(value) { _audioPreloadMetadata = Boolean(value); }\n\t\t}),\n\n\t\t/*\n\t\t\tState history settings.\n\t\t*/\n\t\thistory : Object.freeze({\n\t\t\t// TODO: (v3) This should be under UI settings → `Config.ui.historyControls`.\n\t\t\tget controls() { return _historyControls; },\n\t\t\tset controls(value) {\n\t\t\t\tconst controls = Boolean(value);\n\n\t\t\t\tif (_historyMaxStates === 1 && controls) {\n\t\t\t\t\tthrow new Error('Config.history.controls must be false when Config.history.maxStates is 1');\n\t\t\t\t}\n\n\t\t\t\t_historyControls = controls;\n\t\t\t},\n\n\t\t\tget maxStates() { return _historyMaxStates; },\n\t\t\tset maxStates(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new RangeError('Config.history.maxStates must be a non-negative integer');\n\t\t\t\t}\n\n\t\t\t\t_historyMaxStates = value;\n\n\t\t\t\t// Force `Config.history.controls` to `false`, when limited to `1` moment.\n\t\t\t\tif (_historyControls && value === 1) {\n\t\t\t\t\t_historyControls = false;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// legacy\n\t\t\t// Die if deprecated state history settings are accessed.\n\t\t\tget mode()  { throw new Error(_errHistoryModeDeprecated); },\n\t\t\tset mode(_) { throw new Error(_errHistoryModeDeprecated); },\n\t\t\tget tracking()  { throw new Error(_errHistoryTrackingDeprecated); },\n\t\t\tset tracking(_) { throw new Error(_errHistoryTrackingDeprecated); }\n\t\t\t// /legacy\n\t\t}),\n\n\t\t/*\n\t\t\tMacros settings.\n\t\t*/\n\t\tmacros : Object.freeze({\n\t\t\tget ifAssignmentError() { return _macrosIfAssignmentError; },\n\t\t\tset ifAssignmentError(value) { _macrosIfAssignmentError = Boolean(value); },\n\n\t\t\tget maxLoopIterations() { return _macrosMaxLoopIterations; },\n\t\t\tset maxLoopIterations(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new RangeError('Config.macros.maxLoopIterations must be a non-negative integer');\n\t\t\t\t}\n\n\t\t\t\t_macrosMaxLoopIterations = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tNavigation settings.\n\t\t*/\n\t\tnavigation : Object.freeze({\n\t\t\tget override() { return _navigationOverride; },\n\t\t\tset override(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.navigation.override must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_navigationOverride = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tPassages settings.\n\t\t*/\n\t\tpassages : Object.freeze({\n\t\t\tget descriptions() { return _passagesDescriptions; },\n\t\t\tset descriptions(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'boolean' && valueType !== 'Object' && valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.descriptions must be a boolean, object, function, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesDescriptions = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.updateTitle`.\n\t\t\tget displayTitles() { return _passagesDisplayTitles; },\n\t\t\tset displayTitles(value) { _passagesDisplayTitles = Boolean(value); },\n\n\t\t\tget nobr() { return _passagesNobr; },\n\t\t\tset nobr(value) { _passagesNobr = Boolean(value); },\n\n\t\t\tget onProcess() { return _passagesOnProcess; },\n\t\t\tset onProcess(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.onProcess must be a function or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesOnProcess = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.(start|startingPassage)`.\n\t\t\tget start() { return _passagesStart; },\n\t\t\tset start(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'string') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.start must be a string or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesStart = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.transitionOut`.\n\t\t\tget transitionOut() { return _passagesTransitionOut; },\n\t\t\tset transitionOut(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t   valueType !== 'string'\n\t\t\t\t\t\t&& (valueType !== 'number' || !Number.isSafeInteger(value) || value < 0)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.transitionOut must be a string, non-negative integer, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesTransitionOut = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tSaves settings.\n\t\t*/\n\t\tsaves : Object.freeze({\n\t\t\tget autoload() { return _savesAutoload; },\n\t\t\tset autoload(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'boolean' && valueType !== 'string' && valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.saves.autoload must be a boolean, string, function, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_savesAutoload = value;\n\t\t\t},\n\n\t\t\tget autosave() { return _savesAutosave; },\n\t\t\tset autosave(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\t// legacy\n\t\t\t\t\t// Convert a string value to an Array of string.\n\t\t\t\t\tif (valueType === 'string') {\n\t\t\t\t\t\t_savesAutosave = [value];\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// /legacy\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t   valueType !== 'boolean'\n\t\t\t\t\t\t&& (valueType !== 'Array' || !value.every(item => typeof item === 'string'))\n\t\t\t\t\t\t&& valueType !== 'function'\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new TypeError(`Config.saves.autosave must be a boolean, Array of strings, function, or null/undefined (received: ${valueType}${valueType === 'Array' ? ' of mixed' : ''})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_savesAutosave = value;\n\t\t\t},\n\n\t\t\tget id() { return _savesId; },\n\t\t\tset id(value) {\n\t\t\t\tif (typeof value !== 'string' || value === '') {\n\t\t\t\t\tthrow new TypeError(`Config.saves.id must be a non-empty string (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesId = value;\n\t\t\t},\n\n\t\t\tget isAllowed() { return _savesIsAllowed; },\n\t\t\tset isAllowed(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.isAllowed must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesIsAllowed = value;\n\t\t\t},\n\n\t\t\tget onLoad() { return _savesOnLoad; },\n\t\t\tset onLoad(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.onLoad must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesOnLoad = value;\n\t\t\t},\n\n\t\t\tget onSave() { return _savesOnSave; },\n\t\t\tset onSave(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.onSave must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesOnSave = value;\n\t\t\t},\n\n\t\t\tget slots() { return _savesSlots; },\n\t\t\tset slots(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new TypeError(`Config.saves.slots must be a non-negative integer (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesSlots = value;\n\t\t\t},\n\n\t\t\tget version() { return _savesVersion; },\n\t\t\tset version(value) { _savesVersion = value; }\n\t\t}),\n\n\t\t/*\n\t\t\tUI settings.\n\t\t*/\n\t\tui : Object.freeze({\n\t\t\tget stowBarInitially() { return _uiStowBarInitially; },\n\t\t\tset stowBarInitially(value) {\n\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\tif (\n\t\t\t\t\t   valueType !== 'boolean'\n\t\t\t\t\t&& (valueType !== 'number' || !Number.isSafeInteger(value) || value < 0)\n\t\t\t\t) {\n\t\t\t\t\tthrow new TypeError(`Config.ui.stowBarInitially must be a boolean or non-negative integer (received: ${valueType})`);\n\t\t\t\t}\n\n\t\t\t\t_uiStowBarInitially = value;\n\t\t\t},\n\n\t\t\tget updateStoryElements() { return _uiUpdateStoryElements; },\n\t\t\tset updateStoryElements(value) { _uiUpdateStoryElements = Boolean(value); }\n\t\t})\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tsimpleaudio.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser, Config, Has, LoadScreen, Story, Util, Visibility, clone */\n\nvar SimpleAudio = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tEvents that count as user activation—i.e. \"user gestures\", \"activation behavior\".\n\n\t\tNOTE (ca. Dec, 2018): This not an exhaustive list and varies significantly by browser.\n\t\tProposals for a specification/standard are still very much in flux at this point.\n\n\t\tTODO (ca. Dec, 2018): Revisit this topic.\n\n\t\tSEE: (too many to list)\n\t\t\thttps://github.com/whatwg/html/issues/3849\n\t\t\thttps://github.com/whatwg/html/issues/1903\n\t\t\thttps://html.spec.whatwg.org/#activation\n\t\t\thttps://docs.google.com/spreadsheets/d/1DGXjhQ6D3yZXIePOMo0dsd2agz0t5W7rYH1NwJ-QGJo/edit#gid=0\n\t*/\n\tconst _gestureEventNames = Object.freeze(['click', 'contextmenu', 'dblclick', 'keyup', 'mouseup', 'pointerup', 'touchend']);\n\n\t// Special group IDs.\n\tconst _specialIds = Object.freeze([':not', ':all', ':looped', ':muted', ':paused', ':playing']);\n\n\t// Format specifier regular expression.\n\tconst _formatSpecRe = /^([\\w-]+)\\s*\\|\\s*(\\S.*)$/; // e.g. 'mp3|https://audiohost.tld/id'\n\n\t// ID verification regular expressions.\n\tconst _badIdRe = /[:\\s]/;\n\n\t// Tracks collection.\n\tconst _tracks = new Map();\n\n\t// Groups collection.\n\tconst _groups = new Map();\n\n\t// Playlists collection.\n\tconst _lists = new Map();\n\n\t// Subscriber collection.\n\tconst _subscribers = new Map();\n\n\t// Master playback rate.\n\tlet _masterRate = 1;\n\n\t// Master playback volume.\n\tlet _masterVolume = 1;\n\n\t// Master mute state.\n\tlet _masterMute = false;\n\n\t// Master mute on tab/window visibility state.\n\tlet _masterMuteOnHidden = false;\n\n\n\t/*******************************************************************************************************************\n\t\tFeature Detection Functions.\n\t*******************************************************************************************************************/\n\t// Return whether the `<HTMLAudioElement>.play()` method returns a `Promise`.\n\t//\n\t// NOTE: The initial result is cached for future calls.\n\tconst _playReturnsPromise = (function () {\n\t\t// Cache of whether `<HTMLAudioElement>.play()` returns a `Promise`.\n\t\tlet _hasPromise = null;\n\n\t\tfunction _playReturnsPromise() {\n\t\t\tif (_hasPromise !== null) {\n\t\t\t\treturn _hasPromise;\n\t\t\t}\n\n\t\t\t_hasPromise = false;\n\n\t\t\tif (Has.audio) {\n\t\t\t\ttry {\n\t\t\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t\t\t// NOTE (ca. Jan 01, 2020): Firefox will still log an \"Autoplay is only allowed\n\t\t\t\t\t// when […] media is muted.\" message to the console when attempting the test\n\t\t\t\t\t// below, even though the audio has been muted.  Stay classy, Firefox.\n\t\t\t\t\t//\n\t\t\t\t\t// QUESTION (ca. Jan 01, 2020): Keep this?  It's only here to appease Firefox,\n\t\t\t\t\t// but doesn't seem to work as Firefox seems to ignore mute in violation of the\n\t\t\t\t\t// `HTMLAudioElement` specification—willfully or simply a bug, I can't say.\n\t\t\t\t\taudio.muted = true;\n\n\t\t\t\t\tconst value = audio.play();\n\n\t\t\t\t\t// Silence \"Uncaught (in promise)\" console errors from Blink.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: Swallowing errors is generally bad, but in this case we know there's\n\t\t\t\t\t// going to be an error regardless, since there's no source, and we don't actually\n\t\t\t\t\t// care about the error, since we just want the return value, so we consign it\n\t\t\t\t\t// to the bit bucket.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: We don't ensure that the return value is not `undefined` here because\n\t\t\t\t\t// having the attempted call to `<Promise>.catch()` on an `undefined` value throw\n\t\t\t\t\t// is acceptable, since it will be caught and `false` eventually returned.\n\t\t\t\t\tvalue.catch(() => { /* no-op */ });\n\n\t\t\t\t\t_hasPromise = value instanceof Promise;\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t}\n\n\t\t\treturn _hasPromise;\n\t\t}\n\n\t\treturn _playReturnsPromise;\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tAudioTrack Class.\n\t*******************************************************************************************************************/\n\tclass AudioTrack {\n\t\tconstructor(obj) {\n\t\t\t// Process the given array of sources or AudioTrack object.\n\t\t\tif (obj instanceof Array) {\n\t\t\t\tthis._create(obj);\n\t\t\t}\n\t\t\telse if (obj instanceof AudioTrack) {\n\t\t\t\tthis._copy(obj);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('sources parameter must be either an array, of URIs or source objects, or an AudioTrack instance');\n\t\t\t}\n\t\t}\n\n\t\t_create(sourceList) {\n\t\t\tconst dataUriRe   = /^data:\\s*audio\\/([^;,]+)\\s*[;,]/i;\n\t\t\tconst extRe       = /\\.([^./\\\\]+)$/;\n\t\t\tconst getType     = AudioTrack.getType;\n\t\t\tconst usedSources = [];\n\t\t\t/*\n\t\t\t\tHTMLAudioElement: DOM factory method vs. constructor\n\n\t\t\t\tUse of the DOM factory method, `document.createElement('audio')`, should be\n\t\t\t\tpreferred over use of the constructor, `new Audio()`.  The reason being that\n\t\t\t\tobjects created by the latter are, erroneously, treated differently, often\n\t\t\t\tunfavorably, by certain browser engines—e.g. within some versions of the iOS\n\t\t\t\tbrowser core.\n\n\t\t\t\tNotably, the only difference between the two, per the specification, is that\n\t\t\t\tobjects created via the constructor should have their `preload` property\n\t\t\t\tautomatically set to 'auto'.  Thus, there's no technical reason to prefer\n\t\t\t\tusage of the constructor, even discounting buggy browser implementations.\n\t\t\t*/\n\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t// Initially set the `preload` attribute to `'none'`.\n\t\t\taudio.preload = 'none';\n\n\t\t\t// Process the array of sources, adding any valid sources to the `usedSources`\n\t\t\t// array and to the audio element as source elements.\n\t\t\tsourceList.forEach(src => {\n\t\t\t\tlet srcObj = null;\n\n\t\t\t\tswitch (typeof src) {\n\t\t\t\tcase 'string':\n\t\t\t\t\t{\n\t\t\t\t\t\tlet match;\n\n\t\t\t\t\t\tif (src.slice(0, 5) === 'data:') {\n\t\t\t\t\t\t\tmatch = dataUriRe.exec(src);\n\n\t\t\t\t\t\t\tif (match === null) {\n\t\t\t\t\t\t\t\tthrow new Error('source data URI missing media type');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tmatch = extRe.exec(Util.parseUrl(src).pathname);\n\n\t\t\t\t\t\t\tif (match === null) {\n\t\t\t\t\t\t\t\tthrow new Error('source URL missing file extension');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst type = getType(match[1]);\n\n\t\t\t\t\t\tif (type !== null) {\n\t\t\t\t\t\t\tsrcObj = { src, type };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\t{\n\t\t\t\t\t\tif (src === null) {\n\t\t\t\t\t\t\tthrow new Error('source object cannot be null');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (!src.hasOwnProperty('src')) {\n\t\t\t\t\t\t\tthrow new Error('source object missing required \"src\" property');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (!src.hasOwnProperty('format')) {\n\t\t\t\t\t\t\tthrow new Error('source object missing required \"format\" property');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst type = getType(src.format);\n\n\t\t\t\t\t\tif (type !== null) {\n\t\t\t\t\t\t\tsrcObj = { src : src.src, type };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`invalid source value (type: ${typeof src})`);\n\t\t\t\t}\n\n\t\t\t\tif (srcObj !== null) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tOpera (Blink; ca. Jul 2017) fails to play audio from some sources\n\t\t\t\t\t\twith MIME-types containing a `codecs` parameter, despite the fact\n\t\t\t\t\t\tthat `canPlayType()` blessed the full MIME-type including `codecs`.\n\n\t\t\t\t\t\tBizarrely, this only affects some MIME-types—e.g. MP3s are affected,\n\t\t\t\t\t\twhile WAVEs are not.\n\t\t\t\t\t\t\tFails: 'audio/mpeg; codecs=\"mp3\"'\n\t\t\t\t\t\t\tPlays: 'audio/mpeg'\n\t\t\t\t\t\t\tPlays: 'audio/wav; codecs=\"1\"'\n\n\t\t\t\t\t\tTo workaround this we remove all parameters from the MIME-type in\n\t\t\t\t\t\tOpera.\n\t\t\t\t\t*/\n\t\t\t\t\tif (Browser.isOpera) {\n\t\t\t\t\t\tsrcObj.type =  srcObj.type.replace(/;.*$/, '');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst source = document.createElement('source');\n\t\t\t\t\tsource.src  = srcObj.src;\n\t\t\t\t\tsource.type = srcObj.type;\n\t\t\t\t\taudio.appendChild(source);\n\t\t\t\t\tusedSources.push(srcObj);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (audio.hasChildNodes()) {\n\t\t\t\t// Set the `preload` attribute to `'metadata'`, unless preloading has been disabled.\n\t\t\t\tif (Config.audio.preloadMetadata) {\n\t\t\t\t\taudio.preload = 'metadata';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._finalize(audio, usedSources, clone(sourceList));\n\t\t}\n\n\t\t_copy(obj) {\n\t\t\tthis._finalize(\n\t\t\t\tobj.audio.cloneNode(true), // deep clone of the audio element & its children\n\t\t\t\tclone(obj.sources),\n\t\t\t\tclone(obj.originals)\n\t\t\t);\n\t\t}\n\n\t\t_finalize(audio, sources, originals) {\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\taudio : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : audio\n\t\t\t\t},\n\n\t\t\t\tsources : {\n\t\t\t\t\tvalue : Object.freeze(sources)\n\t\t\t\t},\n\n\t\t\t\toriginals : {\n\t\t\t\t\tvalue : Object.freeze(originals)\n\t\t\t\t},\n\n\t\t\t\t_error : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_faderId : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_mute : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_rate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_volume : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Set up event handlers on the audio and source elements.\n\t\t\tjQuery(this.audio)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving a `loadstart` event on the audio element, set `_error` to\n\t\t\t\t\t`false`.\n\t\t\t\t*/\n\t\t\t\t.on('loadstart.AudioTrack', () => this._error = false)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving an `error` event on the audio element, set `_error` to\n\t\t\t\t\t`true`.\n\n\t\t\t\t\tCaveats by browser:\n\t\t\t\t\t\tEdge violates the specification by triggering `error` events from source\n\t\t\t\t\t\telements on their parent media element, rather than the source element.\n\t\t\t\t\t\tTo enable error handling in all browsers, we set the error handler on the\n\t\t\t\t\t\taudio element and have the final source element forward its `error` event.\n\n\t\t\t\t\t\tIE does not trigger, at least some, `error` events from source elements at\n\t\t\t\t\t\tall, not on the source element or its parent media element.  AFAIK, nothing\n\t\t\t\t\t\tcan be done about this lossage.\n\t\t\t\t*/\n\t\t\t\t.on('error.AudioTrack', () => this._error = true)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving an `error` event on the final source element (if any), trigger\n\t\t\t\t\tan `error` event on the audio element—that being necessary because the source\n\t\t\t\t\t`error` event does not bubble.\n\t\t\t\t*/\n\t\t\t\t.find('source:last-of-type')\n\t\t\t\t.on('error.AudioTrack', () => this._trigger('error'));\n\n\t\t\t// Subscribe to command messages.\n\t\t\tsubscribe(this, mesg => {\n\t\t\t\tif (!this.audio) {\n\t\t\t\t\tunsubscribe(this);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch (mesg) {\n\t\t\t\tcase 'loadwithscreen':\n\t\t\t\t\tif (this.hasSource()) {\n\t\t\t\t\t\tconst lockId = LoadScreen.lock();\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t// NOTE: Do not use an arrow function here.\n\t\t\t\t\t\t\t.one(\n\t\t\t\t\t\t\t\t'canplaythrough.AudioTrack_loadwithscreen error.AudioTrack_loadwithscreen',\n\t\t\t\t\t\t\t\tfunction () {\n\t\t\t\t\t\t\t\t\tjQuery(this).off('.AudioTrack_loadwithscreen');\n\t\t\t\t\t\t\t\t\tLoadScreen.unlock(lockId);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.load();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'load':   this.load();               break;\n\t\t\t\tcase 'mute':   this._updateAudioMute();   break;\n\t\t\t\tcase 'rate':   this._updateAudioRate();   break;\n\t\t\t\tcase 'stop':   this.stop();               break;\n\t\t\t\tcase 'volume': this._updateAudioVolume(); break;\n\t\t\t\tcase 'unload': this.unload();             break;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Synchronize with the current master audio settings.\n\t\t\tthis._updateAudioMute();\n\t\t\tthis._updateAudioRate();\n\t\t\tthis._updateAudioVolume();\n\t\t}\n\n\t\t_trigger(eventName) {\n\t\t\t// Do not use `trigger()` here as we do not want these events to bubble.\n\t\t\tjQuery(this.audio).triggerHandler(eventName);\n\t\t}\n\n\t\t_destroy() {\n\t\t\t/*\n\t\t\t\tStrictly speaking, self-destruction is not necessary as this object will,\n\t\t\t\teventually, be garbage collected.  That said, since the audio element contains\n\t\t\t\tdata buffers for the selected audio source, which may be quite large, manually\n\t\t\t\tpurging them as soon as we know that they're no longer needed is not a bad idea.\n\t\t\t*/\n\t\t\tunsubscribe(this);\n\n\t\t\tif (!this.audio) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tjQuery(this.audio).off();\n\t\t\tthis.unload();\n\t\t\tthis._error = true;\n\n\t\t\t// Delete the audio element property.\n\t\t\tdelete this.audio;\n\t\t}\n\n\t\tclone() {\n\t\t\treturn new AudioTrack(this);\n\t\t}\n\n\t\tload() {\n\t\t\tthis.fadeStop();\n\t\t\tthis.audio.pause();\n\n\t\t\tif (!this.audio.hasChildNodes()) {\n\t\t\t\tif (this.sources.length === 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.sources.forEach(srcObj => {\n\t\t\t\t\tconst source = document.createElement('source');\n\t\t\t\t\tsource.src  = srcObj.src;\n\t\t\t\t\tsource.type = srcObj.type;\n\t\t\t\t\tthis.audio.appendChild(source);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (this.audio.preload !== 'auto') {\n\t\t\t\tthis.audio.preload = 'auto';\n\t\t\t}\n\n\t\t\tif (!this.isLoading()) {\n\t\t\t\tthis.audio.load();\n\t\t\t}\n\t\t}\n\n\t\tunload() {\n\t\t\tthis.fadeStop();\n\t\t\tthis.stop();\n\n\t\t\tconst audio = this.audio;\n\t\t\taudio.preload = 'none';\n\n\t\t\t// Remove all source elements.\n\t\t\twhile (audio.hasChildNodes()) {\n\t\t\t\taudio.removeChild(audio.firstChild);\n\t\t\t}\n\n\t\t\t// Force the audio element to drop any existing data buffers.\n\t\t\taudio.load();\n\t\t}\n\n\t\tplay() {\n\t\t\tif (!this.hasSource()) {\n\t\t\t\treturn Promise.reject(new Error('none of the candidate sources were acceptable'));\n\t\t\t}\n\n\t\t\tif (this.isUnloaded()) {\n\t\t\t\treturn Promise.reject(new Error('no sources are loaded'));\n\t\t\t}\n\n\t\t\tif (this.isFailed()) {\n\t\t\t\treturn Promise.reject(new Error('failed to load any of the sources'));\n\t\t\t}\n\n\t\t\tif (this.audio.preload !== 'auto') {\n\t\t\t\tthis.audio.preload = 'auto';\n\t\t\t}\n\n\t\t\tconst namespace = '.AudioTrack_play';\n\n\t\t\treturn _playReturnsPromise()\n\t\t\t\t? this.audio.play()\n\t\t\t\t: new Promise((resolve, reject) => {\n\t\t\t\t\tif (this.isPlaying()) {\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tjQuery(this.audio)\n\t\t\t\t\t\t\t.off(namespace)\n\t\t\t\t\t\t\t.one(`error${namespace} playing${namespace} timeupdate${namespace}`, ev => {\n\t\t\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\t\t\tif (ev.type === 'error') {\n\t\t\t\t\t\t\t\t\treject(new Error('unknown audio play error'));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.audio.play();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tthis.play().catch(() => {\n\t\t\t\tconst gestures = _gestureEventNames.map(name => `${name}.AudioTrack_playWhenAllowed`).join(' ');\n\t\t\t\tjQuery(document).one(gestures, () => {\n\t\t\t\t\tjQuery(document).off('.AudioTrack_playWhenAllowed');\n\t\t\t\t\tthis.audio.play();\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tpause() {\n\t\t\tthis.audio.pause();\n\t\t}\n\n\t\tstop() {\n\t\t\tthis.audio.pause();\n\t\t\tthis.time(0);\n\t\t\tthis._trigger(':stopped');\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (typeof duration !== 'number') {\n\t\t\t\tthrow new TypeError('duration parameter must be a number');\n\t\t\t}\n\t\t\tif (typeof toVol !== 'number') {\n\t\t\t\tthrow new TypeError('toVolume parameter must be a number');\n\t\t\t}\n\t\t\tif (fromVol != null && typeof fromVol !== 'number') { // lazy equality for null\n\t\t\t\tthrow new TypeError('fromVolume parameter must be a number');\n\t\t\t}\n\n\t\t\tif (!this.hasSource()) {\n\t\t\t\treturn Promise.reject(new Error('none of the candidate sources were acceptable'));\n\t\t\t}\n\n\t\t\tif (this.isUnloaded()) {\n\t\t\t\treturn Promise.reject(new Error('no sources are loaded'));\n\t\t\t}\n\n\t\t\tif (this.isFailed()) {\n\t\t\t\treturn Promise.reject(new Error('failed to load any of the sources'));\n\t\t\t}\n\n\t\t\tthis.fadeStop();\n\n\t\t\tconst from = Math.clamp(fromVol == null ? this.volume() : fromVol, 0, 1); // lazy equality for null\n\t\t\tconst to   = Math.clamp(toVol, 0, 1);\n\n\t\t\tif (from === to) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.volume(from);\n\n\t\t\t/*\n\t\t\t\tWe listen for the `timeupdate` event here, rather than `playing`, because\n\t\t\t\tvarious browsers (notably, mobile browsers) are poor at firing media events\n\t\t\t\tin a timely fashion, so we use `timeupdate` to ensure that we don't start\n\t\t\t\tthe fade until the track is actually progressing.\n\t\t\t*/\n\t\t\tjQuery(this.audio)\n\t\t\t\t.off('timeupdate.AudioTrack_fade')\n\t\t\t\t.one('timeupdate.AudioTrack_fade', () => {\n\t\t\t\t\tlet min;\n\t\t\t\t\tlet max;\n\n\t\t\t\t\t// Fade in.\n\t\t\t\t\tif (from < to) {\n\t\t\t\t\t\tmin = from;\n\t\t\t\t\t\tmax = to;\n\t\t\t\t\t}\n\t\t\t\t\t// Fade out.\n\t\t\t\t\telse {\n\t\t\t\t\t\tmin = to;\n\t\t\t\t\t\tmax = from;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst time     = Math.max(duration, 1);\n\t\t\t\t\tconst interval = 25; // in milliseconds\n\t\t\t\t\tconst delta    = (to - from) / (time / (interval / 1000));\n\n\t\t\t\t\tthis._trigger(':fading');\n\t\t\t\t\tthis._faderId = setInterval(() => {\n\t\t\t\t\t\tif (!this.isPlaying()) {\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tWhile it may seem like a good idea to also set the track volume\n\t\t\t\t\t\t\t\tto the `to` value here, we should not do so.  We cannot know why\n\t\t\t\t\t\t\t\tthe track is no longer playing, nor if the volume has been modified\n\t\t\t\t\t\t\t\tin the interim, so doing so now may clobber an end-user set volume.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tthis.fadeStop();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthis.volume(Math.clamp(this.volume() + delta, min, max));\n\n\t\t\t\t\t\tif (Config.audio.pauseOnFadeToZero && this.volume() === 0) {\n\t\t\t\t\t\t\tthis.pause();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.volume() === to) {\n\t\t\t\t\t\t\tthis.fadeStop();\n\t\t\t\t\t\t\tthis._trigger(':faded');\n\t\t\t\t\t\t}\n\t\t\t\t\t}, interval);\n\t\t\t\t});\n\n\t\t\treturn this.play();\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\treturn this.fade(duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\treturn this.fade(duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tif (this._faderId !== null) {\n\t\t\t\tclearInterval(this._faderId);\n\t\t\t\tthis._faderId = null;\n\t\t\t}\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\treturn this.audio.loop;\n\t\t\t}\n\n\t\t\tthis.audio.loop = !!loop;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\treturn this._mute;\n\t\t\t}\n\n\t\t\tthis._mute = !!mute;\n\t\t\tthis._updateAudioMute();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioMute() {\n\t\t\tthis.audio.muted = this._mute || _masterMute;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\treturn this._rate;\n\t\t\t}\n\n\t\t\tif (typeof rate !== 'number') {\n\t\t\t\tthrow new TypeError('rate parameter must be a number');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tClamp the playback rate to sane values—some browsers also do this to varying degrees.\n\n\t\t\t\tNOTE (ca. Aug 2016): The specification allows negative values for reverse playback,\n\t\t\t\thowever, most browsers either completely ignore negative values or clamp them to\n\t\t\t\tsome positive value.  In some (notably, IE & Edge), setting a negative playback\n\t\t\t\trate breaks the associated controls, if displayed.\n\t\t\t*/\n\t\t\t/*\n\t\t\tthis._rate = rate < 0\n\t\t\t\t? Math.clamp(rate, -0.2, -5) // clamp to 5× slower & faster, backward\n\t\t\t\t: Math.clamp(rate, 0.2, 5);  // clamp to 5× slower & faster, forward\n\t\t\t*/\n\t\t\tthis._rate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\t\t\tthis._updateAudioRate();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioRate() {\n\t\t\t/*\n\t\t\tconst rate = this._rate * _masterRate;\n\t\t\tthis.audio.playbackRate = rate < 0\n\t\t\t\t? Math.clamp(rate, -0.2, -5) // clamp to 5× slower & faster, backward\n\t\t\t\t: Math.clamp(rate, 0.2, 5);  // clamp to 5× slower & faster, forward\n\t\t\t*/\n\t\t\tthis.audio.playbackRate = Math.clamp(this._rate * _masterRate, 0.2, 5); // clamp to 5× slower & faster\n\t\t}\n\n\t\ttime(time) {\n\t\t\tif (time == null) { // lazy equality for null\n\t\t\t\treturn this.audio.currentTime;\n\t\t\t}\n\n\t\t\tif (typeof time !== 'number') {\n\t\t\t\tthrow new TypeError('time parameter must be a number');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tNOTE (historic): If we try to modify the audio clip's `.currentTime` property\n\t\t\t\tbefore its metadata has been loaded, it will throw an `InvalidStateError`\n\t\t\t\t(since it doesn't know its duration, allowing `.currentTime` to be set would\n\t\t\t\tbe undefined behavior), so in case an exception is thrown we provide a fallback\n\t\t\t\tusing the `loadedmetadata` event.\n\n\t\t\t\tNOTE (ca. 2016): This workaround should no longer be necessary in most browsers.\n\t\t\t\tThat said, it will still be required for some time to service legacy browsers.\n\n\t\t\t\tNOTE (ca. Dec 09, 2018): Firefox will still log an `InvalidStateError` to the\n\t\t\t\tconsole when attempting to modify the clip's `.currentTime` property before its\n\t\t\t\tmetadata has been loaded, even though it handles the situation properly—by waiting\n\t\t\t\tfor the metadata, as all browsers do now.  To prevent this spurious logging, we\n\t\t\t\tmust now manually check for the existence of the metadata and always failover to\n\t\t\t\tan event regardless of if the browser needs it or not—because I don't want to\n\t\t\t\tintroduce a browser check here.  Stay classy, Firefox.\n\t\t\t*/\n\t\t\tif (this.hasMetadata()) {\n\t\t\t\tthis.audio.currentTime = time;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery(this.audio)\n\t\t\t\t\t.off('loadedmetadata.AudioTrack_time')\n\t\t\t\t\t.one('loadedmetadata.AudioTrack_time', () => this.audio.currentTime = time);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\treturn this._volume;\n\t\t\t}\n\n\t\t\tif (typeof volume !== 'number') {\n\t\t\t\tthrow new TypeError('volume parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._volume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\t\t\tthis._updateAudioVolume();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioVolume() {\n\t\t\tthis.audio.volume = Math.clamp(this._volume * _masterVolume, 0, 1);\n\t\t}\n\n\t\tduration() {\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.audio.duration;\n\t\t}\n\n\t\tremaining() {\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.audio.duration - this.audio.currentTime;\n\t\t}\n\n\t\tisFailed() {\n\t\t\treturn this._error;\n\t\t}\n\n\t\tisLoading() {\n\t\t\treturn this.audio.networkState === HTMLMediaElement.NETWORK_LOADING;\n\t\t}\n\n\t\tisUnloaded() {\n\t\t\treturn !this.audio.hasChildNodes();\n\t\t}\n\n\t\tisUnavailable() {\n\t\t\treturn !this.hasSource() || this.isUnloaded() || this.isFailed();\n\t\t}\n\n\t\tisPlaying() {\n\t\t\t// NOTE: The `this.hasSomeData()` check is probably no longer necessary.\n\t\t\treturn !this.audio.paused && this.hasSomeData();\n\t\t}\n\n\t\tisPaused() {\n\t\t\t/*\n\t\t\t\tIf the selected audio resource is a stream, `currentTime` may return a non-zero\n\t\t\t\tvalue even at the earliest available position within the stream as the browser\n\t\t\t\tmay have dropped the earliest chunks of buffered data or the stream may have a\n\t\t\t\ttimeline which does not start at zero.\n\n\t\t\t\tIn an attempt to guard against these possiblities, as best as we can, we test\n\t\t\t\t`duration` against `Infinity` first, which should yield true for actual streams.\n\t\t\t*/\n\t\t\treturn this.audio.paused\n\t\t\t\t&& (this.audio.duration === Infinity || this.audio.currentTime > 0)\n\t\t\t\t&& !this.audio.ended;\n\t\t}\n\n\t\tisStopped() {\n\t\t\treturn this.audio.paused && this.audio.currentTime === 0;\n\t\t}\n\n\t\tisEnded() {\n\t\t\treturn this.audio.ended;\n\t\t}\n\n\t\tisFading() {\n\t\t\treturn this._faderId !== null;\n\t\t}\n\n\t\tisSeeking() {\n\t\t\treturn this.audio.seeking;\n\t\t}\n\n\t\thasSource() {\n\t\t\treturn this.sources.length > 0;\n\t\t}\n\n\t\thasNoData() {\n\t\t\treturn this.audio.readyState === HTMLMediaElement.HAVE_NOTHING;\n\t\t}\n\n\t\thasMetadata() {\n\t\t\treturn this.audio.readyState >= HTMLMediaElement.HAVE_METADATA;\n\t\t}\n\n\t\thasSomeData() {\n\t\t\treturn this.audio.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA;\n\t\t}\n\n\t\thasData() {\n\t\t\treturn this.audio.readyState === HTMLMediaElement.HAVE_ENOUGH_DATA;\n\t\t}\n\n\t\ton(...args) {\n\t\t\tjQuery.fn.on.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\tone(...args) {\n\t\t\tjQuery.fn.one.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\toff(...args) {\n\t\t\tjQuery.fn.off.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\t/*\n\t\t\tVerifies that the browser supports the given MIME-type and then retuns either\n\t\t\tthe MIME-type, if it is supported, or `null`, if it is not.\n\t\t*/\n\t\tstatic _verifyType(type) {\n\t\t\tif (!type || !Has.audio) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst cache = AudioTrack._types;\n\n\t\t\tif (!cache.hasOwnProperty(type)) {\n\t\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t\t// Some early implementations return 'no' instead of the empty string.\n\t\t\t\tcache[type] = audio.canPlayType(type).replace(/^no$/i, '') !== '';\n\t\t\t}\n\n\t\t\treturn cache[type] ? type : null;\n\t\t}\n\n\t\t/*\n\t\t\tRetuns the MIME-type associated with the given format-ID, if it is supported,\n\t\t\telsewise `null`.\n\t\t*/\n\t\tstatic getType(format) {\n\t\t\tif (!format || !Has.audio) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst known = AudioTrack.formats;\n\t\t\tconst id    = format.toLowerCase();\n\t\t\tconst type  = known.hasOwnProperty(id) ? known[id] : `audio/${id}`;\n\n\t\t\treturn AudioTrack._verifyType(type);\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the browser potentially supports a format.\n\t\t*/\n\t\tstatic canPlayFormat(format) {\n\t\t\treturn AudioTrack.getType(format) !== null;\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the browser potentially supports a MIME-type.\n\t\t*/\n\t\tstatic canPlayType(type) {\n\t\t\treturn AudioTrack._verifyType(type) !== null;\n\t\t}\n\t}\n\n\t// Attach the static data members.\n\tObject.defineProperties(AudioTrack, {\n\t\t/*\n\t\t\tFormat-ID to MIME-type mappings for common audio types.\n\n\t\t\tIn most cases, the codecs property should not be included with the MIME-type,\n\t\t\tas we have no way of knowing which codec was used—and the browser will figure\n\t\t\tit out.  Conversely, in cases where the relationship relationship between a\n\t\t\tformat-ID and a specific codec is strong, we should include the codecs property.\n\n\t\t\tNOTE: Caveats by browser/engine:\n\t\t\t\tOpera ≤12 (Presto) will return a false-negative if the codecs value is quoted\n\t\t\t\twith single quotes, requiring the use of either double quotes or no quotes.\n\n\t\t\t\tBlink-based browsers (e.g. Chrome, Opera ≥15) will return a false-negative\n\t\t\t\tfor WAVE audio if the preferred MIME-type of 'audio/wave' is specified,\n\t\t\t\trequiring the use of 'audio/wav' instead.\n\t\t*/\n\t\tformats : {\n\t\t\tvalue : { // Leave this object extensible for users.\n\t\t\t\t// AAC — MPEG-2 AAC audio; specific profiles vary, but commonly \"AAC-LC\".\n\t\t\t\taac : 'audio/aac',\n\n\t\t\t\t// CAF — Codecs vary.\n\t\t\t\tcaf     : 'audio/x-caf',\n\t\t\t\t'x-caf' : 'audio/x-caf',\n\n\t\t\t\t// MP3 — MPEG-1/-2 Layer-III audio.\n\t\t\t\tmp3  : 'audio/mpeg; codecs=\"mp3\"',\n\t\t\t\tmpeg : 'audio/mpeg; codecs=\"mp3\"',\n\n\t\t\t\t// MP4 — Codecs vary, but commonly \"mp4a.40.2\" (a.k.a. \"AAC-LC\").\n\t\t\t\tm4a     : 'audio/mp4',\n\t\t\t\tmp4     : 'audio/mp4',\n\t\t\t\t'x-m4a' : 'audio/mp4',\n\t\t\t\t'x-mp4' : 'audio/mp4',\n\n\t\t\t\t// OGG — Codecs vary, but commonly \"vorbis\" and, recently, \"opus\".\n\t\t\t\toga : 'audio/ogg',\n\t\t\t\togg : 'audio/ogg',\n\n\t\t\t\t// OPUS — Opus audio in an Ogg container.\n\t\t\t\topus : 'audio/ogg; codecs=\"opus\"',\n\n\t\t\t\t// WAVE — Codecs vary, but commonly \"1\" (1 is the FourCC for PCM/LPCM).\n\t\t\t\twav  : 'audio/wav',\n\t\t\t\twave : 'audio/wav',\n\n\t\t\t\t// WEBM — Codecs vary, but commonly \"vorbis\" and, recently, \"opus\".\n\t\t\t\tweba : 'audio/webm',\n\t\t\t\twebm : 'audio/webm'\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t\tCache of supported MIME-types.\n\t\t*/\n\t\t_types : {\n\t\t\tvalue : {}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAudioList Class.\n\t*******************************************************************************************************************/\n\tclass AudioList {\n\t\tconstructor(obj) {\n\t\t\t// Process the given array of track objects or AudioList object.\n\t\t\tif (obj instanceof Array) {\n\t\t\t\tthis._create(obj);\n\t\t\t}\n\t\t\telse if (obj instanceof AudioList) {\n\t\t\t\tthis._copy(obj);\n\t\t\t\t// this._create(obj.tracks);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('tracks parameter must be either an array, of track objects, or an AudioTrack instance');\n\t\t\t}\n\t\t}\n\n\t\t_create(trackList) {\n\t\t\t// Map the array of tracks to playlist track objects.\n\t\t\tthis._finalize(trackList.map(trackObj => {\n\t\t\t\tif (typeof trackObj !== 'object') { // lazy equality for null\n\t\t\t\t\tthrow new Error('tracks parameter array members must be objects');\n\t\t\t\t}\n\n\t\t\t\tlet own;\n\t\t\t\tlet rate;\n\t\t\t\tlet track;\n\t\t\t\tlet volume;\n\n\t\t\t\tif (trackObj instanceof AudioTrack) {\n\t\t\t\t\town    = true;\n\t\t\t\t\trate   = trackObj.rate();\n\t\t\t\t\ttrack  = trackObj.clone();\n\t\t\t\t\tvolume = trackObj.volume();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (!trackObj.hasOwnProperty('track')) {\n\t\t\t\t\t\tthrow new Error('track object missing required \"track\" property');\n\t\t\t\t\t}\n\t\t\t\t\telse if (!(trackObj.track instanceof AudioTrack)) {\n\t\t\t\t\t\tthrow new Error('track object\\'s \"track\" property must be an AudioTrack object');\n\t\t\t\t\t}\n\t\t\t\t\t// else if (!trackObj.hasOwnProperty('volume')) {\n\t\t\t\t\t// \tthrow new Error('track object missing required \"volume\" property');\n\t\t\t\t\t// }\n\n\t\t\t\t\town    = trackObj.hasOwnProperty('own') && trackObj.own;\n\t\t\t\t\trate   = trackObj.hasOwnProperty('rate') ? trackObj.rate : trackObj.track.rate();\n\t\t\t\t\ttrack  = trackObj.track;\n\t\t\t\t\tvolume = trackObj.hasOwnProperty('volume') ? trackObj.volume : trackObj.track.volume();\n\t\t\t\t}\n\n\t\t\t\ttrack.stop();\n\t\t\t\ttrack.loop(false);\n\t\t\t\ttrack.mute(false);\n\t\t\t\ttrack.rate(rate);\n\t\t\t\ttrack.volume(volume);\n\t\t\t\ttrack.on('ended.AudioList', () => this._onEnd());\n\n\t\t\t\treturn { own, track, volume, rate };\n\t\t\t}));\n\t\t}\n\n\t\t_copy(obj) {\n\t\t\tthis._finalize(clone(obj.tracks));\n\t\t}\n\n\t\t_finalize(tracks) {\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\ttracks : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : Object.freeze(tracks)\n\t\t\t\t},\n\n\t\t\t\tqueue : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : []\n\t\t\t\t},\n\n\t\t\t\tcurrent : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_rate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_volume : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_mute : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_loop : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_shuffle : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t_destroy() {\n\t\t\t/*\n\t\t\t\tStrictly speaking, self-destruction is not necessary as this object will,\n\t\t\t\teventually, be garbage collected.\n\t\t\t*/\n\t\t\t// Stop playback.\n\t\t\tthis.stop();\n\n\t\t\t// Destroy all owned tracks.\n\t\t\tthis.tracks\n\t\t\t\t.filter(trackObj => trackObj.own)\n\t\t\t\t.forEach(trackObj => trackObj.track._destroy());\n\n\t\t\t// Delete the reference-type properties.\n\t\t\tdelete this.tracks;\n\t\t\tdelete this.queue;\n\t\t}\n\n\t\tload() {\n\t\t\tthis.tracks.forEach(trackObj => trackObj.track.load());\n\t\t}\n\n\t\tunload() {\n\t\t\tthis.stop();\n\t\t\tthis.tracks.forEach(trackObj => trackObj.track.unload());\n\t\t}\n\n\t\tplay() {\n\t\t\tif (this.current === null || this.current.track.isUnavailable() || this.current.track.isEnded()) {\n\t\t\t\tif (this.queue.length === 0) {\n\t\t\t\t\tthis._fillQueue();\n\t\t\t\t}\n\n\t\t\t\tif (!this._next()) {\n\t\t\t\t\treturn Promise.reject(new Error('no tracks were available'));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.current.track.play();\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tthis.play().catch(() => {\n\t\t\t\tconst gestures = _gestureEventNames.map(name => `${name}.AudioList_playWhenAllowed`).join(' ');\n\t\t\t\tjQuery(document).one(gestures, () => {\n\t\t\t\t\tjQuery(document).off('.AudioList_playWhenAllowed');\n\t\t\t\t\tthis.play();\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tpause() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.pause();\n\t\t\t}\n\t\t}\n\n\t\tstop() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.stop();\n\t\t\t\tthis.current = null;\n\t\t\t}\n\n\t\t\tthis._drainQueue();\n\t\t}\n\n\t\tskip() {\n\t\t\tif (this._next()) {\n\t\t\t\tthis.current.track.play();\n\t\t\t}\n\t\t\telse if (this._loop) {\n\t\t\t\tthis.play();\n\t\t\t}\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (typeof duration !== 'number') {\n\t\t\t\tthrow new TypeError('duration parameter must be a number');\n\t\t\t}\n\t\t\tif (typeof toVol !== 'number') {\n\t\t\t\tthrow new TypeError('toVolume parameter must be a number');\n\t\t\t}\n\t\t\tif (fromVol != null && typeof fromVol !== 'number') { // lazy equality for null\n\t\t\t\tthrow new TypeError('fromVolume parameter must be a number');\n\t\t\t}\n\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\tthis._fillQueue();\n\t\t\t}\n\n\t\t\tif (this.current === null || this.current.track.isUnavailable() || this.current.track.isEnded()) {\n\t\t\t\tif (!this._next()) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst adjToVol = Math.clamp(toVol, 0, 1) * this.current.volume;\n\t\t\tlet adjFromVol;\n\n\t\t\tif (fromVol != null) { // lazy equality for null\n\t\t\t\tadjFromVol = Math.clamp(fromVol, 0, 1) * this.current.volume;\n\t\t\t}\n\n\t\t\tthis._volume = toVol; // NOTE: Kludgey, but necessary.\n\n\t\t\treturn this.current.track.fade(duration, adjToVol, adjFromVol);\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\treturn this.fade(duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\treturn this.fade(duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.fadeStop();\n\t\t\t}\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\treturn this._loop;\n\t\t\t}\n\n\t\t\tthis._loop = !!loop;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\treturn this._mute;\n\t\t\t}\n\n\t\t\tthis._mute = !!mute;\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.mute(this._mute);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\treturn this._rate;\n\t\t\t}\n\n\t\t\tif (typeof rate !== 'number') {\n\t\t\t\tthrow new TypeError('rate parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._rate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.rate(this._rate * this.current.rate);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tshuffle(shuffle) {\n\t\t\tif (shuffle == null) { // lazy equality for null\n\t\t\t\treturn this._shuffle;\n\t\t\t}\n\n\t\t\tthis._shuffle = !!shuffle;\n\n\t\t\tif (this.queue.length > 0) {\n\t\t\t\tthis._fillQueue();\n\n\t\t\t\t// Try not to immediately replay the last track when not shuffling.\n\t\t\t\tif (!this._shuffle && this.current !== null && this.queue.length > 1) {\n\t\t\t\t\tconst firstIdx = this.queue.findIndex(trackObj => trackObj === this.current);\n\n\t\t\t\t\tif (firstIdx !== -1) {\n\t\t\t\t\t\tthis.queue.push(...this.queue.splice(0, firstIdx + 1));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\treturn this._volume;\n\t\t\t}\n\n\t\t\tif (typeof volume !== 'number') {\n\t\t\t\tthrow new TypeError('volume parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._volume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.volume(this._volume * this.current.volume);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tduration() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('duration takes no parameters');\n\t\t\t}\n\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.tracks\n\t\t\t\t.map(trackObj => trackObj.track.duration())\n\t\t\t\t.reduce((prev, cur) => prev + cur, 0);\n\t\t}\n\n\t\tremaining() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('remaining takes no parameters');\n\t\t\t}\n\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\tlet remainingTime = this.queue\n\t\t\t\t.map(trackObj => trackObj.track.duration())\n\t\t\t\t.reduce((prev, cur) => prev + cur, 0);\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tremainingTime += this.current.track.remaining();\n\t\t\t}\n\n\t\t\treturn remainingTime;\n\t\t}\n\n\t\ttime() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('time takes no parameters');\n\t\t\t}\n\n\t\t\treturn this.duration() - this.remaining();\n\t\t}\n\n\t\tisPlaying() {\n\t\t\treturn this.current !== null && this.current.track.isPlaying();\n\t\t}\n\n\t\tisPaused() {\n\t\t\treturn this.current === null || this.current.track.isPaused();\n\t\t}\n\n\t\tisStopped() {\n\t\t\treturn this.queue.length === 0 && this.current === null;\n\t\t}\n\n\t\tisEnded() {\n\t\t\treturn this.queue.length === 0 && (this.current === null || this.current.track.isEnded());\n\t\t}\n\n\t\tisFading() {\n\t\t\treturn this.current !== null && this.current.track.isFading();\n\t\t}\n\n\t\t_next() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.stop();\n\t\t\t\tthis.current = null;\n\t\t\t}\n\n\t\t\tlet nextTrack;\n\n\t\t\twhile ((nextTrack = this.queue.shift())) {\n\t\t\t\tif (!nextTrack.track.isUnavailable()) {\n\t\t\t\t\tthis.current = nextTrack;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.current === null) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis.current.track.mute(this._mute);\n\t\t\tthis.current.track.rate(this._rate * this.current.rate);\n\t\t\tthis.current.track.volume(this._volume * this.current.volume);\n\n\t\t\t// Attempt to protect against the `loop` state being reenabled\n\t\t\t// outside of the playlist.  Mostly for unowned tracks.\n\t\t\t//\n\t\t\t// TODO: Should we reapply the `ended` event handler too?\n\t\t\tthis.current.track.loop(false);\n\n\t\t\treturn true;\n\t\t}\n\n\t\t_onEnd() {\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\tif (!this._loop) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._fillQueue();\n\t\t\t}\n\n\t\t\tif (!this._next()) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.current.track.play();\n\t\t}\n\n\t\t_drainQueue() {\n\t\t\tthis.queue.splice(0);\n\t\t}\n\n\t\t_fillQueue() {\n\t\t\tthis._drainQueue();\n\t\t\tthis.queue.push(...this.tracks.filter(trackObj => !trackObj.track.isUnavailable()));\n\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (this._shuffle) {\n\t\t\t\tthis.queue.shuffle();\n\n\t\t\t\t// Try not to immediately replay the last track when shuffling.\n\t\t\t\tif (this.queue.length > 1 && this.queue[0] === this.current) {\n\t\t\t\t\tthis.queue.push(this.queue.shift());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAudioRunner Class.\n\t*******************************************************************************************************************/\n\tclass AudioRunner {\n\t\tconstructor(list) {\n\t\t\tif (!(list instanceof Set || list instanceof AudioRunner)) {\n\t\t\t\tthrow new TypeError('list parameter must be a Set or a AudioRunner instance');\n\t\t\t}\n\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\ttrackIds : {\n\t\t\t\t\tvalue : new Set(list instanceof AudioRunner ? list.trackIds : list)\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tload() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.load);\n\t\t}\n\n\t\tunload() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.unload);\n\t\t}\n\n\t\tplay() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.play);\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.playWhenAllowed);\n\t\t}\n\n\t\tpause() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.pause);\n\t\t}\n\n\t\tstop() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.stop);\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (duration == null || toVol == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fade requires parameters');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fade, duration, toVol, fromVol);\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\tif (duration == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fadeIn requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeIn, duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\tif (duration == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fadeOut requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeOut, duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeStop);\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\tthrow new Error('loop requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.loop, loop);\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\tthrow new Error('mute requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.mute, mute);\n\t\t\treturn this;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\tthrow new Error('rate requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.rate, rate);\n\t\t\treturn this;\n\t\t}\n\n\t\ttime(time) {\n\t\t\tif (time == null) { // lazy equality for null\n\t\t\t\tthrow new Error('time requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.time, time);\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\tthrow new Error('volume requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.volume, volume);\n\t\t\treturn this;\n\t\t}\n\n\t\ton(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.on, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\tone(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.one, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\toff(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.off, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\tstatic _run(ids, fn, ...args) {\n\t\t\tids.forEach(id => {\n\t\t\t\tconst track = _tracks.get(id);\n\n\t\t\t\tif (track) {\n\t\t\t\t\tfn.apply(track, args);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTrack Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.tracks.add(trackId, sources…);\n\n\t\tE.g.\n\t\t\tSimpleAudio.tracks.add(\n\t\t\t\t'over_the_top',\n\t\t\t\t'https://audiohost.tld/id/over_the_top.mp3',\n\t\t\t\t'https://audiohost.tld/id/over_the_top.ogg'\n\t\t\t);\n\t*/\n\tfunction trackAdd(/* trackId , sources… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('track ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('sources'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `track ID \"${id}\"`;\n\n\t\tif (_badIdRe.test(id)) {\n\t\t\tthrow new Error(`invalid ${what}: track IDs must not contain colons or whitespace`);\n\t\t}\n\n\t\tconst sources = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet track;\n\n\t\ttry {\n\t\t\ttrack = _newTrack(sources);\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during track initialization: ${ex.message}`);\n\t\t}\n\n\t\t// If in Test Mode and no supported sources were specified, throw an error.\n\t\tif (Config.debug && !track.hasSource()) {\n\t\t\tthrow new Error(`${what}: no supported audio sources found`);\n\t\t}\n\n\t\t// If a track by the given ID already exists, destroy it.\n\t\tif (_tracks.has(id)) {\n\t\t\t_tracks.get(id)._destroy();\n\t\t}\n\n\t\t// Add the track to the cache.\n\t\t_tracks.set(id, track);\n\t}\n\n\tfunction trackDelete(id) {\n\t\tif (_tracks.has(id)) {\n\t\t\t_tracks.get(id)._destroy();\n\t\t}\n\n\t\t// TODO: Should this also remove references to the track from groups and playlists?\n\n\t\treturn _tracks.delete(id);\n\t}\n\n\tfunction trackClear() {\n\t\t_tracks.forEach(track => track._destroy());\n\t\t_tracks.clear();\n\t}\n\n\tfunction trackHas(id) {\n\t\treturn _tracks.has(id);\n\t}\n\n\tfunction trackGet(id) {\n\t\treturn _tracks.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tGroup Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.groups.add(groupId, trackIds…);\n\n\t\tE.g.\n\t\t\tSimpleAudio.groups.add(':ui', 'beep', 'boop', 'boing');\n\t*/\n\tfunction groupAdd(/* groupId , trackIds… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('group ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('track IDs'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `group ID \"${id}\"`;\n\n\t\tif (id[0] !== ':' || _badIdRe.test(id.slice(1))) {\n\t\t\tthrow new Error(`invalid ${what}: group IDs must start with a colon and must not contain colons or whitespace`);\n\t\t}\n\n\t\tif (_specialIds.includes(id)) {\n\t\t\tthrow new Error(`cannot clobber special ${what}`);\n\t\t}\n\n\t\tconst trackIds = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet group;\n\n\t\ttry {\n\t\t\tgroup = new Set(trackIds.map(trackId => {\n\t\t\t\tif (!_tracks.has(trackId)) {\n\t\t\t\t\tthrow new Error(`track \"${trackId}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\treturn trackId;\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during group initialization: ${ex.message}`);\n\t\t}\n\n\t\t// Add the group to the cache.\n\t\t_groups.set(id, Object.freeze(Array.from(group)));\n\t}\n\n\tfunction groupDelete(id) {\n\t\treturn _groups.delete(id);\n\t}\n\n\tfunction groupClear() {\n\t\t_groups.clear();\n\t}\n\n\tfunction groupHas(id) {\n\t\treturn _groups.has(id);\n\t}\n\n\tfunction groupGet(id) {\n\t\treturn _groups.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPlaylist Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.lists.add(listId, sources…);\n\t\t\tWhere `sources` may be either a track ID or descriptor (object).\n\t\t\tTrack descriptors are either { id, [own], [rate], [volume] } or { sources, [rate], [volume] }.\n\n\t\tNOTE: Rate properties are currently unsupported due to poor browser support.\n\n\t\tE.g.\n\t\t\tSimpleAudio.lists.add(\n\t\t\t\t'bgm',\n\t\t\t\t'over_the_top',\n\t\t\t\t{\n\t\t\t\t\tid     : 'heavens_a_lie',\n\t\t\t\t\tvolume : 0.5,\n\t\t\t\t\town    : true\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tsources : [\n\t\t\t\t\t\t'https://audiohost.tld/id/swamped.mp3',\n\t\t\t\t\t\t'https://audiohost.tld/id/swamped.ogg'\n\t\t\t\t\t],\n\t\t\t\t\tvolume  : 0.75\n\t\t\t\t}\n\t\t\t);\n\t*/\n\tfunction listAdd(/* listId , sources… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('list ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('track IDs'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `list ID \"${id}\"`;\n\n\t\tif (_badIdRe.test(id)) {\n\t\t\treturn this.error(`invalid ${what}: list IDs must not contain colons or whitespace`);\n\t\t}\n\n\t\tconst descriptors = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet list;\n\n\t\ttry {\n\t\t\tlist = new AudioList(descriptors.map(desc => {\n\t\t\t\tif (desc === null) {\n\t\t\t\t\tthrow new Error('track descriptor must be a string or object (type: null)');\n\t\t\t\t}\n\n\t\t\t\tswitch (typeof desc) {\n\t\t\t\tcase 'string':\n\t\t\t\t\t// Simply a track ID, so convert it into an object.\n\t\t\t\t\tdesc = { id : desc }; // eslint-disable-line no-param-reassign\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\tif (!desc.hasOwnProperty('id') && !desc.hasOwnProperty('sources')) {\n\t\t\t\t\t\tthrow new Error('track descriptor must contain one of either an \"id\" or a \"sources\" property');\n\t\t\t\t\t}\n\t\t\t\t\telse if (desc.hasOwnProperty('id') && desc.hasOwnProperty('sources')) {\n\t\t\t\t\t\tthrow new Error('track descriptor must contain either an \"id\" or a \"sources\" property, not both');\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`track descriptor must be a string or object (type: ${typeof desc})`);\n\t\t\t\t}\n\n\t\t\t\tlet own;\n\t\t\t\t// let rate;\n\t\t\t\tlet track;\n\t\t\t\tlet volume;\n\n\t\t\t\tif (desc.hasOwnProperty('id')) {\n\t\t\t\t\tif (typeof desc.id !== 'string') {\n\t\t\t\t\t\tthrow new Error('\"id\" property must be a string');\n\t\t\t\t\t}\n\t\t\t\t\tif (!_tracks.has(desc.id)) {\n\t\t\t\t\t\tthrow new Error(`track \"${desc.id}\" does not exist`);\n\t\t\t\t\t}\n\n\t\t\t\t\ttrack = _tracks.get(desc.id);\n\t\t\t\t}\n\t\t\t\telse if (desc.hasOwnProperty('sources')) {\n\t\t\t\t\tif (!Array.isArray(desc.sources) || desc.sources.length === 0) {\n\t\t\t\t\t\tthrow new Error('\"sources\" property must be a non-empty array');\n\t\t\t\t\t}\n\t\t\t\t\tif (desc.hasOwnProperty('own')) {\n\t\t\t\t\t\tthrow new Error('\"own\" property is not allowed with the \"sources\" property');\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\ttrack = _newTrack(desc.sources);\n\t\t\t\t\t\town = true;\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`error during track initialization: ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// If in Test Mode and no supported sources were specified, return an error.\n\t\t\t\t\tif (Config.debug && !track.hasSource()) {\n\t\t\t\t\t\tthrow new Error('no supported audio sources found');\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (desc.hasOwnProperty('own')) {\n\t\t\t\t\tif (typeof desc.own !== 'boolean') {\n\t\t\t\t\t\tthrow new Error('\"own\" property must be a boolean');\n\t\t\t\t\t}\n\n\t\t\t\t\town = desc.own;\n\n\t\t\t\t\tif (own) {\n\t\t\t\t\t\ttrack = track.clone();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if (desc.hasOwnProperty('rate')) {\n\t\t\t\t// \tif (\n\t\t\t\t// \t\t   typeof desc.rate !== 'number'\n\t\t\t\t// \t\t|| Number.isNaN(desc.rate)\n\t\t\t\t// \t\t|| !Number.isFinite(desc.rate)\n\t\t\t\t// \t) {\n\t\t\t\t// \t\tthrow new Error('\"rate\" property must be a finite number');\n\t\t\t\t// \t}\n\t\t\t\t//\n\t\t\t\t// \trate = desc.rate;\n\t\t\t\t// }\n\n\t\t\t\tif (desc.hasOwnProperty('volume')) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t   typeof desc.volume !== 'number'\n\t\t\t\t\t\t|| Number.isNaN(desc.volume)\n\t\t\t\t\t\t|| !Number.isFinite(desc.volume)\n\t\t\t\t\t\t|| desc.volume < 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new Error('\"volume\" property must be a non-negative finite number');\n\t\t\t\t\t}\n\n\t\t\t\t\tvolume = desc.volume;\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\town    : own != null ? own : false, // lazy equality for null,\n\t\t\t\t\t// rate   : rate != null ? rate : track.rate(), // lazy equality for null,\n\t\t\t\t\ttrack,\n\t\t\t\t\tvolume : volume != null ? volume : track.volume() // lazy equality for null\n\t\t\t\t};\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during playlist initialization: ${ex.message}`);\n\t\t}\n\n\t\t// If a playlist by the given ID already exists, destroy it.\n\t\tif (_lists.has(id)) {\n\t\t\t_lists.get(id)._destroy();\n\t\t}\n\n\t\t// Add the playlist to the cache.\n\t\t_lists.set(id, list);\n\t}\n\n\tfunction listDelete(id) {\n\t\tif (_lists.has(id)) {\n\t\t\t_lists.get(id)._destroy();\n\t\t}\n\n\t\treturn _lists.delete(id);\n\t}\n\n\tfunction listClear() {\n\t\t_lists.forEach(list => list._destroy());\n\t\t_lists.clear();\n\t}\n\n\tfunction listHas(id) {\n\t\treturn _lists.has(id);\n\t}\n\n\tfunction listGet(id) {\n\t\treturn _lists.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tRunner Functions.\n\t*******************************************************************************************************************/\n\tconst _runnerParseSelector = (() => {\n\t\tconst notWsRe = /\\S/g;\n\t\tconst parenRe = /[()]/g;\n\n\t\tfunction processNegation(str, startPos) {\n\t\t\tlet match;\n\n\t\t\tnotWsRe.lastIndex = startPos;\n\t\t\tmatch = notWsRe.exec(str);\n\n\t\t\tif (match === null || match[0] !== '(') {\n\t\t\t\tthrow new Error('invalid \":not()\" syntax: missing parentheticals');\n\t\t\t}\n\n\t\t\tparenRe.lastIndex = notWsRe.lastIndex;\n\t\t\tconst start  = notWsRe.lastIndex;\n\t\t\tconst result = { str : '', nextMatch : -1 };\n\t\t\tlet depth = 1;\n\n\t\t\twhile ((match = parenRe.exec(str)) !== null) {\n\t\t\t\tif (match[0] === '(') {\n\t\t\t\t\t++depth;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t--depth;\n\t\t\t\t}\n\n\t\t\t\tif (depth < 1) {\n\t\t\t\t\tresult.nextMatch = parenRe.lastIndex;\n\t\t\t\t\tresult.str = str.slice(start, result.nextMatch - 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tfunction parseSelector(idArg) {\n\t\t\tconst ids  = [];\n\t\t\tconst idRe = /:?[^\\s:()]+/g;\n\t\t\tlet match;\n\n\t\t\twhile ((match = idRe.exec(idArg)) !== null) {\n\t\t\t\tconst id = match[0];\n\n\t\t\t\t// Group negation.\n\t\t\t\tif (id === ':not') {\n\t\t\t\t\tif (ids.length === 0) {\n\t\t\t\t\t\tthrow new Error('invalid negation: no group ID preceded \":not()\"');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst parent = ids[ids.length - 1];\n\n\t\t\t\t\tif (parent.id[0] !== ':') {\n\t\t\t\t\t\tthrow new Error(`invalid negation of track \"${parent.id}\": only groups may be negated with \":not()\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst negation = processNegation(idArg, idRe.lastIndex);\n\n\t\t\t\t\tif (negation.nextMatch === -1) {\n\t\t\t\t\t\tthrow new Error('unknown error parsing \":not()\"');\n\t\t\t\t\t}\n\n\t\t\t\t\tidRe.lastIndex = negation.nextMatch;\n\t\t\t\t\tparent.not = parseSelector(negation.str);\n\t\t\t\t}\n\n\t\t\t\t// Group or track ID.\n\t\t\t\telse {\n\t\t\t\t\tids.push({ id });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn ids;\n\t\t}\n\n\t\treturn parseSelector;\n\t})();\n\n\t/*\n\t\tSimpleAudio.select(selector).…;\n\n\t\tE.g.\n\t\t\tSimpleAudio.select(':ui').…\n\t\t\tSimpleAudio.select(':ui:not(boop)').…\n\t\t\tSimpleAudio.select('boop beep').…\n\t\t\tSimpleAudio.select(':ui :sfx').…\n\t\t\tSimpleAudio.select(':ui:not(boop) :sfx overthetop').…\n\t*/\n\tfunction runnerGet(/* selector */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('no track selector specified');\n\t\t}\n\n\t\tconst selector = String(arguments[0]).trim();\n\t\tconst trackIds = new Set();\n\n\t\ttry {\n\t\t\tconst allIds = Array.from(_tracks.keys());\n\n\t\t\tfunction renderIds(idObj) {\n\t\t\t\tconst id = idObj.id;\n\t\t\t\tlet ids;\n\n\t\t\t\tswitch (id) {\n\t\t\t\tcase ':all':     ids = allIds; break;\n\t\t\t\tcase ':looped':  ids = allIds.filter(id => _tracks.get(id).loop()); break;\n\t\t\t\tcase ':muted':   ids = allIds.filter(id => _tracks.get(id).mute()); break;\n\t\t\t\tcase ':paused':  ids = allIds.filter(id => _tracks.get(id).isPaused()); break;\n\t\t\t\tcase ':playing': ids = allIds.filter(id => _tracks.get(id).isPlaying()); break;\n\t\t\t\tdefault:         ids = id[0] === ':' ? _groups.get(id) : [id]; break;\n\t\t\t\t}\n\n\t\t\t\tif (idObj.hasOwnProperty('not')) {\n\t\t\t\t\tconst negated = idObj.not.map(idObj => renderIds(idObj)).flat(Infinity);\n\t\t\t\t\tids = ids.filter(id => !negated.includes(id));\n\t\t\t\t}\n\n\t\t\t\treturn ids;\n\t\t\t}\n\n\t\t\t_runnerParseSelector(selector).forEach(idObj => renderIds(idObj).forEach(id => {\n\t\t\t\tif (!_tracks.has(id)) {\n\t\t\t\t\tthrow new Error(`track \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\ttrackIds.add(id);\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`error during runner initialization: ${ex.message}`);\n\t\t}\n\n\t\treturn new AudioRunner(trackIds);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMaster Audio Functions.\n\t*******************************************************************************************************************/\n\tfunction masterLoad() {\n\t\tpublish('load');\n\t}\n\n\tfunction masterLoadWithScreen() {\n\t\tpublish('loadwithscreen');\n\t}\n\n\tfunction masterMute(mute) {\n\t\tif (mute == null) { // lazy equality for null\n\t\t\treturn _masterMute;\n\t\t}\n\n\t\t_masterMute = !!mute;\n\t\tpublish('mute', _masterMute);\n\t}\n\n\tfunction masterMuteOnHidden(mute) {\n\t\t// NOTE: Some older browsers—notably: IE 9—do not support the Page Visibility API.\n\t\tif (!Visibility.isEnabled()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (mute == null) { // lazy equality for null\n\t\t\treturn _masterMuteOnHidden;\n\t\t}\n\n\t\t_masterMuteOnHidden = !!mute;\n\n\t\tconst namespace = '.SimpleAudio_masterMuteOnHidden';\n\n\t\tif (_masterMuteOnHidden) {\n\t\t\tconst visibilityChange = `${Visibility.changeEvent}${namespace}`;\n\t\t\tjQuery(document)\n\t\t\t\t.off(namespace)\n\t\t\t\t.on(visibilityChange, () => masterMute(Visibility.isHidden()));\n\n\t\t\t// Only change the mute state initially if hidden.\n\t\t\tif (Visibility.isHidden()) {\n\t\t\t\tmasterMute(true);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tjQuery(document).off(namespace);\n\t\t}\n\t}\n\n\tfunction masterRate(rate) {\n\t\tif (rate == null) { // lazy equality for null\n\t\t\treturn _masterRate;\n\t\t}\n\n\t\tif (typeof rate !== 'number' || Number.isNaN(rate) || !Number.isFinite(rate)) {\n\t\t\tthrow new Error('rate must be a finite number');\n\t\t}\n\n\t\t_masterRate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\t\tpublish('rate', _masterRate);\n\t}\n\n\tfunction masterStop() {\n\t\tpublish('stop');\n\t}\n\n\tfunction masterUnload() {\n\t\tpublish('unload');\n\t}\n\n\tfunction masterVolume(volume) {\n\t\tif (volume == null) { // lazy equality for null\n\t\t\treturn _masterVolume;\n\t\t}\n\n\t\tif (typeof volume !== 'number' || Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\tthrow new Error('volume must be a finite number');\n\t\t}\n\n\t\t_masterVolume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\t\tpublish('volume', _masterVolume);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSubscription Functions.\n\t*******************************************************************************************************************/\n\tfunction subscribe(id, callback) {\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new Error('callback parameter must be a function');\n\t\t}\n\n\t\t_subscribers.set(id, callback);\n\t}\n\n\tfunction unsubscribe(id) {\n\t\t_subscribers.delete(id);\n\t}\n\n\tfunction publish(mesg, data) {\n\t\t_subscribers.forEach(fn => fn(mesg, data));\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _newTrack(sources) {\n\t\treturn new AudioTrack(sources.map(source => {\n\t\t\t// Handle audio passages.\n\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\tif (passage.tags.includes('Twine.audio')) {\n\t\t\t\t\treturn passage.text.trim();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle URIs—possibly prefixed with a format specifier.\n\t\t\tconst match = _formatSpecRe.exec(source);\n\t\t\treturn match === null ? source : {\n\t\t\t\tformat : match[1],\n\t\t\t\tsrc    : match[2]\n\t\t\t};\n\t\t}));\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Track Functions.\n\t\ttracks : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : trackAdd },\n\t\t\t\tdelete : { value : trackDelete },\n\t\t\t\tclear  : { value : trackClear },\n\t\t\t\thas    : { value : trackHas },\n\t\t\t\tget    : { value : trackGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Group Functions.\n\t\tgroups : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : groupAdd },\n\t\t\t\tdelete : { value : groupDelete },\n\t\t\t\tclear  : { value : groupClear },\n\t\t\t\thas    : { value : groupHas },\n\t\t\t\tget    : { value : groupGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Playlist Functions.\n\t\tlists : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : listAdd },\n\t\t\t\tdelete : { value : listDelete },\n\t\t\t\tclear  : { value : listClear },\n\t\t\t\thas    : { value : listHas },\n\t\t\t\tget    : { value : listGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Runner Functions.\n\t\tselect : { value : runnerGet },\n\n\t\t// Master Audio Functions.\n\t\tload           : { value : masterLoad },\n\t\tloadWithScreen : { value : masterLoadWithScreen },\n\t\tmute           : { value : masterMute },\n\t\tmuteOnHidden   : { value : masterMuteOnHidden },\n\t\trate           : { value : masterRate },\n\t\tstop           : { value : masterStop },\n\t\tunload         : { value : masterUnload },\n\t\tvolume         : { value : masterVolume }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tstate.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Diff, Engine, PRNGWrapper, Patterns, clone, session, storage */\n\nvar State = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// History moment stack.\n\tlet _history = [];\n\n\t// Currently active/played moment.\n\tlet _active = momentCreate();\n\n\t// Currently active/played moment index.\n\tlet _activeIndex = -1;\n\n\t// Titles of all moments which have expired (i.e. fallen off the bottom of the stack).\n\tlet _expired = [];\n\n\t// (optional) Seedable PRNG object.\n\tlet _prng = null;\n\n\t// Temporary variables object.\n\tlet _tempVariables = {};\n\n\n\t/*******************************************************************************************************************\n\t\tState Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tResets the story state.\n\t*/\n\tfunction stateReset() {\n\t\tif (DEBUG) { console.log('[State/stateReset()]'); }\n\n\t\t/*\n\t\t\tDelete the active session.\n\t\t*/\n\t\tsession.delete('state');\n\n\t\t/*\n\t\t\tReset the properties.\n\t\t*/\n\t\t_history     = [];\n\t\t_active      = momentCreate();\n\t\t_activeIndex = -1;\n\t\t_expired     = [];\n\t\t_prng        = _prng === null ? null : new PRNGWrapper(_prng.seed, false);\n\t}\n\n\t/*\n\t\tRestores the story state from the active session.\n\t*/\n\tfunction stateRestore() {\n\t\tif (DEBUG) { console.log('[State/stateRestore()]'); }\n\n\t\t/*\n\t\t\tAttempt to restore an active session.\n\t\t*/\n\t\tif (session.has('state')) {\n\t\t\t/*\n\t\t\t\tRetrieve the session.\n\t\t\t*/\n\t\t\tconst stateObj = session.get('state');\n\n\t\t\tif (DEBUG) { console.log('\\tsession state:', stateObj); }\n\n\t\t\tif (stateObj == null) { // lazy equality for null\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tRestore the session.\n\t\t\t*/\n\t\t\tstateUnmarshal(stateObj);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tReturns the current story state marshaled into a serializable object.\n\t*/\n\tfunction stateMarshal(noDelta) {\n\t\t/*\n\t\t\tGather the properties.\n\t\t*/\n\t\tconst stateObj = {\n\t\t\tindex : _activeIndex\n\t\t};\n\n\t\tif (noDelta) {\n\t\t\tstateObj.history = clone(_history);\n\t\t}\n\t\telse {\n\t\t\tstateObj.delta = historyDeltaEncode(_history);\n\t\t}\n\n\t\tif (_expired.length > 0) {\n\t\t\tstateObj.expired = [];\n\t\t}\n\n\t\tif (_prng !== null) {\n\t\t\tstateObj.seed = _prng.seed;\n\t\t}\n\n\t\treturn stateObj;\n\t}\n\n\t/*\n\t\tRestores the story state from a marshaled story state serialization object.\n\t*/\n\tfunction stateUnmarshal(stateObj, noDelta) {\n\t\tif (stateObj == null) { // lazy equality for null\n\t\t\tthrow new Error('state object is null or undefined');\n\t\t}\n\n\t\tif (\n\t\t\t   !stateObj.hasOwnProperty(noDelta ? 'history' : 'delta')\n\t\t\t|| stateObj[noDelta ? 'history' : 'delta'].length === 0\n\t\t) {\n\t\t\tthrow new Error('state object has no history or history is empty');\n\t\t}\n\n\t\tif (!stateObj.hasOwnProperty('index')) {\n\t\t\tthrow new Error('state object has no index');\n\t\t}\n\n\t\tif (_prng !== null && !stateObj.hasOwnProperty('seed')) {\n\t\t\tthrow new Error('state object has no seed, but PRNG is enabled');\n\t\t}\n\n\t\tif (_prng === null && stateObj.hasOwnProperty('seed')) {\n\t\t\tthrow new Error('state object has seed, but PRNG is disabled');\n\t\t}\n\n\t\t/*\n\t\t\tRestore the properties.\n\t\t*/\n\t\t_history     = noDelta ? clone(stateObj.history) : historyDeltaDecode(stateObj.delta);\n\t\t_activeIndex = stateObj.index;\n\t\t_expired     = stateObj.hasOwnProperty('expired') ? [...stateObj.expired] : [];\n\n\t\tif (stateObj.hasOwnProperty('seed')) {\n\t\t\t/*\n\t\t\t\tWe only need to restore the PRNG's seed here as `momentActivate()` will handle\n\t\t\t\tfully restoring the PRNG to its proper state.\n\t\t\t*/\n\t\t\t_prng.seed = stateObj.seed;\n\t\t}\n\n\t\t/*\n\t\t\tActivate the current moment (do this only after all properties have been restored).\n\t\t*/\n\t\tmomentActivate(_activeIndex);\n\t}\n\n\t/*\n\t\tReturns the current story state marshaled into a save-compatible serializable object.\n\t*/\n\tfunction stateMarshalForSave() {\n\t\treturn stateMarshal(true);\n\t}\n\n\t/*\n\t\tRestores the story state from a marshaled save-compatible story state serialization object.\n\t*/\n\tfunction stateUnmarshalForSave(stateObj) {\n\t\treturn stateUnmarshal(stateObj, true);\n\t}\n\n\t/*\n\t\tReturns the titles of expired moments.\n\t*/\n\tfunction stateExpired() {\n\t\treturn _expired;\n\t}\n\n\t/*\n\t\tReturns the total number of played moments (expired + in-play history moments).\n\t*/\n\tfunction stateTurns() {\n\t\treturn _expired.length + historyLength();\n\t}\n\n\t/*\n\t\tReturns the passage titles of all played moments (expired + in-play history moments).\n\t*/\n\tfunction stateTitles() {\n\t\treturn _expired.concat(_history.slice(0, historyLength()).map(moment => moment.title));\n\t}\n\n\t/*\n\t\tReturns whether a passage with the given title has been played (expired + in-play history moments).\n\t*/\n\tfunction stateHasPlayed(title) {\n\t\tif (title == null || title === '') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tif (_expired.includes(title)) {\n\t\t\treturn true;\n\t\t}\n\t\telse if (_history.slice(0, historyLength()).some(moment => moment.title === title)) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMoment Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a new moment object created from the given passage title and variables object.\n\t*/\n\tfunction momentCreate(title, variables) {\n\t\treturn {\n\t\t\ttitle     : title == null ? '' : String(title), // lazy equality for null\n\t\t\tvariables : variables == null ? {} : variables   // lazy equality for null\n\t\t};\n\t}\n\n\t/*\n\t\tReturns the active (present) moment.\n\t*/\n\tfunction momentActive() {\n\t\treturn _active;\n\t}\n\n\t/*\n\t\tReturns the index within the history of the active (present) moment.\n\t*/\n\tfunction momentActiveIndex() {\n\t\treturn _activeIndex;\n\t}\n\n\t/*\n\t\tReturns the title from the active (present) moment.\n\t*/\n\tfunction momentActiveTitle() {\n\t\treturn _active.title;\n\t}\n\n\t/*\n\t\tReturns the variables from the active (present) moment.\n\t*/\n\tfunction momentActiveVariables() {\n\t\treturn _active.variables;\n\t}\n\n\t/*\n\t\tReturns the active (present) moment after setting it to either the given moment object\n\t\tor the moment object at the given history index.  Additionally, updates the active session\n\t\tand triggers a history update event.\n\t*/\n\tfunction momentActivate(moment) {\n\t\tif (moment == null) { // lazy equality for null\n\t\t\tthrow new Error('moment activation attempted with null or undefined');\n\t\t}\n\n\t\t/*\n\t\t\tSet the active moment.\n\t\t*/\n\t\tswitch (typeof moment) {\n\t\tcase 'object':\n\t\t\t_active = clone(moment);\n\t\t\tbreak;\n\n\t\tcase 'number':\n\t\t\tif (historyIsEmpty()) {\n\t\t\t\tthrow new Error('moment activation attempted with index on empty history');\n\t\t\t}\n\n\t\t\tif (moment < 0 || moment >= historySize()) {\n\t\t\t\tthrow new RangeError(`moment activation attempted with out-of-bounds index; need [0, ${historySize() - 1}], got ${moment}`);\n\t\t\t}\n\n\t\t\t_active = clone(_history[moment]);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new TypeError(`moment activation attempted with a \"${typeof moment}\"; must be an object or valid history stack index`);\n\t\t}\n\n\t\t/*\n\t\t\tRestore the seedable PRNG.\n\n\t\t\tNOTE: We cannot simply set `_prng.pull` to `_active.pull` as that would\n\t\t\tnot properly mutate the PRNG's internal state.\n\t\t*/\n\t\tif (_prng !== null) {\n\t\t\t_prng = PRNGWrapper.unmarshal({\n\t\t\t\tseed : _prng.seed,\n\t\t\t\tpull : _active.pull\n\t\t\t});\n\t\t}\n\n\t\t/*\n\t\t\tUpdate the active session.\n\t\t*/\n\t\tsession.set('state', stateMarshal());\n\n\t\t/*\n\t\t\tTrigger a global `:historyupdate` event.\n\n\t\t\tNOTE: We do this here because setting a new active moment is a core component\n\t\t\tof, virtually, all history updates.\n\t\t*/\n\t\tjQuery.event.trigger(':historyupdate');\n\n\t\treturn _active;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tHistory Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the moment history.\n\t*/\n\tfunction historyGet() {\n\t\treturn _history;\n\t}\n\n\t/*\n\t\tReturns the number of active history moments (past only).\n\t*/\n\tfunction historyLength() {\n\t\treturn _activeIndex + 1;\n\t}\n\n\t/*\n\t\tReturns the total number of history moments (past + future).\n\t*/\n\tfunction historySize() {\n\t\treturn _history.length;\n\t}\n\n\t/*\n\t\tReturns whether the history is empty.\n\t*/\n\tfunction historyIsEmpty() {\n\t\treturn _history.length === 0;\n\t}\n\n\t/*\n\t\tReturns the current (pre-play version of the active) moment within the history.\n\t*/\n\tfunction historyCurrent() {\n\t\treturn _history.length > 0 ? _history[_activeIndex] : null;\n\t}\n\n\t/*\n\t\tReturns the topmost (most recent) moment within the history.\n\t*/\n\tfunction historyTop() {\n\t\treturn _history.length > 0 ? _history[_history.length - 1] : null;\n\t}\n\n\t/*\n\t\tReturns the bottommost (least recent) moment within the history.\n\t*/\n\tfunction historyBottom() {\n\t\treturn _history.length > 0 ? _history[0] : null;\n\t}\n\n\t/*\n\t\tReturns the moment at the given index within the history.\n\t*/\n\tfunction historyIndex(index) {\n\t\tif (historyIsEmpty() || index < 0 || index > _activeIndex) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn _history[index];\n\t}\n\n\t/*\n\t\tReturns the moment at the given offset from the active moment within the history.\n\t*/\n\tfunction historyPeek(offset) {\n\t\tif (historyIsEmpty()) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst lengthOffset = 1 + (offset ? Math.abs(offset) : 0);\n\n\t\tif (lengthOffset > historyLength()) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn _history[historyLength() - lengthOffset];\n\t}\n\n\t/*\n\t\tReturns whether a moment with the given title exists within the history.\n\t*/\n\tfunction historyHas(title) {\n\t\tif (historyIsEmpty() || title == null || title === '') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (let i = _activeIndex; i >= 0; --i) {\n\t\t\tif (_history[i].title === title) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tCreates a new moment and pushes it onto the history, discarding future moments if necessary.\n\t*/\n\tfunction historyCreate(title) {\n\t\tif (DEBUG) { console.log(`[State/historyCreate(title: \"${title}\")]`); }\n\n\t\t/*\n\t\t\tTODO: It might be good to have some assertions about the passage title here.\n\t\t*/\n\n\t\t/*\n\t\t\tIf we're not at the top of the stack, discard the future moments.\n\t\t*/\n\t\tif (historyLength() < historySize()) {\n\t\t\tif (DEBUG) { console.log(`\\tnon-top push; discarding ${historySize() - historyLength()} future moments`); }\n\n\t\t\t_history.splice(historyLength(), historySize() - historyLength());\n\t\t}\n\n\t\t/*\n\t\t\tPush the new moment onto the history stack.\n\t\t*/\n\t\t_history.push(momentCreate(title, _active.variables));\n\n\t\tif (_prng) {\n\t\t\thistoryTop().pull = _prng.pull;\n\t\t}\n\n\t\t/*\n\t\t\tTruncate the history, if necessary, by discarding moments from the bottom.\n\t\t*/\n\t\tif (Config.history.maxStates > 0) {\n\t\t\twhile (historySize() > Config.history.maxStates) {\n\t\t\t\t_expired.push(_history.shift().title);\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t\tActivate the new top moment.\n\t\t*/\n\t\t_activeIndex = historySize() - 1;\n\t\tmomentActivate(_activeIndex);\n\n\t\treturn historyLength();\n\t}\n\n\t/*\n\t\tActivate the moment at the given index within the history.\n\t*/\n\tfunction historyGoTo(index) {\n\t\tif (DEBUG) { console.log(`[State/historyGoTo(index: ${index})]`); }\n\n\t\tif (\n\t\t\t   index == null /* lazy equality for null */\n\t\t\t|| index < 0\n\t\t\t|| index >= historySize()\n\t\t\t|| index === _activeIndex\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\t_activeIndex = index;\n\t\tmomentActivate(_activeIndex);\n\n\t\treturn true;\n\t}\n\n\t/*\n\t\tActivate the moment at the given offset from the active moment within the history.\n\t*/\n\tfunction historyGo(offset) {\n\t\tif (DEBUG) { console.log(`[State/historyGo(offset: ${offset})]`); }\n\n\t\tif (offset == null || offset === 0) { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\treturn historyGoTo(_activeIndex + offset);\n\t}\n\n\t/*\n\t\tReturns the delta encoded form of the given history array.\n\t*/\n\tfunction historyDeltaEncode(historyArr) {\n\t\tif (!Array.isArray(historyArr)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (historyArr.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst delta = [historyArr[0]];\n\n\t\tfor (let i = 1, iend = historyArr.length; i < iend; ++i) {\n\t\t\tdelta.push(Diff.diff(historyArr[i - 1], historyArr[i]));\n\t\t}\n\n\t\treturn delta;\n\t}\n\n\t/*\n\t\tReturns a history array from the given delta encoded history array.\n\t*/\n\tfunction historyDeltaDecode(delta) {\n\t\tif (!Array.isArray(delta)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (delta.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst historyArr = [clone(delta[0])];\n\n\t\tfor (let i = 1, iend = delta.length; i < iend; ++i) {\n\t\t\thistoryArr.push(Diff.patch(historyArr[i - 1], delta[i]));\n\t\t}\n\n\t\treturn historyArr;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPRNG Functions.\n\t*******************************************************************************************************************/\n\tfunction prngInit(seed, useEntropy) {\n\t\tif (DEBUG) { console.log(`[State/prngInit(seed: ${seed}, useEntropy: ${useEntropy})]`); }\n\n\t\tif (!historyIsEmpty()) {\n\t\t\tlet scriptSection;\n\n\t\t\tif (TWINE1) { // for Twine 1\n\t\t\t\tscriptSection = 'a script-tagged passage';\n\t\t\t}\n\t\t\telse { // for Twine 2\n\t\t\t\tscriptSection = 'the Story JavaScript';\n\t\t\t}\n\n\t\t\tthrow new Error(`State.initPRNG must be called during initialization, within either ${scriptSection} or the StoryInit special passage`);\n\t\t}\n\n\t\t_prng = new PRNGWrapper(seed, useEntropy);\n\t\t_active.pull = _prng.pull;\n\t}\n\n\tfunction prngIsEnabled() {\n\t\treturn _prng !== null;\n\t}\n\n\tfunction prngPull() {\n\t\treturn _prng ? _prng.pull : NaN;\n\t}\n\n\tfunction prngSeed() {\n\t\treturn _prng ? _prng.seed : null;\n\t}\n\n\tfunction prngRandom() {\n\t\tif (DEBUG) { console.log('[State/prngRandom()]'); }\n\n\t\treturn _prng ? _prng.random() : Math.random();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTemporary Variables Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tClear the temporary variables.\n\t*/\n\tfunction tempVariablesClear() {\n\t\tif (DEBUG) { console.log('[State/tempVariablesReset()]'); }\n\n\t\t_tempVariables = {};\n\n\t\t/* legacy */\n\t\tTempVariables = _tempVariables; // eslint-disable-line no-undef\n\t\t/* /legacy */\n\t}\n\n\t/*\n\t\tReturns the current temporary variables.\n\t*/\n\tfunction tempVariables() {\n\t\treturn _tempVariables;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tVariable Chain Parsing Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the value of the given story/temporary variable.\n\t*/\n\tfunction variableGet(name) {\n\t\tconst varData = _parseVariableChain(name);\n\n\t\tif (varData === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst pNames = varData.names;\n\t\tlet retVal = varData.store;\n\n\t\tfor (let i = 0, iend = pNames.length; i < iend; ++i) {\n\t\t\tif (typeof retVal[pNames[i]] === 'undefined') {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tretVal = retVal[pNames[i]];\n\t\t}\n\n\t\treturn retVal;\n\t}\n\n\t/*\n\t\tSets the value of the given story/temporary variable.\n\t*/\n\tfunction variableSet(name, value) {\n\t\tconst varData = _parseVariableChain(name);\n\n\t\tif (varData === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst pNames  = varData.names;\n\t\tconst varName = pNames.pop();\n\t\tlet baseObj = varData.store;\n\n\t\tfor (let i = 0, iend = pNames.length; i < iend; ++i) {\n\t\t\tif (typeof baseObj[pNames[i]] === 'undefined') {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tbaseObj = baseObj[pNames[i]];\n\t\t}\n\n\t\tbaseObj[varName] = value;\n\t\treturn true;\n\t}\n\n\t/*\n\t\tReturns the property name chain of the given story/temporary variable,\n\t\twhich may be of arbitrary complexity.\n\t*/\n\tconst _parseVarRegExp = new RegExp(`^(?:${Patterns.variableSigil}(${Patterns.identifier})|\\\\.(${Patterns.identifier})|\\\\[(?:(?:\"((?:\\\\\\\\.|[^\"\\\\\\\\])+)\")|(?:'((?:\\\\\\\\.|[^'\\\\\\\\])+)')|(${Patterns.variableSigil}${Patterns.identifierFirstChar}.*)|(\\\\d+))\\\\])`);\n\tfunction _parseVariableChain(varText) {\n\t\tconst retVal = {\n\t\t\tstore : varText[0] === '$' ? State.variables : State.temporary,\n\t\t\tnames : []\n\t\t};\n\t\tlet text  = varText;\n\t\tlet match;\n\n\t\twhile ((match = _parseVarRegExp.exec(text)) !== null) {\n\t\t\t// Remove full match from text.\n\t\t\ttext = text.slice(match[0].length);\n\n\t\t\t// Base variable.\n\t\t\tif (match[1]) {\n\t\t\t\tretVal.names.push(match[1]);\n\t\t\t}\n\n\t\t\t// Dot property.\n\t\t\telse if (match[2]) {\n\t\t\t\tretVal.names.push(match[2]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (double quoted).\n\t\t\telse if (match[3]) {\n\t\t\t\tretVal.names.push(match[3]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (single quoted).\n\t\t\telse if (match[4]) {\n\t\t\t\tretVal.names.push(match[4]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (embedded variable).\n\t\t\telse if (match[5]) {\n\t\t\t\tretVal.names.push(variableGet(match[5]));\n\t\t\t}\n\n\t\t\t// Square-bracketed property (numeric index).\n\t\t\telse if (match[6]) {\n\t\t\t\tretVal.names.push(Number(match[6]));\n\t\t\t}\n\t\t}\n\n\t\treturn text === '' ? retVal : null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tStory Metadata Functions.\n\t*******************************************************************************************************************/\n\tconst _METADATA_STORE = 'metadata';\n\n\tfunction metadataClear() {\n\t\tstorage.delete(_METADATA_STORE);\n\t}\n\n\tfunction metadataDelete(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.delete key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\n\t\tif (store && store.hasOwnProperty(key)) {\n\t\t\tif (Object.keys(store).length === 1) {\n\t\t\t\tstorage.delete(_METADATA_STORE);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdelete store[key];\n\t\t\t\tstorage.set(_METADATA_STORE, store);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction metadataGet(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.get key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store && store.hasOwnProperty(key) ? store[key] : undefined;\n\t}\n\n\tfunction metadataHas(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.has key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store && store.hasOwnProperty(key);\n\t}\n\n\tfunction metadataSet(key, value) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.set key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tif (typeof value === 'undefined') {\n\t\t\tmetadataDelete(key);\n\t\t}\n\t\telse {\n\t\t\tconst store = storage.get(_METADATA_STORE) || {};\n\t\t\tstore[key] = value;\n\t\t\tstorage.set(_METADATA_STORE, store);\n\t\t}\n\t}\n\n\tfunction metadataSize() {\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store ? Object.keys(store).length : 0;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tState Functions.\n\t\t*/\n\t\treset            : { value : stateReset },\n\t\trestore          : { value : stateRestore },\n\t\tmarshalForSave   : { value : stateMarshalForSave },\n\t\tunmarshalForSave : { value : stateUnmarshalForSave },\n\t\texpired          : { get : stateExpired },\n\t\tturns            : { get : stateTurns },\n\t\tpassages         : { get : stateTitles },\n\t\thasPlayed        : { value : stateHasPlayed },\n\n\t\t/*\n\t\t\tMoment Functions.\n\t\t*/\n\t\tactive      : { get : momentActive },\n\t\tactiveIndex : { get : momentActiveIndex },\n\t\tpassage     : { get : momentActiveTitle },     // shortcut for `State.active.title`\n\t\tvariables   : { get : momentActiveVariables }, // shortcut for `State.active.variables`\n\n\t\t/*\n\t\t\tHistory Functions.\n\t\t*/\n\t\thistory     : { get : historyGet },\n\t\tlength      : { get : historyLength },\n\t\tsize        : { get : historySize },\n\t\tisEmpty     : { value : historyIsEmpty },\n\t\tcurrent     : { get : historyCurrent },\n\t\ttop         : { get : historyTop },\n\t\tbottom      : { get : historyBottom },\n\t\tindex       : { value : historyIndex },\n\t\tpeek        : { value : historyPeek },\n\t\thas         : { value : historyHas },\n\t\tcreate      : { value : historyCreate },\n\t\tgoTo        : { value : historyGoTo },\n\t\tgo          : { value : historyGo },\n\t\tdeltaEncode : { value : historyDeltaEncode },\n\t\tdeltaDecode : { value : historyDeltaDecode },\n\n\t\t/*\n\t\t\tPRNG Functions.\n\t\t*/\n\t\tprng : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tinit      : { value : prngInit },\n\t\t\t\tisEnabled : { value : prngIsEnabled },\n\t\t\t\tpull      : { get : prngPull },\n\t\t\t\tseed      : { get : prngSeed }\n\t\t\t}))\n\t\t},\n\t\trandom : { value : prngRandom },\n\n\t\t/*\n\t\t\tTemporary Variables Functions.\n\t\t*/\n\t\tclearTemporary : { value : tempVariablesClear },\n\t\ttemporary      : { get : tempVariables },\n\n\t\t/*\n\t\t\tVariable Chain Parsing Functions.\n\t\t*/\n\t\tgetVar : { value : variableGet },\n\t\tsetVar : { value : variableSet },\n\n\t\t/*\n\t\t\tStory Metadata Functions.\n\t\t*/\n\t\tmetadata : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tclear  : { value : metadataClear },\n\t\t\t\tdelete : { value : metadataDelete },\n\t\t\t\tget    : { value : metadataGet },\n\t\t\t\thas    : { value : metadataHas },\n\t\t\t\tset    : { value : metadataSet },\n\t\t\t\tsize   : { get : metadataSize }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tinitPRNG : { value : prngInit },\n\t\trestart  : { value : () => Engine.restart() },\n\t\tbackward : { value : () => Engine.backward() },\n\t\tforward  : { value : () => Engine.forward() },\n\t\tdisplay  : { value : (...args) => Engine.display(...args) },\n\t\tshow     : { value : (...args) => Engine.show(...args) },\n\t\tplay     : { value : (...args) => Engine.play(...args) }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/scripting.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Engine, Patterns, State, Story, Util */\n\nvar Scripting = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/* eslint-disable no-unused-vars */\n\n\t/*******************************************************************************************************************\n\t\tDeprecated Legacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Returns the jQuery-wrapped target element(s) after making them accessible\n\t\tclickables (ARIA compatibility).\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction addAccessibleClickHandler(targets, selector, handler, one, namespace) {\n\t\tif (arguments.length < 2) {\n\t\t\tthrow new Error('addAccessibleClickHandler insufficient number of parameters');\n\t\t}\n\n\t\tlet fn;\n\t\tlet opts;\n\n\t\tif (typeof selector === 'function') {\n\t\t\tfn = selector;\n\t\t\topts = {\n\t\t\t\tnamespace : one,\n\t\t\t\tone       : !!handler\n\t\t\t};\n\t\t}\n\t\telse {\n\t\t\tfn = handler;\n\t\t\topts = {\n\t\t\t\tnamespace,\n\t\t\t\tone : !!one,\n\t\t\t\tselector\n\t\t\t};\n\t\t}\n\n\t\tif (typeof fn !== 'function') {\n\t\t\tthrow new TypeError('addAccessibleClickHandler handler parameter must be a function');\n\t\t}\n\n\t\treturn jQuery(targets).ariaClick(opts, fn);\n\t}\n\n\t/*\n\t\t[DEPRECATED] Returns a new DOM element, optionally appending it to the passed DOM element, if any.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction insertElement(place, type, id, classNames, text, title) { // eslint-disable-line max-params\n\t\tconst $el = jQuery(document.createElement(type));\n\n\t\t// Add attributes/properties.\n\t\tif (id) {\n\t\t\t$el.attr('id', id);\n\t\t}\n\n\t\tif (classNames) {\n\t\t\t$el.addClass(classNames);\n\t\t}\n\n\t\tif (title) {\n\t\t\t$el.attr('title', title);\n\t\t}\n\n\t\t// Add text content.\n\t\tif (text) {\n\t\t\t$el.text(text);\n\t\t}\n\n\t\t// Append it to the given node.\n\t\tif (place) {\n\t\t\t$el.appendTo(place);\n\t\t}\n\n\t\treturn $el[0];\n\t}\n\n\t/*\n\t\t[DEPRECATED] Creates a new text node and appends it to the passed DOM element.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction insertText(place, text) {\n\t\tjQuery(place).append(document.createTextNode(text));\n\t}\n\n\t/*\n\t\t[DEPRECATED] Removes all children from the passed DOM node.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction removeChildren(node) {\n\t\tjQuery(node).empty();\n\t}\n\n\t/*\n\t\t[DEPRECATED] Removes the passed DOM node.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction removeElement(node) {\n\t\tjQuery(node).remove();\n\t}\n\n\t/*\n\t\t[DEPRECATED] Fades a DOM element in or out.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction fade(el, options) {\n\t\t/* eslint-disable no-param-reassign */\n\t\tconst direction = options.fade === 'in' ? 1 : -1;\n\t\tlet current;\n\t\tlet proxy      = el.cloneNode(true);\n\t\tlet intervalId; // eslint-disable-line prefer-const\n\n\t\tfunction tick() {\n\t\t\tcurrent += 0.05 * direction;\n\t\t\tsetOpacity(proxy, Math.easeInOut(current));\n\n\t\t\tif (direction === 1 && current >= 1 || direction === -1 && current <= 0) {\n\t\t\t\tel.style.visibility = options.fade === 'in' ? 'visible' : 'hidden';\n\t\t\t\tproxy.parentNode.replaceChild(el, proxy);\n\t\t\t\tproxy = null;\n\t\t\t\twindow.clearInterval(intervalId);\n\n\t\t\t\tif (options.onComplete) {\n\t\t\t\t\toptions.onComplete();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction setOpacity(el, opacity) {\n\t\t\t// Old IE.\n\t\t\tel.style.zoom = 1;\n\t\t\tel.style.filter = `alpha(opacity=${Math.floor(opacity * 100)})`;\n\n\t\t\t// CSS.\n\t\t\tel.style.opacity = opacity;\n\t\t}\n\n\t\tel.parentNode.replaceChild(proxy, el);\n\n\t\tif (options.fade === 'in') {\n\t\t\tcurrent = 0;\n\t\t\tproxy.style.visibility = 'visible';\n\t\t}\n\t\telse {\n\t\t\tcurrent = 1;\n\t\t}\n\n\t\tsetOpacity(proxy, current);\n\t\tintervalId = window.setInterval(tick, 25);\n\t\t/* eslint-enable no-param-reassign */\n\t}\n\n\t/*\n\t\t[DEPRECATED] Scrolls the browser window to ensure that a DOM element is in view.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction scrollWindowTo(el, incrementBy) {\n\t\t/* eslint-disable no-param-reassign */\n\t\tlet increment = incrementBy != null ? Number(incrementBy) : 0.1; // lazy equality for null\n\n\t\tif (Number.isNaN(increment) || !Number.isFinite(increment) || increment < 0) {\n\t\t\tincrement = 0.1;\n\t\t}\n\t\telse if (increment > 1) {\n\t\t\tincrement = 1;\n\t\t}\n\n\t\tconst start     = window.scrollY ? window.scrollY : document.body.scrollTop;\n\t\tconst end       = ensureVisible(el);\n\t\tconst distance  = Math.abs(start - end);\n\t\tconst direction = start > end ? -1 : 1;\n\t\tlet progress   = 0;\n\t\tlet intervalId; // eslint-disable-line prefer-const\n\n\t\tfunction tick() {\n\t\t\tprogress += increment;\n\t\t\twindow.scroll(0, start + direction * (distance * Math.easeInOut(progress)));\n\n\t\t\tif (progress >= 1) {\n\t\t\t\twindow.clearInterval(intervalId);\n\t\t\t}\n\t\t}\n\n\t\tfunction findPosY(el) { // eslint-disable-line no-shadow\n\t\t\tlet curtop = 0;\n\n\t\t\twhile (el.offsetParent) {\n\t\t\t\tcurtop += el.offsetTop;\n\t\t\t\tel = el.offsetParent;\n\t\t\t}\n\n\t\t\treturn curtop;\n\t\t}\n\n\t\tfunction ensureVisible(el) { // eslint-disable-line no-shadow\n\t\t\tconst posTop    = findPosY(el);\n\t\t\tconst posBottom = posTop + el.offsetHeight;\n\t\t\tconst winTop    = window.scrollY ? window.scrollY : document.body.scrollTop;\n\t\t\tconst winHeight = window.innerHeight ? window.innerHeight : document.body.clientHeight;\n\t\t\tconst winBottom = winTop + winHeight;\n\n\t\t\treturn posTop >= winTop && posBottom > winBottom && el.offsetHeight < winHeight\n\t\t\t\t? posTop - (winHeight - el.offsetHeight) + 20\n\t\t\t\t: posTop;\n\t\t}\n\n\t\tintervalId = window.setInterval(tick, 25);\n\t\t/* eslint-enable no-param-reassign */\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUser Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a random value from its given arguments.\n\t*/\n\tfunction either(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn Array.prototype.concat.apply([], arguments).random();\n\t}\n\n\t/*\n\t\tRemoves the given key, and its value, from the story metadata store.\n\t*/\n\tfunction forget(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`forget key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\tState.metadata.delete(key);\n\t}\n\n\t/*\n\t\tReturns whether a passage with the given title exists within the story\n\t\thistory.  If multiple passage titles are given, returns the logical-AND\n\t\taggregate of the set.\n\t*/\n\tfunction hasVisited(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('hasVisited called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst played  = State.passages;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend; ++i) {\n\t\t\tif (!played.includes(needles[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/*\n\t\tReturns the number of turns that have passed since the last instance of the given passage\n\t\toccurred within the story history or `-1` if it does not exist.  If multiple passages are\n\t\tgiven, returns the lowest count (which can be `-1`).\n\t*/\n\tfunction lastVisited(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('lastVisited called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn -1;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst played  = State.passages;\n\t\tconst uBound  = played.length - 1;\n\t\tlet turns = State.turns;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend && turns > -1; ++i) {\n\t\t\tconst lastIndex = played.lastIndexOf(needles[i]);\n\t\t\tturns = Math.min(turns, lastIndex === -1 ? -1 : uBound - lastIndex);\n\t\t}\n\n\t\treturn turns;\n\t}\n\n\t/*\n\t\tSets the given key/value pair within the story metadata store.\n\t*/\n\tfunction memorize(key, value) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`memorize key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\tState.metadata.set(key, value);\n\t}\n\n\t/*\n\t\tReturns the title of the current passage.\n\t*/\n\tfunction passage() {\n\t\treturn State.passage;\n\t}\n\n\t/*\n\t\tReturns the title of a previous passage, either the most recent one whose title does not\n\t\tmatch that of the active passage or the one at the optional offset, or an empty string,\n\t\tif there is no such passage.\n\t*/\n\tfunction previous(/* legacy: offset */) {\n\t\tconst passages = State.passages;\n\n\t\t/* legacy: behavior with an offset */\n\t\tif (arguments.length > 0) {\n\t\t\tconst offset = Number(arguments[0]);\n\n\t\t\tif (!Number.isSafeInteger(offset) || offset < 1) {\n\t\t\t\tthrow new RangeError('previous offset parameter must be a positive integer greater than zero');\n\t\t\t}\n\n\t\t\treturn passages.length > offset ? passages[passages.length - 1 - offset] : '';\n\t\t}\n\t\t/* /legacy */\n\n\t\tfor (let i = passages.length - 2; i >= 0; --i) {\n\t\t\tif (passages[i] !== State.passage) {\n\t\t\t\treturn passages[i];\n\t\t\t}\n\t\t}\n\n\t\treturn '';\n\t}\n\n\t/*\n\t\tReturns a pseudo-random whole number (integer) within the range of the given bounds.\n\t*/\n\tfunction random(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('random called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = Math.trunc(arguments[0]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Math.trunc(arguments[0]);\n\t\t\tmax = Math.trunc(arguments[1]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (!Number.isInteger(min)) {\n\t\t\tthrow new Error('random min parameter must be an integer');\n\t\t}\n\t\tif (!Number.isInteger(max)) {\n\t\t\tthrow new Error('random max parameter must be an integer');\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn Math.floor(State.random() * (max - min + 1)) + min;\n\t}\n\n\t/*\n\t\tReturns a pseudo-random real number (floating-point) within the range of the given bounds.\n\n\t\tNOTE: Unlike with its sibling function `random()`, the `max` parameter\n\t\tis exclusive, not inclusive—i.e. the range goes to, but does not include,\n\t\tthe given value.\n\t*/\n\tfunction randomFloat(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('randomFloat called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0.0;\n\t\t\tmax = Number(arguments[0]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Number(arguments[0]);\n\t\t\tmax = Number(arguments[1]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (Number.isNaN(min) || !Number.isFinite(min)) {\n\t\t\tthrow new Error('randomFloat min parameter must be a number');\n\t\t}\n\t\tif (Number.isNaN(max) || !Number.isFinite(max)) {\n\t\t\tthrow new Error('randomFloat max parameter must be a number');\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn State.random() * (max - min) + min;\n\t}\n\n\t/*\n\t\tReturns the value of the given key from the story metadata store\n\t\tor the given default value if the key does not exist.\n\t*/\n\tfunction recall(key, defaultValue) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`recall key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\treturn State.metadata.has(key) ? State.metadata.get(key) : defaultValue;\n\t}\n\n\t/*\n\t\tReturns a new array consisting of all of the tags of the given passages.\n\t*/\n\tfunction tags(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\treturn Story.get(State.passage).tags.slice(0);\n\t\t}\n\n\t\tconst passages = Array.prototype.concat.apply([], arguments);\n\t\tlet tags = [];\n\n\t\tfor (let i = 0, iend = passages.length; i < iend; ++i) {\n\t\t\ttags = tags.concat(Story.get(passages[i]).tags);\n\t\t}\n\n\t\treturn tags;\n\t}\n\n\t/*\n\t\tReturns a reference to the current temporary _variables store.\n\t*/\n\tfunction temporary() {\n\t\treturn State.temporary;\n\t}\n\n\t/*\n\t\tReturns the number of milliseconds which have passed since the current passage was rendered.\n\t*/\n\tfunction time() {\n\t\treturn Engine.lastPlay === null ? 0 : Util.now() - Engine.lastPlay;\n\t}\n\n\t/*\n\t\tReturns the number of passages that the player has visited.\n\n\t\tNOTE: Passages which were visited but have been undone—e.g. via the backward\n\t\tbutton or the `<<back>>` macro—are no longer part of the in-play story\n\t\thistory and thus are not tallied.  Passages which were visited but have\n\t\texpired from the story history, on the other hand, are tallied.\n\t*/\n\tfunction turns() {\n\t\treturn State.turns;\n\t}\n\n\t/*\n\t\tReturns a reference to the current story $variables store.\n\t*/\n\tfunction variables() {\n\t\treturn State.variables;\n\t}\n\n\t/*\n\t\tReturns the number of times that the passage with the given title exists within the story\n\t\thistory.  If multiple passage titles are given, returns the lowest count.\n\t*/\n\tfunction visited(/* variadic */) {\n\t\tif (State.isEmpty()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments.length === 0 ? [State.passage] : arguments);\n\t\tconst played  = State.passages;\n\t\tlet count = State.turns;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend && count > 0; ++i) {\n\t\t\tcount = Math.min(count, played.count(needles[i]));\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/*\n\t\tReturns the number of passages within the story history which are tagged with all of the given tags.\n\t*/\n\tfunction visitedTags(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('visitedTags called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst nLength = needles.length;\n\t\tconst played  = State.passages;\n\t\tconst seen    = new Map();\n\t\tlet count = 0;\n\n\t\tfor (let i = 0, iend = played.length; i < iend; ++i) {\n\t\t\tconst title = played[i];\n\n\t\t\tif (seen.has(title)) {\n\t\t\t\tif (seen.get(title)) {\n\t\t\t\t\t++count;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst tags = Story.get(title).tags;\n\n\t\t\t\tif (tags.length > 0) {\n\t\t\t\t\tlet found = 0;\n\n\t\t\t\t\tfor (let j = 0; j < nLength; ++j) {\n\t\t\t\t\t\tif (tags.includes(needles[j])) {\n\t\t\t\t\t\t\t++found;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (found === nLength) {\n\t\t\t\t\t\t++count;\n\t\t\t\t\t\tseen.set(title, true);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tseen.set(title, false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/* eslint-enable no-unused-vars */\n\n\n\t/*******************************************************************************************************************\n\t\tImport Functions.\n\t*******************************************************************************************************************/\n\tvar { // eslint-disable-line no-var\n\t\t/* eslint-disable no-unused-vars */\n\t\timportScripts,\n\t\timportStyles\n\t\t/* eslint-enable no-unused-vars */\n\t} = (() => {\n\t\t// Slugify the given URL.\n\t\tfunction slugifyUrl(url) {\n\t\t\treturn Util.parseUrl(url).path\n\t\t\t\t.replace(/^[^\\w]+|[^\\w]+$/g, '')\n\t\t\t\t.replace(/[^\\w]+/g, '-')\n\t\t\t\t.toLocaleLowerCase();\n\t\t}\n\n\t\t// Add a <script> element which will load the script from the given URL.\n\t\tfunction addScript(url) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t/*\n\t\t\t\t\tWARNING: The ordering of the code within this function is important,\n\t\t\t\t\tas some browsers don't play well with different arrangements, so\n\t\t\t\t\tbe careful when mucking around with it.\n\n\t\t\t\t\tThe best supported ordering seems be: events → DOM append → attributes.\n\t\t\t\t*/\n\t\t\t\tjQuery(document.createElement('script'))\n\t\t\t\t\t.one('load abort error', ev => {\n\t\t\t\t\t\tjQuery(ev.target).off();\n\n\t\t\t\t\t\tif (ev.type === 'load') {\n\t\t\t\t\t\t\tresolve(ev.target);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treject(new Error(`importScripts failed to load the script \"${url}\".`));\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo(document.head)\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid   : `script-imported-${slugifyUrl(url)}`,\n\t\t\t\t\t\ttype : 'text/javascript',\n\t\t\t\t\t\tsrc  : url\n\t\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\t// Add a <link> element which will load the stylesheet from the given URL.\n\t\tfunction addStyle(url) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t/*\n\t\t\t\t\tWARNING: The ordering of the code within this function is important,\n\t\t\t\t\tas some browsers don't play well with different arrangements, so\n\t\t\t\t\tbe careful when mucking around with it.\n\n\t\t\t\t\tThe best supported ordering seems be: events → DOM append → attributes.\n\t\t\t\t*/\n\t\t\t\tjQuery(document.createElement('link'))\n\t\t\t\t\t.one('load abort error', ev => {\n\t\t\t\t\t\tjQuery(ev.target).off();\n\n\t\t\t\t\t\tif (ev.type === 'load') {\n\t\t\t\t\t\t\tresolve(ev.target);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treject(new Error(`importStyles failed to load the stylesheet \"${url}\".`));\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo(document.head)\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid   : `style-imported-${slugifyUrl(url)}`,\n\t\t\t\t\t\trel  : 'stylesheet',\n\t\t\t\t\t\thref : url\n\t\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\t// Turn a list of callbacks into a sequential chain of `Promise` objects.\n\t\tfunction sequence(callbacks) {\n\t\t\treturn callbacks.reduce((seq, fn) => seq = seq.then(fn), Promise.resolve()); // eslint-disable-line no-param-reassign\n\t\t}\n\n\t\t/*\n\t\t\tImport scripts from a URL.\n\t\t*/\n\t\tfunction importScripts(...urls) {\n\t\t\treturn Promise.all(urls.map(oneOrSeries => {\n\t\t\t\t// Array of URLs to be imported in sequence.\n\t\t\t\tif (Array.isArray(oneOrSeries)) {\n\t\t\t\t\treturn sequence(oneOrSeries.map(url => () => addScript(url)));\n\t\t\t\t}\n\n\t\t\t\t// Single URL to be imported.\n\t\t\t\treturn addScript(oneOrSeries);\n\t\t\t}));\n\t\t}\n\n\t\t/*\n\t\t\tImport stylesheets from a URL.\n\t\t*/\n\t\tfunction importStyles(...urls) {\n\t\t\treturn Promise.all(urls.map(oneOrSeries => {\n\t\t\t\t// Array of URLs to be imported in sequence.\n\t\t\t\tif (Array.isArray(oneOrSeries)) {\n\t\t\t\t\treturn sequence(oneOrSeries.map(url => () => addStyle(url)));\n\t\t\t\t}\n\n\t\t\t\t// Single URL to be imported.\n\t\t\t\treturn addStyle(oneOrSeries);\n\t\t\t}));\n\t\t}\n\n\t\t// Exports.\n\t\treturn {\n\t\t\timportScripts,\n\t\t\timportStyles\n\t\t};\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tParsing Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the given string after converting all TwineScript syntactical sugars to\n\t\ttheir native JavaScript counterparts.\n\t*/\n\tconst parse = (() => {\n\t\tconst parseMap = Object.freeze({\n\t\t\t/* eslint-disable quote-props */\n\t\t\t// Story $variable sigil-prefix.\n\t\t\t'$'     : 'State.variables.',\n\t\t\t// Temporary _variable sigil-prefix.\n\t\t\t'_'     : 'State.temporary.',\n\t\t\t// Assignment operators.\n\t\t\t'to'    : '=',\n\t\t\t// Equality operators.\n\t\t\t'eq'    : '==',\n\t\t\t'neq'   : '!=',\n\t\t\t'is'    : '===',\n\t\t\t'isnot' : '!==',\n\t\t\t// Relational operators.\n\t\t\t'gt'    : '>',\n\t\t\t'gte'   : '>=',\n\t\t\t'lt'    : '<',\n\t\t\t'lte'   : '<=',\n\t\t\t// Logical operators.\n\t\t\t'and'   : '&&',\n\t\t\t'or'    : '||',\n\t\t\t// Unary operators.\n\t\t\t'not'   : '!',\n\t\t\t'def'   : '\"undefined\" !== typeof',\n\t\t\t'ndef'  : '\"undefined\" === typeof'\n\t\t\t/* eslint-enable quote-props */\n\t\t});\n\t\tconst parseRe = new RegExp([\n\t\t\t'(\"\"|\\'\\')',                                          // 1=Empty quotes\n\t\t\t'(\"(?:\\\\\\\\.|[^\"\\\\\\\\])+\")',                            // 2=Double quoted, non-empty\n\t\t\t\"('(?:\\\\\\\\.|[^'\\\\\\\\])+')\",                            // 3=Single quoted, non-empty\n\t\t\t'([=+\\\\-*\\\\/%<>&\\\\|\\\\^~!?:,;\\\\(\\\\)\\\\[\\\\]{}]+)',       // 4=Operator delimiters\n\t\t\t'([^\"\\'=+\\\\-*\\\\/%<>&\\\\|\\\\^~!?:,;\\\\(\\\\)\\\\[\\\\]{}\\\\s]+)' // 5=Barewords\n\t\t].join('|'), 'g');\n\t\tconst varTest = new RegExp(`^${Patterns.variable}`);\n\n\t\tfunction parse(rawCodeString) {\n\t\t\tif (parseRe.lastIndex !== 0) {\n\t\t\t\tthrow new RangeError('Scripting.parse last index is non-zero at start');\n\t\t\t}\n\n\t\t\tlet code  = rawCodeString;\n\t\t\tlet match;\n\n\t\t\twhile ((match = parseRe.exec(code)) !== null) {\n\t\t\t\t// no-op: Empty quotes | Double quoted | Single quoted | Operator delimiters\n\n\t\t\t\t/*\n\t\t\t\t\tBarewords.\n\t\t\t\t*/\n\t\t\t\tif (match[5]) {\n\t\t\t\t\tlet token = match[5];\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is simply a dollar-sign or underscore, then it's either\n\t\t\t\t\t\tjust the raw character or, probably, a function alias, so skip it.\n\t\t\t\t\t*/\n\t\t\t\t\tif (token === '$' || token === '_') {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is a story $variable or temporary _variable, reset it\n\t\t\t\t\t\tto just its sigil—for later mapping.\n\t\t\t\t\t*/\n\t\t\t\t\telse if (varTest.test(token)) {\n\t\t\t\t\t\ttoken = token[0];\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is `is`, check to see if it's followed by `not`, if so,\n\t\t\t\t\t\tconvert them into the `isnot` operator.\n\n\t\t\t\t\t\tNOTE: This is a safety feature, since `$a is not $b` probably sounds\n\t\t\t\t\t\treasonable to most users.\n\t\t\t\t\t*/\n\t\t\t\t\telse if (token === 'is') {\n\t\t\t\t\t\tconst start = parseRe.lastIndex;\n\t\t\t\t\t\tconst part  = code.slice(start);\n\n\t\t\t\t\t\tif (/^\\s+not\\b/.test(part)) {\n\t\t\t\t\t\t\tcode = code.splice(start, part.search(/\\S/));\n\t\t\t\t\t\t\ttoken = 'isnot';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the finalized token has a mapping, replace it within the code string\n\t\t\t\t\t\twith its counterpart.\n\n\t\t\t\t\t\tNOTE: We must use `parseMap.hasOwnProperty(token)` here, rather than\n\t\t\t\t\t\tsimply using something like `parseMap[token]`, otherwise tokens which\n\t\t\t\t\t\tmatch properties from the prototype chain will cause shenanigans.\n\t\t\t\t\t*/\n\t\t\t\t\tif (parseMap.hasOwnProperty(token)) {\n\t\t\t\t\t\tcode = code.splice(\n\t\t\t\t\t\t\tmatch.index,    // starting index\n\t\t\t\t\t\t\ttoken.length,   // replace how many\n\t\t\t\t\t\t\tparseMap[token] // replacement string\n\t\t\t\t\t\t);\n\t\t\t\t\t\tparseRe.lastIndex += parseMap[token].length - token.length;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn code;\n\t\t}\n\n\t\treturn parse;\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tEval Functions.\n\t*******************************************************************************************************************/\n\t/* eslint-disable no-eval, no-extra-parens, no-unused-vars */\n\t/*\n\t\tEvaluates the given JavaScript code and returns the result, throwing if there were errors.\n\t*/\n\tfunction evalJavaScript(code, output) {\n\t\treturn (function (code, output) {\n\t\t\treturn eval(code);\n\t\t}).call(output ? { output } : null, String(code), output);\n\t}\n\n\t/*\n\t\tEvaluates the given TwineScript code and returns the result, throwing if there were errors.\n\t*/\n\tfunction evalTwineScript(code, output) {\n\t\treturn (function (code, output) {\n\t\t\treturn eval(code);\n\t\t}).call(output ? { output } : null, parse(String(code)), output);\n\t}\n\t/* eslint-enable no-eval, no-extra-parens, no-unused-vars */\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tparse           : { value : parse },\n\t\tevalJavaScript  : { value : evalJavaScript },\n\t\tevalTwineScript : { value : evalTwineScript }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/lexer.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar { // eslint-disable-line no-var\n\t/* eslint-disable no-unused-vars */\n\tEOF,\n\tLexer\n\t/* eslint-enable no-unused-vars */\n} = (() => {\n\t'use strict';\n\n\t// End of file (string, actually).\n\tconst EOF = -1;\n\n\n\t/*******************************************************************************************************************\n\t\tLexer Class.\n\t*******************************************************************************************************************/\n\tclass Lexer {\n\t\tconstructor(source, initialState) {\n\t\t\tif (arguments.length < 2) {\n\t\t\t\tthrow new Error('Lexer constructor called with too few parameters (source:string , initialState:function)');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tthis.source  → the string to be scanned\n\t\t\t\tthis.initial → initial state\n\t\t\t\tthis.state   → current state\n\t\t\t\tthis.start   → start position of an item\n\t\t\t\tthis.pos     → current position in the source string\n\t\t\t\tthis.depth   → current brace/bracket/parenthesis nesting depth\n\t\t\t\tthis.items   → scanned item queue\n\t\t\t\tthis.data    → lexing data\n\t\t\t*/\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : source\n\t\t\t\t},\n\n\t\t\t\tinitial : {\n\t\t\t\t\tvalue : initialState\n\t\t\t\t},\n\n\t\t\t\tstate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : initialState\n\t\t\t\t},\n\n\t\t\t\tstart : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\tpos : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\tdepth : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\titems : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : []\n\t\t\t\t},\n\n\t\t\t\tdata : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : {}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treset() {\n\t\t\tthis.state  = this.initial;\n\t\t\tthis.start  = 0;\n\t\t\tthis.pos    = 0;\n\t\t\tthis.depth  = 0;\n\t\t\tthis.items  = [];\n\t\t\tthis.data   = {};\n\t\t}\n\n\t\trun() {\n\t\t\t// scan the source string until no states remain\n\t\t\twhile (this.state !== null) {\n\t\t\t\tthis.state = this.state(this);\n\t\t\t}\n\n\t\t\t// return the array of items\n\t\t\treturn this.items;\n\t\t}\n\n\t\tnextItem() {\n\t\t\t// scan the source string until we have an item or no states remain\n\t\t\twhile (this.items.length === 0 && this.state !== null) {\n\t\t\t\tthis.state = this.state(this);\n\t\t\t}\n\n\t\t\t// return the current item\n\t\t\treturn this.items.shift();\n\t\t}\n\n\t\tnext() {\n\t\t\tif (this.pos >= this.source.length) {\n\t\t\t\treturn EOF;\n\t\t\t}\n\n\t\t\treturn this.source[this.pos++];\n\t\t}\n\n\t\tpeek() {\n\t\t\tif (this.pos >= this.source.length) {\n\t\t\t\treturn EOF;\n\t\t\t}\n\n\t\t\treturn this.source[this.pos];\n\t\t}\n\n\t\tbackup(num) {\n\t\t\t// if (num) {\n\t\t\t// \tthis.pos -= num;\n\t\t\t// }\n\t\t\t// else {\n\t\t\t// \t--this.pos;\n\t\t\t// }\n\t\t\tthis.pos -= num || 1;\n\t\t}\n\n\t\tforward(num) {\n\t\t\t// if (num) {\n\t\t\t// \tthis.pos += num;\n\t\t\t// }\n\t\t\t// else {\n\t\t\t// \t++this.pos;\n\t\t\t// }\n\t\t\tthis.pos += num || 1;\n\t\t}\n\n\t\tignore() {\n\t\t\tthis.start = this.pos;\n\t\t}\n\n\t\taccept(valid) {\n\t\t\tconst ch = this.next();\n\n\t\t\tif (ch === EOF) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (valid.includes(ch)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t\treturn false;\n\t\t}\n\n\t\tacceptRe(validRe) {\n\t\t\tconst ch = this.next();\n\n\t\t\tif (ch === EOF) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (validRe.test(ch)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t\treturn false;\n\t\t}\n\n\t\tacceptRun(valid) {\n\t\t\tfor (;;) {\n\t\t\t\tconst ch = this.next();\n\n\t\t\t\tif (ch === EOF) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!valid.includes(ch)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t}\n\n\t\tacceptRunRe(validRe) {\n\t\t\tfor (;;) {\n\t\t\t\tconst ch = this.next();\n\n\t\t\t\tif (ch === EOF) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!validRe.test(ch)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t}\n\n\t\temit(type) {\n\t\t\tthis.items.push({\n\t\t\t\ttype,\n\t\t\t\ttext  : this.source.slice(this.start, this.pos),\n\t\t\t\tstart : this.start,\n\t\t\t\tpos   : this.pos\n\t\t\t});\n\t\t\tthis.start = this.pos;\n\t\t}\n\n\t\terror(type, message) {\n\t\t\tif (arguments.length < 2) {\n\t\t\t\tthrow new Error('Lexer.prototype.error called with too few parameters (type:number , message:string)');\n\t\t\t}\n\n\t\t\tthis.items.push({\n\t\t\t\ttype,\n\t\t\t\tmessage,\n\t\t\t\ttext  : this.source.slice(this.start, this.pos),\n\t\t\t\tstart : this.start,\n\t\t\t\tpos   : this.pos\n\t\t\t});\n\t\t\treturn null;\n\t\t}\n\n\t\tstatic enumFromNames(names) {\n\t\t\tconst obj = names.reduce((obj, name, i) => {\n\t\t\t\tobj[name] = i; // eslint-disable-line no-param-reassign\n\t\t\t\treturn obj;\n\t\t\t}, {});\n\t\t\treturn Object.freeze(Object.assign(Object.create(null), obj));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn {\n\t\tEOF,\n\t\tLexer\n\t};\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/wikifier.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, EOF, Engine, Lexer, Patterns, Scripting, State, Story, TempState, Util, convertBreaks,\n\t       errorPrologRegExp\n*/\n\n/*\n\tTODO: The Wikifier, and associated code, could stand to receive a serious refactoring.\n*/\n/* eslint-disable max-len */\nvar Wikifier = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Wikifier call depth.\n\tlet _callDepth = 0;\n\n\n\t/*******************************************************************************************************************\n\t\tWikifier Class.\n\t*******************************************************************************************************************/\n\tclass Wikifier {\n\t\tconstructor(destination, source, options) {\n\t\t\tif (Wikifier.Parser.Profile.isEmpty()) {\n\t\t\t\tWikifier.Parser.Profile.compile();\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// General Wikifier properties.\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : String(source)\n\t\t\t\t},\n\n\t\t\t\toptions : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : Object.assign({\n\t\t\t\t\t\tprofile : 'all'\n\t\t\t\t\t}, options)\n\t\t\t\t},\n\n\t\t\t\tnextMatch : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\toutput : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t// Macro parser ('macro') related properties.\n\t\t\t\t_rawArgs : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : ''\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// No destination specified.  Create a fragment to act as the output buffer.\n\t\t\tif (destination == null) { // lazy equality for null\n\t\t\t\tthis.output = document.createDocumentFragment();\n\t\t\t}\n\n\t\t\t// jQuery-wrapped destination.  Grab the first element.\n\t\t\telse if (destination.jquery) { // cannot use `hasOwnProperty()` here as `jquery` is from jQuery's prototype\n\t\t\t\tthis.output = destination[0];\n\t\t\t}\n\n\t\t\t// Normal destination.\n\t\t\telse {\n\t\t\t\tthis.output = destination;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tWikify the source into the output buffer element, possibly converting line\n\t\t\t\tbreaks into paragraphs.\n\n\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\tto ensure that the call depth is properly restored in the event that an\n\t\t\t\tuncaught exception is thrown during the call to `subWikify()`.\n\t\t\t*/\n\t\t\ttry {\n\t\t\t\t++_callDepth;\n\n\t\t\t\tthis.subWikify(this.output);\n\n\t\t\t\t// Limit line break conversion to non-recursive calls.\n\t\t\t\tif (_callDepth === 1 && Config.cleanupWikifierOutput) {\n\t\t\t\t\tconvertBreaks(this.output);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\t--_callDepth;\n\t\t\t}\n\t\t}\n\n\t\tsubWikify(output, terminator, options) {\n\t\t\t// Cache and temporarily replace the current output buffer.\n\t\t\tconst oldOutput = this.output;\n\t\t\tthis.output = output;\n\n\t\t\tlet newOptions;\n\t\t\tlet oldOptions;\n\n\t\t\t// Parser option overrides.\n\t\t\tif (Wikifier.Option.length > 0) {\n\t\t\t\tnewOptions = Object.assign(newOptions || {}, Wikifier.Option.options);\n\t\t\t}\n\t\t\t// Local parameter option overrides.\n\t\t\tif (options !== null && typeof options === 'object') {\n\t\t\t\tnewOptions = Object.assign(newOptions || {}, options);\n\t\t\t}\n\t\t\t// If new options exist, cache and temporarily replace the current options.\n\t\t\tif (newOptions) {\n\t\t\t\toldOptions = this.options;\n\t\t\t\tthis.options = Object.assign({}, this.options, newOptions);\n\t\t\t}\n\n\t\t\tconst parsersProfile   = Wikifier.Parser.Profile.get(this.options.profile);\n\t\t\tconst terminatorRegExp = terminator\n\t\t\t\t? new RegExp(`(?:${terminator})`, this.options.ignoreTerminatorCase ? 'gim' : 'gm')\n\t\t\t\t: null;\n\t\t\tlet terminatorMatch;\n\t\t\tlet parserMatch;\n\n\t\t\tdo {\n\t\t\t\t// Prepare the RegExp match positions.\n\t\t\t\tparsersProfile.parserRegExp.lastIndex = this.nextMatch;\n\n\t\t\t\tif (terminatorRegExp) {\n\t\t\t\t\tterminatorRegExp.lastIndex = this.nextMatch;\n\t\t\t\t}\n\n\t\t\t\t// Get the first matches.\n\t\t\t\tparserMatch     = parsersProfile.parserRegExp.exec(this.source);\n\t\t\t\tterminatorMatch = terminatorRegExp ? terminatorRegExp.exec(this.source) : null;\n\n\t\t\t\t// Try for a terminator match, unless there's a closer parser match.\n\t\t\t\tif (terminatorMatch && (!parserMatch || terminatorMatch.index <= parserMatch.index)) {\n\t\t\t\t\t// Output any text before the match.\n\t\t\t\t\tif (terminatorMatch.index > this.nextMatch) {\n\t\t\t\t\t\tthis.outputText(this.output, this.nextMatch, terminatorMatch.index);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set the match parameters.\n\t\t\t\t\tthis.matchStart  = terminatorMatch.index;\n\t\t\t\t\tthis.matchLength = terminatorMatch[0].length;\n\t\t\t\t\tthis.matchText   = terminatorMatch[0];\n\t\t\t\t\tthis.nextMatch   = terminatorRegExp.lastIndex;\n\n\t\t\t\t\t// Restore the original output buffer and options.\n\t\t\t\t\tthis.output = oldOutput;\n\n\t\t\t\t\tif (oldOptions) {\n\t\t\t\t\t\tthis.options = oldOptions;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Exit.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Try for a parser match.\n\t\t\t\telse if (parserMatch) {\n\t\t\t\t\t// Output any text before the match.\n\t\t\t\t\tif (parserMatch.index > this.nextMatch) {\n\t\t\t\t\t\tthis.outputText(this.output, this.nextMatch, parserMatch.index);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set the match parameters.\n\t\t\t\t\tthis.matchStart  = parserMatch.index;\n\t\t\t\t\tthis.matchLength = parserMatch[0].length;\n\t\t\t\t\tthis.matchText   = parserMatch[0];\n\t\t\t\t\tthis.nextMatch   = parsersProfile.parserRegExp.lastIndex;\n\n\t\t\t\t\t// Figure out which parser matched.\n\t\t\t\t\tlet matchingParser;\n\n\t\t\t\t\tfor (let i = 1, iend = parserMatch.length; i < iend; ++i) {\n\t\t\t\t\t\tif (parserMatch[i]) {\n\t\t\t\t\t\t\tmatchingParser = i - 1;\n\t\t\t\t\t\t\tbreak; // stop once we've found the matching parser\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Call the parser.\n\t\t\t\t\tparsersProfile.parsers[matchingParser].handler(this);\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} while (terminatorMatch || parserMatch);\n\n\t\t\t// Output any text after the last match.\n\t\t\tif (TempState.break == null) { // lazy equality for null\n\t\t\t\tif (this.nextMatch < this.source.length) {\n\t\t\t\t\tthis.outputText(this.output, this.nextMatch, this.source.length);\n\t\t\t\t\tthis.nextMatch = this.source.length;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// In case of <<break>>/<<continue>>, remove the last <br>.\n\t\t\telse if (\n\t\t\t\t   this.output.lastChild\n\t\t\t\t&& this.output.lastChild.nodeType === Node.ELEMENT_NODE\n\t\t\t\t&& this.output.lastChild.nodeName.toUpperCase() === 'BR'\n\t\t\t) {\n\t\t\t\tjQuery(this.output.lastChild).remove();\n\t\t\t}\n\n\t\t\t// Restore the original output buffer and options.\n\t\t\tthis.output = oldOutput;\n\n\t\t\tif (oldOptions) {\n\t\t\t\tthis.options = oldOptions;\n\t\t\t}\n\t\t}\n\n\t\toutputText(destination, startPos, endPos) {\n\t\t\tdestination.appendChild(document.createTextNode(this.source.substring(startPos, endPos)));\n\t\t}\n\n\t\t/*\n\t\t\t[DEPRECATED] Meant to be called by legacy macros, this returns the raw, unprocessed\n\t\t\ttext given to the currently executing macro.\n\t\t*/\n\t\trawArgs() {\n\t\t\treturn this._rawArgs;\n\t\t}\n\n\t\t/*\n\t\t\t[DEPRECATED] Meant to be called by legacy macros, this returns the text given to\n\t\t\tthe currently executing macro after doing TwineScript-to-JavaScript transformations.\n\t\t*/\n\t\tfullArgs() {\n\t\t\treturn Scripting.parse(this._rawArgs);\n\t\t}\n\n\t\t/*\n\t\t\tReturns the output generated by wikifying the given text, throwing if there were errors.\n\t\t*/\n\t\tstatic wikifyEval(text) {\n\t\t\tconst output = document.createDocumentFragment();\n\n\t\t\tnew Wikifier(output, text);\n\n\t\t\tconst errors = output.querySelector('.error');\n\n\t\t\tif (errors !== null) {\n\t\t\t\tthrow new Error(errors.textContent.replace(errorPrologRegExp, ''));\n\t\t\t}\n\n\t\t\treturn output;\n\t\t}\n\n\t\t/*\n\t\t\tCreate and return an internal link.\n\t\t*/\n\t\tstatic createInternalLink(destination, passage, text, callback) {\n\t\t\tconst $link = jQuery(document.createElement('a'));\n\n\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t$link.attr('data-passage', passage);\n\n\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t$link.addClass('link-internal');\n\n\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t$link.addClass('link-visited');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$link.addClass('link-broken');\n\t\t\t\t}\n\n\t\t\t\t$link.ariaClick({ one : true }, () => {\n\t\t\t\t\tif (typeof callback === 'function') {\n\t\t\t\t\t\tcallback();\n\t\t\t\t\t}\n\n\t\t\t\t\tEngine.play(passage);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (text) {\n\t\t\t\t$link.append(document.createTextNode(text));\n\t\t\t}\n\n\t\t\tif (destination) {\n\t\t\t\t$link.appendTo(destination);\n\t\t\t}\n\n\t\t\t// For legacy-compatibility we must return the DOM node.\n\t\t\treturn $link[0];\n\t\t}\n\n\t\t/*\n\t\t\tCreate and return an external link.\n\t\t*/\n\t\tstatic createExternalLink(destination, url, text) {\n\t\t\tconst $link = jQuery(document.createElement('a'))\n\t\t\t\t.attr('target', '_blank')\n\t\t\t\t.addClass('link-external')\n\t\t\t\t.text(text)\n\t\t\t\t.appendTo(destination);\n\n\t\t\tif (url != null) { // lazy equality for null\n\t\t\t\t$link.attr({\n\t\t\t\t\thref     : url,\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// For legacy-compatibility we must return the DOM node.\n\t\t\treturn $link[0];\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the given link source is external (probably).\n\t\t*/\n\t\tstatic isExternalLink(link) {\n\t\t\tif (Story.has(link)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst urlRegExp = new RegExp(`^${Patterns.url}`, 'gim');\n\t\t\treturn urlRegExp.test(link) || /[/.?#]/.test(link);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tOption Static Object.\n\t*******************************************************************************************************************/\n\tObject.defineProperty(Wikifier, 'Option', {\n\t\tvalue : (() => {\n\t\t\t// Options array (stack).\n\t\t\tlet _optionsStack = [];\n\n\n\t\t\t/*\n\t\t\t\tGlobalOption Functions.\n\t\t\t*/\n\t\t\tfunction optionLength() {\n\t\t\t\treturn _optionsStack.length;\n\t\t\t}\n\n\t\t\tfunction optionGetter() {\n\t\t\t\treturn Object.assign({}, ..._optionsStack);\n\t\t\t}\n\n\t\t\tfunction optionClear() {\n\t\t\t\t_optionsStack = [];\n\t\t\t}\n\n\t\t\tfunction optionGet(idx) {\n\t\t\t\treturn _optionsStack[idx];\n\t\t\t}\n\n\t\t\tfunction optionPop() {\n\t\t\t\treturn _optionsStack.pop();\n\t\t\t}\n\n\t\t\tfunction optionPush(options) {\n\t\t\t\tif (typeof options !== 'object' || options === null) {\n\t\t\t\t\tthrow new TypeError(`Wikifier.Option.push options parameter must be an object (received: ${Util.getType(options)})`);\n\t\t\t\t}\n\n\t\t\t\treturn _optionsStack.push(options);\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tExports.\n\t\t\t*/\n\t\t\treturn Object.freeze(Object.defineProperties({}, {\n\t\t\t\tlength  : { get : optionLength },\n\t\t\t\toptions : { get : optionGetter },\n\t\t\t\tclear   : { value : optionClear },\n\t\t\t\tget     : { value : optionGet },\n\t\t\t\tpop     : { value : optionPop },\n\t\t\t\tpush    : { value : optionPush }\n\t\t\t}));\n\t\t})()\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tParser Static Object.\n\t*******************************************************************************************************************/\n\tObject.defineProperty(Wikifier, 'Parser', {\n\t\tvalue : (() => {\n\t\t\t// Parser definition array.  Ordering matters, so this must be an ordered list.\n\t\t\tconst _parsers = [];\n\n\t\t\t// Parser profiles object.\n\t\t\tlet _profiles;\n\n\n\t\t\t/*\n\t\t\t\tParser Functions.\n\t\t\t*/\n\t\t\tfunction parsersGetter() {\n\t\t\t\treturn _parsers;\n\t\t\t}\n\n\t\t\tfunction parsersAdd(parser) {\n\t\t\t\t// Parser object sanity checks.\n\t\t\t\tif (typeof parser !== 'object') {\n\t\t\t\t\tthrow new Error('Wikifier.Parser.add parser parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('name')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"name\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.name !== 'string') {\n\t\t\t\t\tthrow new Error('parser object \"name\" property must be a string');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('match')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"match\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.match !== 'string') {\n\t\t\t\t\tthrow new Error('parser object \"match\" property must be a string');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('handler')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"handler\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.handler !== 'function') {\n\t\t\t\t\tthrow new Error('parser object \"handler\" property must be a function');\n\t\t\t\t}\n\n\t\t\t\tif (parser.hasOwnProperty('profiles') && !Array.isArray(parser.profiles)) {\n\t\t\t\t\tthrow new Error('parser object \"profiles\" property must be an array');\n\t\t\t\t}\n\n\t\t\t\t// Check for an existing parser with the same name.\n\t\t\t\tif (parsersHas(parser.name)) {\n\t\t\t\t\tthrow new Error(`cannot clobber existing parser \"${parser.name}\"`);\n\t\t\t\t}\n\n\t\t\t\t// Add the parser to the end of the array.\n\t\t\t\t_parsers.push(parser);\n\t\t\t}\n\n\t\t\tfunction parsersDelete(name) {\n\t\t\t\tconst parser = _parsers.find(parser => parser.name === name);\n\n\t\t\t\tif (parser) {\n\t\t\t\t\t_parsers.delete(parser);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction parsersIsEmpty() {\n\t\t\t\treturn _parsers.length === 0;\n\t\t\t}\n\n\t\t\tfunction parsersHas(name) {\n\t\t\t\treturn !!_parsers.find(parser => parser.name === name);\n\t\t\t}\n\n\t\t\tfunction parsersGet(name) {\n\t\t\t\treturn _parsers.find(parser => parser.name === name) || null;\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tParser Profile Functions.\n\t\t\t*/\n\t\t\tfunction profilesGetter() {\n\t\t\t\treturn _profiles;\n\t\t\t}\n\n\t\t\tfunction profilesCompile() {\n\t\t\t\tif (DEBUG) { console.log('[Wikifier.Parser/profilesCompile()]'); }\n\n\t\t\t\tconst all  = _parsers;\n\t\t\t\tconst core = all.filter(parser => !Array.isArray(parser.profiles) || parser.profiles.includes('core'));\n\n\t\t\t\t_profiles = Object.freeze({\n\t\t\t\t\tall : {\n\t\t\t\t\t\tparsers      : all,\n\t\t\t\t\t\tparserRegExp : new RegExp(all.map(parser => `(${parser.match})`).join('|'), 'gm')\n\t\t\t\t\t},\n\t\t\t\t\tcore : {\n\t\t\t\t\t\tparsers      : core,\n\t\t\t\t\t\tparserRegExp : new RegExp(core.map(parser => `(${parser.match})`).join('|'), 'gm')\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\treturn _profiles;\n\t\t\t}\n\n\t\t\tfunction profilesIsEmpty() {\n\t\t\t\treturn typeof _profiles !== 'object' || Object.keys(_profiles).length === 0;\n\t\t\t}\n\n\t\t\tfunction profilesGet(profile) {\n\t\t\t\tif (typeof _profiles !== 'object' || !_profiles.hasOwnProperty(profile)) {\n\t\t\t\t\tthrow new Error(`nonexistent parser profile \"${profile}\"`);\n\t\t\t\t}\n\n\t\t\t\treturn _profiles[profile];\n\t\t\t}\n\n\t\t\tfunction profilesHas(profile) {\n\t\t\t\treturn typeof _profiles === 'object' && _profiles.hasOwnProperty(profile);\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tExports.\n\t\t\t*/\n\t\t\treturn Object.freeze(Object.defineProperties({}, {\n\t\t\t\t/*\n\t\t\t\t\tParser Containers.\n\t\t\t\t*/\n\t\t\t\tparsers : { get : parsersGetter },\n\n\t\t\t\t/*\n\t\t\t\t\tParser Functions.\n\t\t\t\t*/\n\t\t\t\tadd     : { value : parsersAdd },\n\t\t\t\tdelete  : { value : parsersDelete },\n\t\t\t\tisEmpty : { value : parsersIsEmpty },\n\t\t\t\thas     : { value : parsersHas },\n\t\t\t\tget     : { value : parsersGet },\n\n\t\t\t\t/*\n\t\t\t\t\tParser Profile.\n\t\t\t\t*/\n\t\t\t\tProfile : {\n\t\t\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tProfiles Containers.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tprofiles : { get : profilesGetter },\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tProfiles Functions.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tcompile : { value : profilesCompile },\n\t\t\t\t\t\tisEmpty : { value : profilesIsEmpty },\n\t\t\t\t\t\thas     : { value : profilesHas },\n\t\t\t\t\t\tget     : { value : profilesGet }\n\t\t\t\t\t}))\n\t\t\t\t}\n\t\t\t}));\n\t\t})()\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAdditional Static Properties.\n\t*******************************************************************************************************************/\n\tObject.defineProperties(Wikifier, {\n\t\thelpers : { value : {} },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tgetValue       : { value : State.getVar },              // SEE: `state.js`.\n\t\tsetValue       : { value : State.setVar },              // SEE: `state.js`.\n\t\tparse          : { value : Scripting.parse },           // SEE: `markup/scripting.js`.\n\t\tevalExpression : { value : Scripting.evalTwineScript }, // SEE: `markup/scripting.js`.\n\t\tevalStatements : { value : Scripting.evalTwineScript }, // SEE: `markup/scripting.js`.\n\t\ttextPrimitives : { value : Patterns }                   // SEE: `lib/patterns.js`.\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tHelper Static Methods.\n\t*******************************************************************************************************************/\n\tObject.defineProperties(Wikifier.helpers, {\n\t\tinlineCss : {\n\t\t\tvalue : (() => {\n\t\t\t\tconst lookaheadRe = new RegExp(Patterns.inlineCss, 'gm');\n\t\t\t\tconst idOrClassRe = new RegExp(`(${Patterns.cssIdOrClassSigil})(${Patterns.anyLetter}+)`, 'g');\n\n\t\t\t\tfunction helperInlineCss(w) {\n\t\t\t\t\tconst css = { classes : [], id : '', styles : {} };\n\t\t\t\t\tlet matched;\n\n\t\t\t\t\tdo {\n\t\t\t\t\t\tlookaheadRe.lastIndex = w.nextMatch;\n\n\t\t\t\t\t\tconst match = lookaheadRe.exec(w.source);\n\n\t\t\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\t\t\tif (matched) {\n\t\t\t\t\t\t\tif (match[1]) {\n\t\t\t\t\t\t\t\tcss.styles[Util.fromCssProperty(match[1])] = match[2].trim();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (match[3]) {\n\t\t\t\t\t\t\t\tcss.styles[Util.fromCssProperty(match[3])] = match[4].trim();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (match[5]) {\n\t\t\t\t\t\t\t\tlet subMatch;\n\n\t\t\t\t\t\t\t\tidOrClassRe.lastIndex = 0; // NOTE: Guard against buggy implementations.\n\n\t\t\t\t\t\t\t\twhile ((subMatch = idOrClassRe.exec(match[5])) !== null) {\n\t\t\t\t\t\t\t\t\tif (subMatch[1] === '.') {\n\t\t\t\t\t\t\t\t\t\tcss.classes.push(subMatch[2]);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tcss.id = subMatch[2];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tw.nextMatch = lookaheadRe.lastIndex; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\t\t\t\t\t} while (matched);\n\n\t\t\t\t\treturn css;\n\t\t\t\t}\n\n\t\t\t\treturn helperInlineCss;\n\t\t\t})()\n\t\t},\n\n\t\tevalText : {\n\t\t\tvalue(text) {\n\t\t\t\tlet result;\n\n\t\t\t\ttry {\n\t\t\t\t\tresult = Scripting.evalTwineScript(text);\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAttempt to prevent the leakage of auto-globals by enforcing that\n\t\t\t\t\t\tthe resultant value be either a string or a number.\n\n\t\t\t\t\t\tNOTE: This is not a foolproof solution to the problem of auto-global\n\t\t\t\t\t\tleakage.  Various auto-globals, which return strings or numbers, can\n\t\t\t\t\t\tstill leak through—e.g. `window.status` → string.\n\t\t\t\t\t*/\n\t\t\t\t\tswitch (typeof result) {\n\t\t\t\t\tcase 'string':\n\t\t\t\t\t\tif (result.trim() === '') {\n\t\t\t\t\t\t\tresult = text;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'number':\n\t\t\t\t\t\tresult = String(result);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tresult = text;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\tresult = text;\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}\n\t\t},\n\n\t\tevalPassageId : {\n\t\t\tvalue(passage) {\n\t\t\t\tif (passage == null || Story.has(passage)) { // lazy equality for null; `0` is a valid name, so we cannot simply evaluate `passage`\n\t\t\t\t\treturn passage;\n\t\t\t\t}\n\n\t\t\t\treturn Wikifier.helpers.evalText(passage);\n\t\t\t}\n\t\t},\n\n\t\thasBlockContext : {\n\t\t\tvalue(nodes) {\n\t\t\t\tconst hasGCS = typeof window.getComputedStyle === 'function';\n\n\t\t\t\tfor (let i = nodes.length - 1; i >= 0; --i) {\n\t\t\t\t\tconst node = nodes[i];\n\n\t\t\t\t\tswitch (node.nodeType) {\n\t\t\t\t\tcase Node.ELEMENT_NODE:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst tagName = node.nodeName.toUpperCase();\n\n\t\t\t\t\t\t\tif (tagName === 'BR') {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst styles = hasGCS ? window.getComputedStyle(node, null) : node.currentStyle;\n\n\t\t\t\t\t\t\tif (styles && styles.display) {\n\t\t\t\t\t\t\t\tif (styles.display === 'none') {\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn styles.display === 'block';\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tWebKit/Blink-based browsers do not attach any computed style\n\t\t\t\t\t\t\t\tinformation to elements until they're inserted into the DOM\n\t\t\t\t\t\t\t\t(and probably visible), not even the default browser styles\n\t\t\t\t\t\t\t\tand any user styles.  So, we make an assumption based on the\n\t\t\t\t\t\t\t\telement.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tswitch (tagName) {\n\t\t\t\t\t\t\tcase 'ADDRESS':\n\t\t\t\t\t\t\tcase 'ARTICLE':\n\t\t\t\t\t\t\tcase 'ASIDE':\n\t\t\t\t\t\t\tcase 'BLOCKQUOTE':\n\t\t\t\t\t\t\tcase 'CENTER':\n\t\t\t\t\t\t\tcase 'DIV':\n\t\t\t\t\t\t\tcase 'DL':\n\t\t\t\t\t\t\tcase 'FIGURE':\n\t\t\t\t\t\t\tcase 'FOOTER':\n\t\t\t\t\t\t\tcase 'FORM':\n\t\t\t\t\t\t\tcase 'H1':\n\t\t\t\t\t\t\tcase 'H2':\n\t\t\t\t\t\t\tcase 'H3':\n\t\t\t\t\t\t\tcase 'H4':\n\t\t\t\t\t\t\tcase 'H5':\n\t\t\t\t\t\t\tcase 'H6':\n\t\t\t\t\t\t\tcase 'HEADER':\n\t\t\t\t\t\t\tcase 'HR':\n\t\t\t\t\t\t\tcase 'MAIN':\n\t\t\t\t\t\t\tcase 'NAV':\n\t\t\t\t\t\t\tcase 'OL':\n\t\t\t\t\t\t\tcase 'P':\n\t\t\t\t\t\t\tcase 'PRE':\n\t\t\t\t\t\t\tcase 'SECTION':\n\t\t\t\t\t\t\tcase 'TABLE':\n\t\t\t\t\t\t\tcase 'UL':\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn false;\n\n\t\t\t\t\tcase Node.COMMENT_NODE:\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t},\n\n\t\tcreateShadowSetterCallback : {\n\t\t\tvalue : (() => {\n\t\t\t\tlet macroParser = null;\n\n\t\t\t\tfunction cacheMacroParser() {\n\t\t\t\t\tif (!macroParser) {\n\t\t\t\t\t\tmacroParser = Wikifier.Parser.get('macro');\n\n\t\t\t\t\t\tif (!macroParser) {\n\t\t\t\t\t\t\tthrow new Error('cannot find \"macro\" parser');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn macroParser;\n\t\t\t\t}\n\n\t\t\t\tfunction getMacroContextShadowView() {\n\t\t\t\t\tconst macro = macroParser || cacheMacroParser();\n\t\t\t\t\tconst view  = new Set();\n\n\t\t\t\t\tfor (let context = macro.context; context !== null; context = context.parent) {\n\t\t\t\t\t\tif (context._shadows) {\n\t\t\t\t\t\t\tcontext._shadows.forEach(name => view.add(name));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn [...view];\n\t\t\t\t}\n\n\t\t\t\tfunction helperCreateShadowSetterCallback(code) {\n\t\t\t\t\tconst shadowStore = {};\n\n\t\t\t\t\tgetMacroContextShadowView().forEach(varName => {\n\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\t\t\t\t\t});\n\n\t\t\t\t\treturn function () {\n\t\t\t\t\t\tconst shadowNames = Object.keys(shadowStore);\n\t\t\t\t\t\tconst valueCache  = shadowNames.length > 0 ? {} : null;\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t\t\tevaluation.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tCache the existing values of the variables to be shadowed and assign the\n\t\t\t\t\t\t\t\tshadow values.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tstore[varKey] = shadowStore[varName];\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t// Evaluate the JavaScript.\n\t\t\t\t\t\t\treturn Scripting.evalJavaScript(code);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t// Revert the variable shadowing.\n\t\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tUpdate the shadow store with the variable's current value, in case it\n\t\t\t\t\t\t\t\t\twas modified during the callback.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\n\t\t\t\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn helperCreateShadowSetterCallback;\n\t\t\t})()\n\t\t},\n\n\t\tparseSquareBracketedMarkup : {\n\t\t\tvalue : (() => {\n\t\t\t\t/* eslint-disable no-param-reassign */\n\t\t\t\tconst Item = Lexer.enumFromNames([ // lex item types object (pseudo-enumeration)\n\t\t\t\t\t'Error',     // error\n\t\t\t\t\t'DelimLTR',  // '|' or '->'\n\t\t\t\t\t'DelimRTL',  // '<-'\n\t\t\t\t\t'InnerMeta', // ']['\n\t\t\t\t\t'ImageMeta', // '[img[', '[<img[', or '[>img['\n\t\t\t\t\t'LinkMeta',  // '[['\n\t\t\t\t\t'Link',      // link destination\n\t\t\t\t\t'RightMeta', // ']]'\n\t\t\t\t\t'Setter',    // setter expression\n\t\t\t\t\t'Source',    // image source\n\t\t\t\t\t'Text'       // link text or image alt text\n\t\t\t\t]);\n\t\t\t\tconst Delim = Lexer.enumFromNames([ // delimiter state object (pseudo-enumeration)\n\t\t\t\t\t'None', // no delimiter encountered\n\t\t\t\t\t'LTR',  // '|' or '->'\n\t\t\t\t\t'RTL'   // '<-'\n\t\t\t\t]);\n\n\t\t\t\t// Lexing functions.\n\t\t\t\tfunction slurpQuote(lexer, endQuote) {\n\t\t\t\t\tloop: for (;;) {\n\t\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/* falls through */\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn EOF;\n\n\t\t\t\t\t\tcase endQuote:\n\t\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t\t}\n\n\t\t\t\t\treturn lexer.pos;\n\t\t\t\t}\n\n\t\t\t\tfunction lexLeftMeta(lexer) {\n\t\t\t\t\tif (!lexer.accept('[')) {\n\t\t\t\t\t\treturn lexer.error(Item.Error, 'malformed square-bracketed markup');\n\t\t\t\t\t}\n\n\t\t\t\t\t// Is link markup.\n\t\t\t\t\tif (lexer.accept('[')) {\n\t\t\t\t\t\tlexer.data.isLink = true;\n\t\t\t\t\t\tlexer.emit(Item.LinkMeta);\n\t\t\t\t\t}\n\n\t\t\t\t\t// May be image markup.\n\t\t\t\t\telse {\n\t\t\t\t\t\tlexer.accept('<>'); // aligner syntax\n\n\t\t\t\t\t\tif (!lexer.accept('Ii') || !lexer.accept('Mm') || !lexer.accept('Gg') || !lexer.accept('[')) {\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, 'malformed square-bracketed markup');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlexer.data.isLink = false;\n\t\t\t\t\t\tlexer.emit(Item.ImageMeta);\n\t\t\t\t\t}\n\n\t\t\t\t\tlexer.depth = 2; // account for both initial left square brackets\n\t\t\t\t\treturn lexCoreComponents;\n\t\t\t\t}\n\n\t\t\t\tfunction lexCoreComponents(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\t\t\t\t\tlet delim = Delim.None;\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tThis is not entirely reliable within sections that allow raw strings, since\n\t\t\t\t\t\t\t\tit's possible, however unlikely, for a raw string to contain unpaired double\n\t\t\t\t\t\t\t\tquotes.  The likelihood is low enough, however, that I'm deeming the risk as\n\t\t\t\t\t\t\t\tacceptable—for now, at least.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '|': // possible pipe ('|') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None) {\n\t\t\t\t\t\t\t\tdelim = Delim.LTR;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\tlexer.forward();\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimLTR);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '-': // possible right arrow ('->') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None && lexer.peek() === '>') {\n\t\t\t\t\t\t\t\tdelim = Delim.LTR;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimLTR);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '<': // possible left arrow ('<-') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None && lexer.peek() === '-') {\n\t\t\t\t\t\t\t\tdelim = Delim.RTL;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimRTL);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tswitch (lexer.peek()) {\n\t\t\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\n\t\t\t\t\t\t\t\t\tif (delim === Delim.RTL) {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.InnerMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn lexer.data.isLink ? lexSetter : lexImageLink;\n\n\t\t\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\n\t\t\t\t\t\t\t\t\tif (delim === Delim.RTL) {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfunction lexImageLink(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tThis is not entirely reliable within sections that allow raw strings, since\n\t\t\t\t\t\t\t\tit's possible, however unlikely, for a raw string to contain unpaired double\n\t\t\t\t\t\t\t\tquotes.  The likelihood is low enough, however, that I'm deeming the risk as\n\t\t\t\t\t\t\t\tacceptable—for now, at least.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup link component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tswitch (lexer.peek()) {\n\t\t\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.Link);\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.InnerMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn lexSetter;\n\n\t\t\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.Link);\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfunction lexSetter(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup setter component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase \"'\":\n\t\t\t\t\t\t\tif (slurpQuote(lexer, \"'\") === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated single quoted string in ${what} markup setter component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tif (lexer.peek() !== ']') {\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Setter);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Parse function.\n\t\t\t\tfunction parseSquareBracketedMarkup(w) {\n\t\t\t\t\t// Initialize the lexer.\n\t\t\t\t\tconst lexer  = new Lexer(w.source, lexLeftMeta);\n\n\t\t\t\t\t// Set the initial positions within the source string.\n\t\t\t\t\tlexer.start = lexer.pos = w.matchStart;\n\n\t\t\t\t\t// Lex the raw argument string.\n\t\t\t\t\tconst markup = {};\n\t\t\t\t\tconst items  = lexer.run();\n\t\t\t\t\tconst last   = items.last();\n\n\t\t\t\t\tif (last && last.type === Item.Error) {\n\t\t\t\t\t\tmarkup.error = last.message;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\titems.forEach(item => {\n\t\t\t\t\t\t\tconst text = item.text.trim();\n\n\t\t\t\t\t\t\tswitch (item.type) {\n\t\t\t\t\t\t\tcase Item.ImageMeta:\n\t\t\t\t\t\t\t\tmarkup.isImage = true;\n\n\t\t\t\t\t\t\t\tif (text[1] === '<') {\n\t\t\t\t\t\t\t\t\tmarkup.align = 'left';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (text[1] === '>') {\n\t\t\t\t\t\t\t\t\tmarkup.align = 'right';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.LinkMeta:\n\t\t\t\t\t\t\t\tmarkup.isLink = true;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Link:\n\t\t\t\t\t\t\t\tif (text[0] === '~') {\n\t\t\t\t\t\t\t\t\tmarkup.forceInternal = true;\n\t\t\t\t\t\t\t\t\tmarkup.link = text.slice(1);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tmarkup.link = text;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Setter:\n\t\t\t\t\t\t\t\tmarkup.setter = text;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Source:\n\t\t\t\t\t\t\t\tmarkup.source = text;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Text:\n\t\t\t\t\t\t\t\tmarkup.text = text;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tmarkup.pos = lexer.pos;\n\t\t\t\t\treturn markup;\n\t\t\t\t}\n\n\t\t\t\treturn parseSquareBracketedMarkup;\n\t\t\t\t/* eslint-enable no-param-reassign */\n\t\t\t})()\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Wikifier;\n})();\n/* eslint-enable max-len */\n\n/***********************************************************************************************************************\n\n\tmarkup/parserlib.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, DebugView, EOF, Engine, Lexer, Macro, MacroContext, Patterns, Scripting, State, Story, Template,\n\t       Wikifier, toStringOrDefault, throwError\n*/\n/* eslint \"no-param-reassign\": [ 2, { \"props\" : false } ] */\n\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _verbatimTagHandler(w) {\n\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\tconst match = this.lookahead.exec(w.source);\n\n\t\tif (match && match.index === w.matchStart) {\n\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t.append(match[1])\n\t\t\t\t.appendTo(w.output);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tParsers.\n\t*******************************************************************************************************************/\n\tWikifier.Parser.add({\n\t\tname       : 'quoteByBlock',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^<<<\\\\n',\n\t\tterminator : '^<<<\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.subWikify(\n\t\t\t\tjQuery(document.createElement('blockquote'))\n\t\t\t\t\t.appendTo(w.output)\n\t\t\t\t\t.get(0),\n\t\t\t\tthis.terminator\n\t\t\t);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'quoteByLine',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^>+',\n\t\tlookahead  : /^>+/gm,\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst destStack = [w.output];\n\t\t\tlet curLevel = 0;\n\t\t\tlet newLevel = w.matchLength;\n\t\t\tlet matched;\n\t\t\tlet i;\n\n\t\t\tdo {\n\t\t\t\tif (newLevel > curLevel) {\n\t\t\t\t\tfor (i = curLevel; i < newLevel; ++i) {\n\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\tjQuery(document.createElement('blockquote'))\n\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (newLevel < curLevel) {\n\t\t\t\t\tfor (i = curLevel; i > newLevel; --i) {\n\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcurLevel = newLevel;\n\t\t\t\tw.subWikify(destStack[destStack.length - 1], this.terminator);\n\t\t\t\tjQuery(document.createElement('br')).appendTo(destStack[destStack.length - 1]);\n\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tnewLevel = match[0].length;\n\t\t\t\t\tw.nextMatch += match[0].length;\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'macro',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<<',\n\t\tlookahead : new RegExp(`<<(/?${Patterns.macroName})(?:\\\\s*)((?:(?:\\`(?:\\\\\\\\.|[^\\`\\\\\\\\])*\\`)|(?:\"(?:\\\\\\\\.|[^\"\\\\\\\\])*\")|(?:'(?:\\\\\\\\.|[^'\\\\\\\\])*')|(?:\\\\[(?:[<>]?[Ii][Mm][Gg])?\\\\[[^\\\\r\\\\n]*?\\\\]\\\\]+)|[^>]|(?:>(?!>)))*)>>`, 'gm'),\n\t\tworking   : { source : '', name : '', arguments : '', index : 0 }, // the working parse object\n\t\tcontext   : null, // last execution context object (top-level macros, hierarchically, have a null context)\n\n\t\thandler(w) {\n\t\t\tconst matchStart = this.lookahead.lastIndex = w.matchStart;\n\n\t\t\tif (this.parseTag(w)) {\n\t\t\t\t/*\n\t\t\t\t\tIf `parseBody()` is called below, it will modify the current working\n\t\t\t\t\tvalues, so we must cache them now.\n\t\t\t\t*/\n\t\t\t\tconst nextMatch = w.nextMatch;\n\t\t\t\tconst name      = this.working.name;\n\t\t\t\tconst rawArgs   = this.working.arguments;\n\t\t\t\tlet macro;\n\n\t\t\t\ttry {\n\t\t\t\t\tmacro = Macro.get(name);\n\n\t\t\t\t\tif (macro) {\n\t\t\t\t\t\tlet payload = null;\n\n\t\t\t\t\t\tif (macro.hasOwnProperty('tags')) {\n\t\t\t\t\t\t\tpayload = this.parseBody(w, macro);\n\n\t\t\t\t\t\t\tif (!payload) {\n\t\t\t\t\t\t\t\tw.nextMatch = nextMatch; // we must reset `w.nextMatch` here, as `parseBody()` modifies it\n\t\t\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t\t`cannot find a closing tag for macro <<${name}>>`,\n\t\t\t\t\t\t\t\t\t`${w.source.slice(matchStart, w.nextMatch)}\\u2026`\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (typeof macro.handler === 'function') {\n\t\t\t\t\t\t\tconst args = !payload\n\t\t\t\t\t\t\t\t? this.createArgs(rawArgs, this.skipArgs(macro, macro.name))\n\t\t\t\t\t\t\t\t: payload[0].args;\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tNew-style macros.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (macro.hasOwnProperty('_MACRO_API')) {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tAdd the macro's execution context to the context chain.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tthis.context = new MacroContext({\n\t\t\t\t\t\t\t\t\tmacro,\n\t\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\t\targs,\n\t\t\t\t\t\t\t\t\tpayload,\n\t\t\t\t\t\t\t\t\tsource : w.source.slice(matchStart, w.nextMatch),\n\t\t\t\t\t\t\t\t\tparent : this.context,\n\t\t\t\t\t\t\t\t\tparser : w\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tCall the handler.\n\n\t\t\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\t\t\t\t\t\tto ensure that the execution context is properly restored in the event\n\t\t\t\t\t\t\t\t\tthat an uncaught exception is thrown during the handler call.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tmacro.handler.call(this.context);\n\t\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\t\tQUESTION: Swap to the following, which passes macro arguments in\n\t\t\t\t\t\t\t\t\t\tas parameters to the handler function, in addition to them being\n\t\t\t\t\t\t\t\t\t\tavailable on its `this`?  If so, it might still be something to\n\t\t\t\t\t\t\t\t\t\thold off on until v3, when the legacy macro API is removed.\n\n\t\t\t\t\t\t\t\t\t\tmacro.handler.apply(this.context, this.context.args);\n\t\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t\tthis.context = this.context.parent;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t[DEPRECATED] Old-style/legacy macros.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tSet up the raw arguments string.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tconst prevRawArgs = w._rawArgs;\n\t\t\t\t\t\t\t\tw._rawArgs = rawArgs;\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tCall the handler.\n\n\t\t\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\t\t\t\t\t\tto ensure that the previous raw arguments string is properly restored in\n\t\t\t\t\t\t\t\t\tthe event that an uncaught exception is thrown during the handler call.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tmacro.handler(w.output, name, args, w, payload);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t\tw._rawArgs = prevRawArgs;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t`macro <<${name}>> handler function ${macro.hasOwnProperty('handler') ? 'is not a function' : 'does not exist'}`,\n\t\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (Macro.tags.has(name)) {\n\t\t\t\t\t\tconst tags = Macro.tags.get(name);\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`child tag <<${name}>> was found outside of a call to its parent macro${tags.length === 1 ? '' : 's'} <<${tags.join('>>, <<')}>>`,\n\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`macro <<${name}>> does not exist`,\n\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot execute ${macro && macro.isWidget ? 'widget' : 'macro'} <<${name}>>: ${ex.message}`,\n\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\tthis.working.source    = '';\n\t\t\t\t\tthis.working.name      = '';\n\t\t\t\t\tthis.working.arguments = '';\n\t\t\t\t\tthis.working.index     = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t}\n\t\t},\n\n\t\tparseTag(w) {\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart && match[1]) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tthis.working.source    = w.source.slice(match.index, this.lookahead.lastIndex);\n\t\t\t\tthis.working.name      = match[1];\n\t\t\t\tthis.working.arguments = match[2];\n\t\t\t\tthis.working.index     = match.index;\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t},\n\n\t\tparseBody(w, macro) {\n\t\t\tconst openTag  = this.working.name;\n\t\t\tconst closeTag = `/${openTag}`;\n\t\t\tconst closeAlt = `end${openTag}`;\n\t\t\tconst bodyTags = Array.isArray(macro.tags) ? macro.tags : false;\n\t\t\tconst payload  = [];\n\t\t\tlet end          = -1;\n\t\t\tlet opened       = 1;\n\t\t\tlet curSource    = this.working.source;\n\t\t\tlet curTag       = this.working.name;\n\t\t\tlet curArgument  = this.working.arguments;\n\t\t\tlet contentStart = w.nextMatch;\n\n\t\t\twhile ((w.matchStart = w.source.indexOf(this.match, w.nextMatch)) !== -1) {\n\t\t\t\tif (!this.parseTag(w)) {\n\t\t\t\t\tthis.lookahead.lastIndex = w.nextMatch = w.matchStart + this.match.length;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst tagSource = this.working.source;\n\t\t\t\tconst tagName   = this.working.name;\n\t\t\t\tconst tagArgs   = this.working.arguments;\n\t\t\t\tconst tagBegin  = this.working.index;\n\t\t\t\tconst tagEnd    = w.nextMatch;\n\n\t\t\t\tswitch (tagName) {\n\t\t\t\tcase openTag:\n\t\t\t\t\t++opened;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase closeAlt:\n\t\t\t\tcase closeTag:\n\t\t\t\t\t--opened;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tif (opened === 1 && bodyTags) {\n\t\t\t\t\t\tfor (let i = 0, iend = bodyTags.length; i < iend; ++i) {\n\t\t\t\t\t\t\tif (tagName === bodyTags[i]) {\n\t\t\t\t\t\t\t\tpayload.push({\n\t\t\t\t\t\t\t\t\tsource    : curSource,\n\t\t\t\t\t\t\t\t\tname      : curTag,\n\t\t\t\t\t\t\t\t\targuments : curArgument,\n\t\t\t\t\t\t\t\t\targs      : this.createArgs(curArgument, this.skipArgs(macro, curTag)),\n\t\t\t\t\t\t\t\t\tcontents  : w.source.slice(contentStart, tagBegin)\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tcurSource    = tagSource;\n\t\t\t\t\t\t\t\tcurTag       = tagName;\n\t\t\t\t\t\t\t\tcurArgument  = tagArgs;\n\t\t\t\t\t\t\t\tcontentStart = tagEnd;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (opened === 0) {\n\t\t\t\t\tpayload.push({\n\t\t\t\t\t\tsource    : curSource,\n\t\t\t\t\t\tname      : curTag,\n\t\t\t\t\t\targuments : curArgument,\n\t\t\t\t\t\targs      : this.createArgs(curArgument, this.skipArgs(macro, curTag)),\n\t\t\t\t\t\tcontents  : w.source.slice(contentStart, tagBegin)\n\t\t\t\t\t});\n\t\t\t\t\tend = tagEnd;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (end !== -1) {\n\t\t\t\tw.nextMatch = end;\n\t\t\t\treturn payload;\n\t\t\t}\n\n\t\t\treturn null;\n\t\t},\n\n\t\tcreateArgs(rawArgsString, skipArgs) {\n\t\t\tconst args = skipArgs ? [] : this.parseArgs(rawArgsString);\n\n\t\t\t// Extend the args array with the raw and full argument strings.\n\t\t\tObject.defineProperties(args, {\n\t\t\t\traw : {\n\t\t\t\t\tvalue : rawArgsString\n\t\t\t\t},\n\t\t\t\tfull : {\n\t\t\t\t\tvalue : Scripting.parse(rawArgsString)\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn args;\n\t\t},\n\n\t\tskipArgs(macro, tagName) {\n\t\t\tif (macro.hasOwnProperty('skipArgs')) {\n\t\t\t\tconst sa = macro.skipArgs;\n\n\t\t\t\treturn typeof sa === 'boolean' && sa || Array.isArray(sa) && sa.includes(tagName);\n\t\t\t}\n\t\t\t/* legacy */\n\t\t\telse if (macro.hasOwnProperty('skipArg0')) {\n\t\t\t\treturn macro.skipArg0 && macro.name === tagName;\n\t\t\t}\n\t\t\t/* /legacy */\n\n\t\t\treturn false;\n\t\t},\n\n\t\tparseArgs : (() => {\n\t\t\tconst Item = Lexer.enumFromNames([ // lex item types object (pseudo-enumeration)\n\t\t\t\t'Error',        // error\n\t\t\t\t'Bareword',     // bare identifier\n\t\t\t\t'Expression',   // expression (backquoted)\n\t\t\t\t'String',       // quoted string (single or double)\n\t\t\t\t'SquareBracket' // [[…]] or [img[…]]\n\t\t\t]);\n\t\t\tconst spaceRe    = new RegExp(Patterns.space);\n\t\t\tconst notSpaceRe = new RegExp(Patterns.notSpace);\n\t\t\tconst varTest    = new RegExp(`^${Patterns.variable}`);\n\n\t\t\t// Lexing functions.\n\t\t\tfunction slurpQuote(lexer, endQuote) {\n\t\t\t\tloop: for (;;) {\n\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* falls through */\n\t\t\t\t\tcase EOF:\n\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\treturn EOF;\n\n\t\t\t\t\tcase endQuote:\n\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t}\n\n\t\t\t\treturn lexer.pos;\n\t\t\t}\n\n\t\t\tfunction lexSpace(lexer) {\n\t\t\t\tconst offset = lexer.source.slice(lexer.pos).search(notSpaceRe);\n\n\t\t\t\tif (offset === EOF) {\n\t\t\t\t\t// no non-whitespace characters, so bail\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\telse if (offset !== 0) {\n\t\t\t\t\tlexer.pos += offset;\n\t\t\t\t\tlexer.ignore();\n\t\t\t\t}\n\n\t\t\t\t// determine what the next state is\n\t\t\t\tswitch (lexer.next()) {\n\t\t\t\tcase '`':\n\t\t\t\t\treturn lexExpression;\n\t\t\t\tcase '\"':\n\t\t\t\t\treturn lexDoubleQuote;\n\t\t\t\tcase \"'\":\n\t\t\t\t\treturn lexSingleQuote;\n\t\t\t\tcase '[':\n\t\t\t\t\treturn lexSquareBracket;\n\t\t\t\tdefault:\n\t\t\t\t\treturn lexBareword;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction lexExpression(lexer) {\n\t\t\t\tif (slurpQuote(lexer, '`') === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated backquote expression');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.Expression);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexDoubleQuote(lexer) {\n\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated double quoted string');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.String);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexSingleQuote(lexer) {\n\t\t\t\tif (slurpQuote(lexer, \"'\") === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated single quoted string');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.String);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexSquareBracket(lexer) {\n\t\t\t\tconst imgMeta = '<>IiMmGg';\n\t\t\t\tlet what;\n\n\t\t\t\tif (lexer.accept(imgMeta)) {\n\t\t\t\t\twhat = 'image';\n\t\t\t\t\tlexer.acceptRun(imgMeta);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\twhat = 'link';\n\t\t\t\t}\n\n\t\t\t\tif (!lexer.accept('[')) {\n\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t}\n\n\t\t\t\tlexer.depth = 2; // account for both initial left square brackets\n\n\t\t\t\tloop: for (;;) {\n\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* falls through */\n\t\t\t\t\tcase EOF:\n\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\tcase '[':\n\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase ']':\n\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\tif (lexer.depth < 0) {\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, \"unexpected right square bracket ']'\");\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\tif (lexer.next() === ']') {\n\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.SquareBracket);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexBareword(lexer) {\n\t\t\t\tconst offset = lexer.source.slice(lexer.pos).search(spaceRe);\n\t\t\t\tlexer.pos = offset === EOF ? lexer.source.length : lexer.pos + offset;\n\t\t\t\tlexer.emit(Item.Bareword);\n\t\t\t\treturn offset === EOF ? null : lexSpace;\n\t\t\t}\n\n\t\t\t// Parse function.\n\t\t\tfunction parseMacroArgs(rawArgsString) {\n\t\t\t\t// Initialize the lexer.\n\t\t\t\tconst lexer = new Lexer(rawArgsString, lexSpace);\n\t\t\t\tconst args  = [];\n\n\t\t\t\t// Lex the raw argument string.\n\t\t\t\tlexer.run().forEach(item => {\n\t\t\t\t\tlet arg = item.text;\n\n\t\t\t\t\tswitch (item.type) {\n\t\t\t\t\tcase Item.Error:\n\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${item.message}`);\n\n\t\t\t\t\tcase Item.Bareword:\n\t\t\t\t\t\t// A variable, so substitute its value.\n\t\t\t\t\t\tif (varTest.test(arg)) {\n\t\t\t\t\t\t\targ = State.getVar(arg);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Property access on the settings or setup objects, so try to evaluate it.\n\t\t\t\t\t\telse if (/^(?:settings|setup)[.[]/.test(arg)) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\targ = Scripting.evalTwineScript(arg);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Null literal, so convert it into null.\n\t\t\t\t\t\telse if (arg === 'null') {\n\t\t\t\t\t\t\targ = null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Undefined literal, so convert it into undefined.\n\t\t\t\t\t\telse if (arg === 'undefined') {\n\t\t\t\t\t\t\targ = undefined;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Boolean true literal, so convert it into true.\n\t\t\t\t\t\telse if (arg === 'true') {\n\t\t\t\t\t\t\targ = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Boolean false literal, so convert it into false.\n\t\t\t\t\t\telse if (arg === 'false') {\n\t\t\t\t\t\t\targ = false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// NaN literal, so convert it into NaN.\n\t\t\t\t\t\telse if (arg === 'NaN') {\n\t\t\t\t\t\t\targ = NaN;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Attempt to convert it into a number, in case it's a numeric literal.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst argAsNum = Number(arg);\n\n\t\t\t\t\t\t\tif (!Number.isNaN(argAsNum)) {\n\t\t\t\t\t\t\t\targ = argAsNum;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.Expression:\n\t\t\t\t\t\targ = arg.slice(1, -1).trim(); // remove the backquotes and trim the expression\n\n\t\t\t\t\t\t// Empty backquotes.\n\t\t\t\t\t\tif (arg === '') {\n\t\t\t\t\t\t\targ = undefined;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Evaluate the expression.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tThe enclosing parenthesis here are necessary to force a code string\n\t\t\t\t\t\t\t\t\tconsisting solely of an object literal to be evaluated as such, rather\n\t\t\t\t\t\t\t\t\tthan as a code block.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\targ = Scripting.evalTwineScript(`(${arg})`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument expression \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.String:\n\t\t\t\t\t\t// Evaluate the string to handle escaped characters.\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\targ = Scripting.evalJavaScript(arg);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument string \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.SquareBracket:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\t\t\tsource     : arg,\n\t\t\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${markup.error}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (markup.pos < arg.length) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": unexpected character(s) \"${arg.slice(markup.pos)}\" (pos: ${markup.pos})`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert to a link or image object.\n\t\t\t\t\t\t\tif (markup.isLink) {\n\t\t\t\t\t\t\t\t// .isLink, [.text], [.forceInternal], .link, [.setter]\n\t\t\t\t\t\t\t\targ = { isLink : true };\n\t\t\t\t\t\t\t\targ.count    = markup.hasOwnProperty('text') ? 2 : 1;\n\t\t\t\t\t\t\t\targ.link     = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\t\t\t\t\t\targ.text     = markup.hasOwnProperty('text') ? Wikifier.helpers.evalText(markup.text) : arg.link;\n\t\t\t\t\t\t\t\targ.external = !markup.forceInternal && Wikifier.isExternalLink(arg.link);\n\t\t\t\t\t\t\t\targ.setFn    = markup.hasOwnProperty('setter')\n\t\t\t\t\t\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (markup.isImage) {\n\t\t\t\t\t\t\t\t// .isImage, [.align], [.title], .source, [.forceInternal], [.link], [.setter]\n\t\t\t\t\t\t\t\targ = (source => {\n\t\t\t\t\t\t\t\t\tconst imgObj = {\n\t\t\t\t\t\t\t\t\t\tsource,\n\t\t\t\t\t\t\t\t\t\tisImage : true\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t\t// Check for Twine 1.4 Base64 image passage transclusion.\n\t\t\t\t\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t\t\t\t\timgObj.source  = passage.text;\n\t\t\t\t\t\t\t\t\t\t\timgObj.passage = passage.title;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturn imgObj;\n\t\t\t\t\t\t\t\t})(Wikifier.helpers.evalPassageId(markup.source));\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('align')) {\n\t\t\t\t\t\t\t\t\targ.align = markup.align;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('text')) {\n\t\t\t\t\t\t\t\t\targ.title = Wikifier.helpers.evalText(markup.text);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('link')) {\n\t\t\t\t\t\t\t\t\targ.link     = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\t\t\t\t\t\t\targ.external = !markup.forceInternal && Wikifier.isExternalLink(arg.link);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\targ.setFn = markup.hasOwnProperty('setter')\n\t\t\t\t\t\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\targs.push(arg);\n\t\t\t\t});\n\n\t\t\t\treturn args;\n\t\t\t}\n\n\t\t\treturn parseMacroArgs;\n\t\t})()\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'link',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\[\\\\[[^[]',\n\n\t\thandler(w) {\n\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup(w);\n\n\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = markup.pos;\n\n\t\t\t// text=(text), forceInternal=(~), link=link, setter=(setter)\n\t\t\tconst link  = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\tconst text  = markup.hasOwnProperty('text') ? Wikifier.helpers.evalText(markup.text) : link;\n\t\t\tconst setFn = markup.hasOwnProperty('setter')\n\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t: null;\n\n\t\t\t// Debug view setup.\n\t\t\tconst output = (Config.debug\n\t\t\t\t? new DebugView(w.output, 'link-markup', '[[link]]', w.source.slice(w.matchStart, w.nextMatch))\n\t\t\t\t: w\n\t\t\t).output;\n\n\t\t\tif (markup.forceInternal || !Wikifier.isExternalLink(link)) {\n\t\t\t\tWikifier.createInternalLink(output, link, text, setFn);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tWikifier.createExternalLink(output, link, text);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'urlLink',\n\t\tprofiles : ['core'],\n\t\tmatch    : Patterns.url,\n\n\t\thandler(w) {\n\t\t\tw.outputText(Wikifier.createExternalLink(w.output, w.matchText), w.matchStart, w.nextMatch);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'image',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\[[<>]?[Ii][Mm][Gg]\\\\[',\n\n\t\thandler(w) {\n\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup(w);\n\n\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = markup.pos;\n\n\t\t\t// Debug view setup.\n\t\t\tlet debugView;\n\n\t\t\tif (Config.debug) {\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tw.output,\n\t\t\t\t\t'image-markup',\n\t\t\t\t\tmarkup.hasOwnProperty('link') ? '[img[][link]]' : '[img[]]',\n\t\t\t\t\tw.source.slice(w.matchStart, w.nextMatch)\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ block : true });\n\t\t\t}\n\n\t\t\t// align=(left|right), title=(title), source=source, forceInternal=(~), link=(link), setter=(setter)\n\t\t\tconst setFn = markup.hasOwnProperty('setter')\n\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t: null;\n\t\t\tlet el     = (Config.debug ? debugView : w).output;\n\t\t\tlet source;\n\n\t\t\tif (markup.hasOwnProperty('link')) {\n\t\t\t\tconst link = Wikifier.helpers.evalPassageId(markup.link);\n\n\t\t\t\tif (markup.forceInternal || !Wikifier.isExternalLink(link)) {\n\t\t\t\t\tel = Wikifier.createInternalLink(el, link, null, setFn);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tel = Wikifier.createExternalLink(el, link);\n\t\t\t\t}\n\n\t\t\t\tel.classList.add('link-image');\n\t\t\t}\n\n\t\t\tel = jQuery(document.createElement('img'))\n\t\t\t\t.appendTo(el)\n\t\t\t\t.get(0);\n\t\t\tsource = Wikifier.helpers.evalPassageId(markup.source);\n\n\t\t\t// Check for image passage transclusion.\n\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\tel.setAttribute('data-passage', passage.title);\n\t\t\t\t\tsource = passage.text.trim();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tel.src = source;\n\n\t\t\tif (markup.hasOwnProperty('text')) {\n\t\t\t\tel.title = Wikifier.helpers.evalText(markup.text);\n\t\t\t}\n\n\t\t\tif (markup.hasOwnProperty('align')) {\n\t\t\t\tel.align = markup.align;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'monospacedByBlock',\n\t\tprofiles  : ['block'],\n\t\tmatch     : '^\\\\{\\\\{\\\\{\\\\n',\n\t\tlookahead : /^\\{\\{\\{\\n((?:^[^\\n]*\\n)+?)(^\\}\\}\\}$\\n?)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tconst pre = jQuery(document.createElement('pre'));\n\t\t\t\tjQuery(document.createElement('code'))\n\t\t\t\t\t.text(match[1])\n\t\t\t\t\t.appendTo(pre);\n\t\t\t\tpre.appendTo(w.output);\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'formatByChar',\n\t\tprofiles : ['core'],\n\t\tmatch    : \"''|//|__|\\\\^\\\\^|~~|==|\\\\{\\\\{\\\\{\",\n\n\t\thandler(w) {\n\t\t\tswitch (w.matchText) {\n\t\t\tcase \"''\":\n\t\t\t\tw.subWikify(jQuery(document.createElement('strong')).appendTo(w.output).get(0), \"''\");\n\t\t\t\tbreak;\n\n\t\t\tcase '//':\n\t\t\t\tw.subWikify(jQuery(document.createElement('em')).appendTo(w.output).get(0), '//');\n\t\t\t\tbreak;\n\n\t\t\tcase '__':\n\t\t\t\tw.subWikify(jQuery(document.createElement('u')).appendTo(w.output).get(0), '__');\n\t\t\t\tbreak;\n\n\t\t\tcase '^^':\n\t\t\t\tw.subWikify(jQuery(document.createElement('sup')).appendTo(w.output).get(0), '\\\\^\\\\^');\n\t\t\t\tbreak;\n\n\t\t\tcase '~~':\n\t\t\t\tw.subWikify(jQuery(document.createElement('sub')).appendTo(w.output).get(0), '~~');\n\t\t\t\tbreak;\n\n\t\t\tcase '==':\n\t\t\t\tw.subWikify(jQuery(document.createElement('s')).appendTo(w.output).get(0), '==');\n\t\t\t\tbreak;\n\n\t\t\tcase '{{{':\n\t\t\t\t{\n\t\t\t\t\tconst lookahead = /\\{\\{\\{((?:.|\\n)*?)\\}\\}\\}/gm;\n\n\t\t\t\t\tlookahead.lastIndex = w.matchStart;\n\n\t\t\t\t\tconst match = lookahead.exec(w.source);\n\n\t\t\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\t\t\tjQuery(document.createElement('code'))\n\t\t\t\t\t\t\t.text(match[1])\n\t\t\t\t\t\t\t.appendTo(w.output);\n\t\t\t\t\t\tw.nextMatch = lookahead.lastIndex;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'customStyle',\n\t\tprofiles   : ['core'],\n\t\tmatch      : '@@',\n\t\tterminator : '@@',\n\t\tblockRe    : /\\s*\\n/gm,\n\n\t\thandler(w) {\n\t\t\tconst css = Wikifier.helpers.inlineCss(w);\n\n\t\t\tthis.blockRe.lastIndex = w.nextMatch; // must follow the call to `inlineCss()`\n\n\t\t\tconst blockMatch = this.blockRe.exec(w.source);\n\t\t\tconst blockLevel = blockMatch && blockMatch.index === w.nextMatch;\n\t\t\tconst $el        = jQuery(document.createElement(blockLevel ? 'div' : 'span'))\n\t\t\t\t.appendTo(w.output);\n\n\t\t\tif (css.classes.length === 0 && css.id === '' && Object.keys(css.styles).length === 0) {\n\t\t\t\t$el.addClass('marked');\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcss.classes.forEach(className => $el.addClass(className));\n\n\t\t\t\tif (css.id !== '') {\n\t\t\t\t\t$el.attr('id', css.id);\n\t\t\t\t}\n\n\t\t\t\t$el.css(css.styles);\n\t\t\t}\n\n\t\t\tif (blockLevel) {\n\t\t\t\t// Skip the leading and, if it exists, trailing newlines.\n\t\t\t\tw.nextMatch += blockMatch[0].length;\n\t\t\t\tw.subWikify($el[0], `\\\\n?${this.terminator}`);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tw.subWikify($el[0], this.terminator);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimText',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '\"{3}|<[Nn][Oo][Ww][Ii][Kk][Ii]>',\n\t\tlookahead : /(?:\"{3}((?:.|\\n)*?)\"{3})|(?:<[Nn][Oo][Ww][Ii][Kk][Ii]>((?:.|\\n)*?)<\\/[Nn][Oo][Ww][Ii][Kk][Ii]>)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tjQuery(document.createElement('span'))\n\t\t\t\t\t.addClass('verbatim')\n\t\t\t\t\t.text(match[1] || match[2])\n\t\t\t\t\t.appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'horizontalRule',\n\t\tprofiles : ['core'],\n\t\tmatch    : '^----+$\\\\n?|<[Hh][Rr]\\\\s*/?>\\\\n?',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createElement('hr')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'emdash',\n\t\tprofiles : ['core'],\n\t\tmatch    : '--',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createTextNode('\\u2014')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'doubleDollarSign',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\${2}', // eslint-disable-line no-template-curly-in-string\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createTextNode('$')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\t/*\n\t\t\tSupported syntax:\n\t\t\t\t$variable\n\t\t\t\t$variable.property\n\t\t\t\t$variable[numericIndex]\n\t\t\t\t$variable[\"property\"]\n\t\t\t\t$variable['property']\n\t\t\t\t$variable[$indexOrPropertyVariable]\n\t\t*/\n\t\tname     : 'nakedVariable',\n\t\tprofiles : ['core'],\n\t\tmatch    : `${Patterns.variable}(?:(?:\\\\.${Patterns.identifier})|(?:\\\\[\\\\d+\\\\])|(?:\\\\[\"(?:\\\\\\\\.|[^\"\\\\\\\\])+\"\\\\])|(?:\\\\['(?:\\\\\\\\.|[^'\\\\\\\\])+'\\\\])|(?:\\\\[${Patterns.variable}\\\\]))*`,\n\n\t\thandler(w) {\n\t\t\tconst result = toStringOrDefault(State.getVar(w.matchText), null);\n\n\t\t\tif (result === null) {\n\t\t\t\tjQuery(document.createTextNode(w.matchText)).appendTo(w.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnew Wikifier(\n\t\t\t\t\t(Config.debug\n\t\t\t\t\t\t? new DebugView(w.output, 'variable', w.matchText, w.matchText) // Debug view setup.\n\t\t\t\t\t\t: w\n\t\t\t\t\t).output,\n\t\t\t\t\tresult\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'template',\n\t\tprofiles : ['core'],\n\t\tmatch    : `\\\\?${Patterns.templateName}`,\n\n\t\thandler(w) {\n\t\t\tconst name = w.matchText.slice(1);\n\t\t\tlet template = Template.get(name);\n\t\t\tlet result   = null;\n\n\t\t\t// If we have an array of templates, randomly choose one.\n\t\t\tif (template instanceof Array) {\n\t\t\t\ttemplate = template.random();\n\t\t\t}\n\n\t\t\tswitch (typeof template) {\n\t\t\tcase 'function':\n\t\t\t\ttry {\n\t\t\t\t\tresult = toStringOrDefault(template.call({ name }), null);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot execute function template ?${name}: ${ex.message}`,\n\t\t\t\t\t\tw.source.slice(w.matchStart, w.nextMatch)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'string':\n\t\t\t\tresult = template;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (result === null) {\n\t\t\t\tjQuery(document.createTextNode(w.matchText)).appendTo(w.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnew Wikifier(\n\t\t\t\t\t(Config.debug\n\t\t\t\t\t\t? new DebugView(w.output, 'template', w.matchText, w.matchText) // Debug view setup.\n\t\t\t\t\t\t: w\n\t\t\t\t\t).output,\n\t\t\t\t\tresult\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'heading',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^!{1,6}',\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.subWikify(\n\t\t\t\tjQuery(document.createElement(`h${w.matchLength}`)).appendTo(w.output).get(0),\n\t\t\t\tthis.terminator\n\t\t\t);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname           : 'table',\n\t\tprofiles       : ['block'],\n\t\tmatch          : '^\\\\|(?:[^\\\\n]*)\\\\|(?:[fhck]?)$',\n\t\tlookahead      : /^\\|([^\\n]*)\\|([fhck]?)$/gm,\n\t\trowTerminator  : '\\\\|(?:[cfhk]?)$\\\\n?',\n\t\tcellPattern    : '(?:\\\\|([^\\\\n\\\\|]*)\\\\|)|(\\\\|[cfhk]?$\\\\n?)',\n\t\tcellTerminator : '(?:\\\\u0020*)\\\\|',\n\t\trowTypes       : { c : 'caption', f : 'tfoot', h : 'thead', '' : 'tbody' }, // eslint-disable-line id-length\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst table       = jQuery(document.createElement('table')).appendTo(w.output).get(0);\n\t\t\tconst prevColumns = [];\n\t\t\tlet curRowType    = null;\n\t\t\tlet $rowContainer = null;\n\t\t\tlet rowCount      = 0;\n\t\t\tlet matched;\n\n\t\t\tw.nextMatch = w.matchStart;\n\n\t\t\tdo {\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tconst nextRowType = match[2];\n\n\t\t\t\t\tif (nextRowType === 'k') {\n\t\t\t\t\t\ttable.className = match[1];\n\t\t\t\t\t\tw.nextMatch += match[0].length + 1;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (nextRowType !== curRowType) {\n\t\t\t\t\t\t\tcurRowType = nextRowType;\n\t\t\t\t\t\t\t$rowContainer = jQuery(document.createElement(this.rowTypes[nextRowType]))\n\t\t\t\t\t\t\t\t.appendTo(table);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (curRowType === 'c') {\n\t\t\t\t\t\t\t$rowContainer.css('caption-side', rowCount === 0 ? 'top' : 'bottom');\n\t\t\t\t\t\t\tw.nextMatch += 1;\n\t\t\t\t\t\t\tw.subWikify($rowContainer[0], this.rowTerminator);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tthis.rowHandler(\n\t\t\t\t\t\t\t\tw,\n\t\t\t\t\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t\t\t\t\t.appendTo($rowContainer)\n\t\t\t\t\t\t\t\t\t.get(0),\n\t\t\t\t\t\t\t\tprevColumns\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t++rowCount;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t},\n\n\t\trowHandler(w, rowEl, prevColumns) {\n\t\t\tconst cellRe = new RegExp(this.cellPattern, 'gm');\n\t\t\tlet col         = 0;\n\t\t\tlet curColCount = 1;\n\t\t\tlet matched;\n\n\t\t\tdo {\n\t\t\t\tcellRe.lastIndex = w.nextMatch;\n\n\t\t\t\tconst cellMatch = cellRe.exec(w.source);\n\n\t\t\t\tmatched = cellMatch && cellMatch.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tif (cellMatch[1] === '~') {\n\t\t\t\t\t\tconst last = prevColumns[col];\n\n\t\t\t\t\t\tif (last) {\n\t\t\t\t\t\t\t++last.rowCount;\n\t\t\t\t\t\t\tlast.$element\n\t\t\t\t\t\t\t\t.attr('rowspan', last.rowCount)\n\t\t\t\t\t\t\t\t.css('vertical-align', 'middle');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length - 1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (cellMatch[1] === '>') {\n\t\t\t\t\t\t++curColCount;\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length - 1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (cellMatch[2]) {\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t++w.nextMatch;\n\n\t\t\t\t\t\tconst css = Wikifier.helpers.inlineCss(w);\n\t\t\t\t\t\tlet spaceLeft  = false;\n\t\t\t\t\t\tlet spaceRight = false;\n\t\t\t\t\t\tlet $cell;\n\n\t\t\t\t\t\twhile (w.source.substr(w.nextMatch, 1) === ' ') {\n\t\t\t\t\t\t\tspaceLeft = true;\n\t\t\t\t\t\t\t++w.nextMatch;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (w.source.substr(w.nextMatch, 1) === '!') {\n\t\t\t\t\t\t\t$cell = jQuery(document.createElement('th')).appendTo(rowEl);\n\t\t\t\t\t\t\t++w.nextMatch;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t$cell = jQuery(document.createElement('td')).appendTo(rowEl);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tprevColumns[col] = {\n\t\t\t\t\t\t\trowCount : 1,\n\t\t\t\t\t\t\t$element : $cell\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (curColCount > 1) {\n\t\t\t\t\t\t\t$cell.attr('colspan', curColCount);\n\t\t\t\t\t\t\tcurColCount = 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tw.subWikify($cell[0], this.cellTerminator);\n\n\t\t\t\t\t\tif (w.matchText.substr(w.matchText.length - 2, 1) === ' ') {\n\t\t\t\t\t\t\tspaceRight = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcss.classes.forEach(className => $cell.addClass(className));\n\n\t\t\t\t\t\tif (css.id !== '') {\n\t\t\t\t\t\t\t$cell.attr('id', css.id);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (spaceLeft && spaceRight) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'center';\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (spaceLeft) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'right';\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (spaceRight) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'left';\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$cell.css(css.styles);\n\n\t\t\t\t\t\tw.nextMatch = w.nextMatch - 1;\n\t\t\t\t\t}\n\n\t\t\t\t\t++col;\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'list',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^(?:(?:\\\\*+)|(?:#+))',\n\t\tlookahead  : /^(?:(\\*+)|(#+))/gm,\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = w.matchStart;\n\n\t\t\tconst destStack = [w.output];\n\t\t\tlet curType  = null;\n\t\t\tlet curLevel = 0;\n\t\t\tlet matched;\n\t\t\tlet i;\n\n\t\t\tdo {\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tconst newType  = match[2] ? 'ol' : 'ul';\n\t\t\t\t\tconst newLevel = match[0].length;\n\n\t\t\t\t\tw.nextMatch += match[0].length;\n\n\t\t\t\t\tif (newLevel > curLevel) {\n\t\t\t\t\t\tfor (i = curLevel; i < newLevel; ++i) {\n\t\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\t\tjQuery(document.createElement(newType))\n\t\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (newLevel < curLevel) {\n\t\t\t\t\t\tfor (i = curLevel; i > newLevel; --i) {\n\t\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (newLevel === curLevel && newType !== curType) {\n\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\tjQuery(document.createElement(newType))\n\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tcurLevel = newLevel;\n\t\t\t\t\tcurType = newType;\n\t\t\t\t\tw.subWikify(\n\t\t\t\t\t\tjQuery(document.createElement('li'))\n\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t.get(0),\n\t\t\t\t\t\tthis.terminator\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'commentByBlock',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '(?:/(?:%|\\\\*))|(?:<!--)',\n\t\tlookahead : /(?:\\/(%|\\*)(?:(?:.|\\n)*?)\\1\\/)|(?:<!--(?:(?:.|\\n)*?)-->)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'lineContinuation',\n\t\tprofiles : ['core'],\n\n\t\t// WARNING: The ordering here is important: end-of-line, start-of-line, end-of-string, start-of-string.\n\t\tmatch : `\\\\\\\\${Patterns.spaceNoTerminator}*\\\\n|\\\\n${Patterns.spaceNoTerminator}*\\\\\\\\|\\\\n?\\\\\\\\${Patterns.spaceNoTerminator}*$|^${Patterns.spaceNoTerminator}*\\\\\\\\\\\\n?`,\n\n\t\thandler(w) {\n\t\t\tw.nextMatch = w.matchStart + w.matchLength;\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'lineBreak',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\n|<[Bb][Rr]\\\\s*/?>',\n\n\t\thandler(w) {\n\t\t\tif (!w.options.nobr) {\n\t\t\t\tjQuery(document.createElement('br')).appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'htmlCharacterReference',\n\t\tprofiles : ['core'],\n\t\tmatch    : '(?:(?:&#?[0-9A-Za-z]{2,8};|.)(?:&#?(?:x0*(?:3[0-6][0-9A-Fa-f]|1D[C-Fc-f][0-9A-Fa-f]|20[D-Fd-f][0-9A-Fa-f]|FE2[0-9A-Fa-f])|0*(?:76[89]|7[7-9][0-9]|8[0-7][0-9]|761[6-9]|76[2-7][0-9]|84[0-3][0-9]|844[0-7]|6505[6-9]|6506[0-9]|6507[0-1]));)+|&#?[0-9A-Za-z]{2,8};)',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t.append(w.matchText)\n\t\t\t\t.appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'xmlProlog',\n\t\tprofiles : ['core'],\n\t\tmatch    : '<\\\\?[Xx][Mm][Ll][^>]*\\\\?>',\n\n\t\thandler(w) {\n\t\t\tw.nextMatch = w.matchStart + w.matchLength;\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimHtml',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Hh][Tt][Mm][Ll]>',\n\t\tlookahead : /<[Hh][Tt][Mm][Ll]>((?:.|\\n)*?)<\\/[Hh][Tt][Mm][Ll]>/gm,\n\t\thandler   : _verbatimTagHandler\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimScriptTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Ss][Cc][Rr][Ii][Pp][Tt][^>]*>',\n\t\tlookahead : /(<[Ss][Cc][Rr][Ii][Pp][Tt]*>(?:.|\\n)*?<\\/[Ss][Cc][Rr][Ii][Pp][Tt]>)/gm,\n\t\thandler   : _verbatimTagHandler\n\t});\n\n\tWikifier.Parser.add({\n\t\tname           : 'styleTag',\n\t\tprofiles       : ['core'],\n\t\tmatch          : '<[Ss][Tt][Yy][Ll][Ee][^>]*>',\n\t\tlookahead      : /(<[Ss][Tt][Yy][Ll][Ee]*>)((?:.|\\n)*?)(<\\/[Ss][Tt][Yy][Ll][Ee]>)/gm,\n\t\timageMarkup    : new RegExp(Patterns.cssImage, 'g'),\n\t\thasImageMarkup : new RegExp(Patterns.cssImage),\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tlet css = match[2];\n\n\t\t\t\t// Check for wiki image transclusion.\n\t\t\t\tif (this.hasImageMarkup.test(css)) {\n\t\t\t\t\tthis.imageMarkup.lastIndex = 0;\n\n\t\t\t\t\tcss = css.replace(this.imageMarkup, wikiImage => {\n\t\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\t\tsource     : wikiImage,\n\t\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (markup.hasOwnProperty('error') || markup.pos < wikiImage.length) {\n\t\t\t\t\t\t\treturn wikiImage;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet source = markup.source;\n\n\t\t\t\t\t\t// Handle image passage transclusion.\n\t\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t\tsource = passage.text;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tThe source may be URI- or Base64-encoded, so we cannot use `encodeURIComponent()`\n\t\t\t\t\t\t\there.  Instead, we simply encode any double quotes, since the URI will be\n\t\t\t\t\t\t\tdelimited by them.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\treturn `url(\"${source.replace(/\"/g, '%22')}\")`;\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t\t.append(match[1] + css + match[3])\n\t\t\t\t\t.appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'svgTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Ss][Vv][Gg][^>]*>',\n\t\tlookahead : /(<[Ss][Vv][Gg][^>]*>(?:.|\\n)*?<\\/[Ss][Vv][Gg]>)/gm,\n\t\tnamespace : 'http://www.w3.org/2000/svg',\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tconst $frag = jQuery(document.createDocumentFragment()).append(match[1]);\n\n\t\t\t\t// Postprocess the relevant SVG element nodes.\n\t\t\t\t$frag.find('a[data-passage],image[data-passage]').each((_, el) => {\n\t\t\t\t\tconst tagName = el.tagName.toLowerCase();\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.processAttributeDirectives(el);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`svg|<${tagName}>: ${ex.message}`,\n\t\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (el.hasAttribute('data-passage')) {\n\t\t\t\t\t\tthis.processDataAttributes(el, tagName);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\t$frag.appendTo(w.output);\n\t\t\t}\n\t\t},\n\n\t\tprocessAttributeDirectives(el) {\n\t\t\t// NOTE: The `.attributes` property yields a live collection, so we\n\t\t\t// must make a non-live copy of it as we will be adding and removing\n\t\t\t// members of said collection if any directives are found.\n\t\t\t[...el.attributes].forEach(({ name, value }) => {\n\t\t\t\tconst evalShorthand = name[0] === '@';\n\n\t\t\t\tif (evalShorthand || name.startsWith('sc-eval:')) {\n\t\t\t\t\tconst newName = name.slice(evalShorthand ? 1 : 8); // Remove eval directive prefix.\n\n\t\t\t\t\tif (newName === 'data-setter') {\n\t\t\t\t\t\tthrow new Error(`evaluation directive is not allowed on the data-setter attribute: \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\t// Evaluate the value as TwineScript.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = Scripting.evalTwineScript(value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`bad evaluation from attribute directive \"${name}\": ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Assign the result to the new attribute and remove the old one.\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: Most browsers (ca. Nov 2017) have broken `setAttribute()`\n\t\t\t\t\t\t\tmethod implementations that throw on attribute names that start\n\t\t\t\t\t\t\twith, or contain, various symbols that are completely valid per\n\t\t\t\t\t\t\tthe specification.  Thus this code could fail if the user chooses\n\t\t\t\t\t\t\tattribute names that, after removing the directive prefix, are\n\t\t\t\t\t\t\tunpalatable to `setAttribute()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tel.setAttribute(newName, result);\n\t\t\t\t\t\tel.removeAttribute(name);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`cannot transform attribute directive \"${name}\" into attribute \"${newName}\"`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tprocessDataAttributes(el, tagName) {\n\t\t\tlet passage = el.getAttribute('data-passage');\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst evaluated = Wikifier.helpers.evalPassageId(passage);\n\n\t\t\tif (evaluated !== passage) {\n\t\t\t\tpassage = evaluated;\n\t\t\t\tel.setAttribute('data-passage', evaluated);\n\t\t\t}\n\n\t\t\tif (passage !== '') {\n\t\t\t\t// '<image>' element, so attempt media passage transclusion.\n\t\t\t\tif (tagName === 'image') {\n\t\t\t\t\tif (passage.slice(0, 5) !== 'data:' && Story.has(passage)) {\n\t\t\t\t\t\tpassage = Story.get(passage);\n\n\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t// NOTE: SVG `.href` IDL attribute is read-only,\n\t\t\t\t\t\t\t// so set its `href` content attribute instead.\n\t\t\t\t\t\t\tel.setAttribute('href', passage.text.trim());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Elsewise, assume a link element of some type—e.g., '<a>'.\n\t\t\t\telse {\n\t\t\t\t\tlet setter = el.getAttribute('data-setter');\n\t\t\t\t\tlet setFn;\n\n\t\t\t\t\tif (setter != null) { // lazy equality for null\n\t\t\t\t\t\tsetter = String(setter).trim();\n\n\t\t\t\t\t\tif (setter !== '') {\n\t\t\t\t\t\t\tsetFn = Wikifier.helpers.createShadowSetterCallback(Scripting.parse(setter));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tel.classList.add('link-internal');\n\n\t\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t\tel.classList.add('link-visited');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tel.classList.add('link-broken');\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery(el).ariaClick({ one : true }, function () {\n\t\t\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\t\t\tsetFn.call(this);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\t/*\n\t\t\tNOTE: This parser MUST come after any parser which handles HTML tag-\n\t\t\tlike constructs—e.g. 'verbatimText', 'horizontalRule', 'lineBreak',\n\t\t\t'xmlProlog', 'verbatimHtml', 'verbatimSvgTag', 'verbatimScriptTag',\n\t\t\tand 'styleTag'.\n\t\t*/\n\t\tname      : 'htmlTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<\\\\w+(?:\\\\s+[^\\\\u0000-\\\\u001F\\\\u007F-\\\\u009F\\\\s\"\\'>\\\\/=]+(?:\\\\s*=\\\\s*(?:\"[^\"]*?\"|\\'[^\\']*?\\'|[^\\\\s\"\\'=<>`]+))?)*\\\\s*\\\\/?>',\n\t\ttagRe     : /^<(\\w+)/,\n\t\tmediaTags : ['audio', 'img', 'source', 'track', 'video'], // NOTE: The `<picture>` element should not be in this list.\n\t\tnobrTags  : ['audio', 'colgroup', 'datalist', 'dl', 'figure', 'meter', 'ol', 'optgroup', 'picture', 'progress', 'ruby', 'select', 'table', 'tbody', 'tfoot', 'thead', 'tr', 'ul', 'video'],\n\t\tvoidTags  : ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'],\n\n\t\thandler(w) {\n\t\t\tconst tagMatch = this.tagRe.exec(w.matchText);\n\t\t\tconst tag      = tagMatch && tagMatch[1];\n\t\t\tconst tagName  = tag && tag.toLowerCase();\n\n\t\t\tif (tagName) {\n\t\t\t\tconst isVoid = this.voidTags.includes(tagName) || w.matchText.endsWith('/>');\n\t\t\t\tconst isNobr = this.nobrTags.includes(tagName);\n\t\t\t\tlet terminator;\n\t\t\t\tlet terminatorMatch;\n\n\t\t\t\tif (!isVoid) {\n\t\t\t\t\tterminator = `<\\\\/${tagName}\\\\s*>`;\n\n\t\t\t\t\tconst terminatorRe = new RegExp(terminator, 'gim'); // ignore case during match\n\n\t\t\t\t\tterminatorRe.lastIndex = w.matchStart;\n\t\t\t\t\tterminatorMatch = terminatorRe.exec(w.source);\n\t\t\t\t}\n\n\t\t\t\tif (isVoid || terminatorMatch) {\n\t\t\t\t\tlet output    = w.output;\n\t\t\t\t\tlet el        = document.createElement(w.output.tagName);\n\t\t\t\t\tlet debugView;\n\n\t\t\t\t\tel.innerHTML = w.matchText;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tNOTE: The use of a `while` statement here is curious, however,\n\t\t\t\t\t\tI'm hesitant to change it for fear of breaking some edge case.\n\t\t\t\t\t*/\n\t\t\t\t\twhile (el.firstChild) {\n\t\t\t\t\t\tel = el.firstChild;\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.processAttributeDirectives(el);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`<${tagName}>: ${ex.message}`,\n\t\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (el.hasAttribute('data-passage')) {\n\t\t\t\t\t\tthis.processDataAttributes(el, tagName);\n\n\t\t\t\t\t\t// Debug view setup.\n\t\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t`html-${tagName}`,\n\t\t\t\t\t\t\t\ttagName,\n\t\t\t\t\t\t\t\tw.matchText\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tdebugView.modes({\n\t\t\t\t\t\t\t\tblock   : tagName === 'img',\n\t\t\t\t\t\t\t\tnonvoid : terminatorMatch\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\toutput = debugView.output;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (terminatorMatch) {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists\n\t\t\t\t\t\t\tsolely to ensure that the options stack is properly restored in\n\t\t\t\t\t\t\tthe event that an uncaught exception is thrown during the call to\n\t\t\t\t\t\t\t`subWikify()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tWikifier.Option.push({ nobr : isNobr });\n\t\t\t\t\t\t\tw.subWikify(el, terminator, { ignoreTerminatorCase : true });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\tWikifier.Option.pop();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tDebug view modification.  If the current element has any debug\n\t\t\t\t\t\t\tview descendants who have \"block\" mode set, then set its debug\n\t\t\t\t\t\t\tview to the same.  It just makes things look a bit nicer.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tif (debugView && jQuery(el).find('.debug.block').length > 0) {\n\t\t\t\t\t\t\tdebugView.modes({ block : true });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tNOTE: The use of `cloneNode(true)` here for `<track>` elements\n\t\t\t\t\t\tis necessary to workaround a poorly understood rehoming issue.\n\t\t\t\t\t*/\n\t\t\t\t\toutput.appendChild(tagName === 'track' ? el.cloneNode(true) : el);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot find a closing tag for HTML <${tag}>`,\n\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tprocessAttributeDirectives(el) {\n\t\t\t// NOTE: The `.attributes` property yields a live collection, so we\n\t\t\t// must make a non-live copy of it as we will be adding and removing\n\t\t\t// members of said collection if any directives are found.\n\t\t\t[...el.attributes].forEach(({ name, value }) => {\n\t\t\t\tconst evalShorthand = name[0] === '@';\n\n\t\t\t\tif (evalShorthand || name.startsWith('sc-eval:')) {\n\t\t\t\t\tconst newName = name.slice(evalShorthand ? 1 : 8); // Remove eval directive prefix.\n\n\t\t\t\t\tif (newName === 'data-setter') {\n\t\t\t\t\t\tthrow new Error(`evaluation directive is not allowed on the data-setter attribute: \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\t// Evaluate the value as TwineScript.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = Scripting.evalTwineScript(value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`bad evaluation from attribute directive \"${name}\": ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Assign the result to the new attribute and remove the old one.\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: Most browsers (ca. Nov 2017) have broken `setAttribute()`\n\t\t\t\t\t\t\tmethod implementations that throw on attribute names that start\n\t\t\t\t\t\t\twith, or contain, various symbols that are completely valid per\n\t\t\t\t\t\t\tthe specification.  Thus this code could fail if the user chooses\n\t\t\t\t\t\t\tattribute names that, after removing the directive prefix, are\n\t\t\t\t\t\t\tunpalatable to `setAttribute()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tel.setAttribute(newName, result);\n\t\t\t\t\t\tel.removeAttribute(name);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`cannot transform attribute directive \"${name}\" into attribute \"${newName}\"`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tprocessDataAttributes(el, tagName) {\n\t\t\tlet passage = el.getAttribute('data-passage');\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst evaluated = Wikifier.helpers.evalPassageId(passage);\n\n\t\t\tif (evaluated !== passage) {\n\t\t\t\tpassage = evaluated;\n\t\t\t\tel.setAttribute('data-passage', evaluated);\n\t\t\t}\n\n\t\t\tif (passage !== '') {\n\t\t\t\t// Media element, so attempt media passage transclusion.\n\t\t\t\tif (this.mediaTags.includes(tagName)) {\n\t\t\t\t\tif (passage.slice(0, 5) !== 'data:' && Story.has(passage)) {\n\t\t\t\t\t\tpassage = Story.get(passage);\n\n\t\t\t\t\t\tlet parentName;\n\t\t\t\t\t\tlet twineTag;\n\n\t\t\t\t\t\tswitch (tagName) {\n\t\t\t\t\t\tcase 'audio':\n\t\t\t\t\t\tcase 'video':\n\t\t\t\t\t\t\ttwineTag = `Twine.${tagName}`;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'img':\n\t\t\t\t\t\t\ttwineTag = 'Twine.image';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'track':\n\t\t\t\t\t\t\ttwineTag = 'Twine.vtt';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'source':\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst $parent = $(el).closest('audio,picture,video');\n\n\t\t\t\t\t\t\t\tif ($parent.length) {\n\t\t\t\t\t\t\t\t\tparentName = $parent.get(0).tagName.toLowerCase();\n\t\t\t\t\t\t\t\t\ttwineTag = `Twine.${parentName === 'picture' ? 'image' : parentName}`;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (passage.tags.includes(twineTag)) {\n\t\t\t\t\t\t\tel[parentName === 'picture' ? 'srcset' : 'src'] = passage.text.trim();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Elsewise, assume a link element of some type—e.g., '<a>', '<area>', '<button>', etc.\n\t\t\t\telse {\n\t\t\t\t\tlet setter = el.getAttribute('data-setter');\n\t\t\t\t\tlet setFn;\n\n\t\t\t\t\tif (setter != null) { // lazy equality for null\n\t\t\t\t\t\tsetter = String(setter).trim();\n\n\t\t\t\t\t\tif (setter !== '') {\n\t\t\t\t\t\t\tsetFn = Wikifier.helpers.createShadowSetterCallback(Scripting.parse(setter));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tel.classList.add('link-internal');\n\n\t\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t\tel.classList.add('link-visited');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tel.classList.add('link-broken');\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery(el).ariaClick({ one : true }, function () {\n\t\t\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\t\t\tsetFn.call(this);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/template.js\n\n\tCopyright © 2019–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns */\n\nvar Template = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Template definitions.\n\tconst _templates = new Map();\n\n\t// Valid template name regular expression.\n\tconst _validNameRe = new RegExp(`^(?:${Patterns.templateName})$`);\n\n\t// Valid template type predicate.\n\tconst _validType = template => {\n\t\tconst templateType = typeof template;\n\t\treturn templateType === 'function' || templateType === 'string';\n\t};\n\n\n\t/*******************************************************************************\n\t\tTemplate Functions.\n\t*******************************************************************************/\n\n\tfunction templateAdd(name, template) {\n\t\tif (\n\t\t\t   !_validType(template)\n\t\t\t&& !(template instanceof Array && template.length > 0 && template.every(_validType))\n\t\t) {\n\t\t\tthrow new TypeError(`invalid template type (${name}); templates must be: functions, strings, or an array of either`);\n\t\t}\n\n\t\t(name instanceof Array ? name : [name]).forEach(name => {\n\t\t\tif (!_validNameRe.test(name)) {\n\t\t\t\tthrow new Error(`invalid template name \"${name}\"`);\n\t\t\t}\n\t\t\tif (_templates.has(name)) {\n\t\t\t\tthrow new Error(`cannot clobber existing template ?${name}`);\n\t\t\t}\n\n\t\t\t_templates.set(name, template);\n\t\t});\n\t}\n\n\tfunction templateDelete(name) {\n\t\t(name instanceof Array ? name : [name]).forEach(name => _templates.delete(name));\n\t}\n\n\tfunction templateGet(name) {\n\t\treturn _templates.has(name) ? _templates.get(name) : null;\n\t}\n\n\tfunction templateHas(name) {\n\t\treturn _templates.has(name);\n\t}\n\n\tfunction templateSize() {\n\t\treturn _templates.size;\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tadd    : { value : templateAdd },\n\t\tdelete : { value : templateDelete },\n\t\tget    : { value : templateGet },\n\t\thas    : { value : templateHas },\n\t\tsize   : { get : templateSize }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macro.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns, Scripting, clone, macros */\n\nvar Macro = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Macro definitions.\n\tconst _macros = {};\n\n\t// Map of all macro tags and their parents (key: 'tag name' => value: ['list of parent names']).\n\tconst _tags = {};\n\n\t// Valid macro name regular expression.\n\tconst _validNameRe = new RegExp(`^(?:${Patterns.macroName})$`);\n\n\n\t/*******************************************************************************************************************\n\t\tMacros Functions.\n\t*******************************************************************************************************************/\n\tfunction macrosAdd(name, def, deep) {\n\t\tif (Array.isArray(name)) {\n\t\t\tname.forEach(name => macrosAdd(name, def, deep));\n\t\t\treturn;\n\t\t}\n\n\t\tif (!_validNameRe.test(name)) {\n\t\t\tthrow new Error(`invalid macro name \"${name}\"`);\n\t\t}\n\n\t\tif (macrosHas(name)) {\n\t\t\tthrow new Error(`cannot clobber existing macro <<${name}>>`);\n\t\t}\n\t\telse if (tagsHas(name)) {\n\t\t\tthrow new Error(`cannot clobber child tag <<${name}>> of parent macro${_tags[name].length === 1 ? '' : 's'} <<${_tags[name].join('>>, <<')}>>`);\n\t\t}\n\n\t\ttry {\n\t\t\tif (typeof def === 'object') {\n\t\t\t\t// Add the macro definition.\n\t\t\t\t_macros[name] = deep ? clone(def) : def;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Add the macro alias.\n\t\t\t\tif (macrosHas(def)) {\n\t\t\t\t\t_macros[name] = deep ? clone(_macros[def]) : _macros[def];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new Error(`cannot create alias of nonexistent macro <<${def}>>`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tObject.defineProperty(_macros, name, { writable : false });\n\n\t\t\t/* legacy */\n\t\t\t/*\n\t\t\t\tSince `macrosGet()` may return legacy macros, we have to add a flag to (modern)\n\t\t\t\tAPI macros, so that the macro formatter will know how to call the macro.\n\t\t\t*/\n\t\t\t_macros[name]._MACRO_API = true;\n\t\t\t/* /legacy */\n\t\t}\n\t\tcatch (ex) {\n\t\t\tif (ex.name === 'TypeError') {\n\t\t\t\tthrow new Error(`cannot clobber protected macro <<${name}>>`);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error(`unknown error when attempting to add macro <<${name}>>: [${ex.name}] ${ex.message}`);\n\t\t\t}\n\t\t}\n\n\t\t// Tags post-processing.\n\t\tif (_macros[name].hasOwnProperty('tags')) {\n\t\t\tif (_macros[name].tags == null) { // lazy equality for null\n\t\t\t\ttagsRegister(name);\n\t\t\t}\n\t\t\telse if (Array.isArray(_macros[name].tags)) {\n\t\t\t\ttagsRegister(name, _macros[name].tags);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error(`bad value for \"tags\" property of macro <<${name}>>`);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction macrosDelete(name) {\n\t\tif (Array.isArray(name)) {\n\t\t\tname.forEach(name => macrosDelete(name));\n\t\t\treturn;\n\t\t}\n\n\t\tif (macrosHas(name)) {\n\t\t\t// Tags pre-processing.\n\t\t\tif (_macros[name].hasOwnProperty('tags')) {\n\t\t\t\ttagsUnregister(name);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t// Remove the macro definition.\n\t\t\t\tObject.defineProperty(_macros, name, { writable : true });\n\t\t\t\tdelete _macros[name];\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tthrow new Error(`unknown error removing macro <<${name}>>: ${ex.message}`);\n\t\t\t}\n\t\t}\n\t\telse if (tagsHas(name)) {\n\t\t\tthrow new Error(`cannot remove child tag <<${name}>> of parent macro <<${_tags[name]}>>`);\n\t\t}\n\t}\n\n\tfunction macrosIsEmpty() {\n\t\treturn Object.keys(_macros).length === 0;\n\t}\n\n\tfunction macrosHas(name) {\n\t\treturn _macros.hasOwnProperty(name);\n\t}\n\n\tfunction macrosGet(name) {\n\t\tlet macro = null;\n\n\t\tif (macrosHas(name) && typeof _macros[name].handler === 'function') {\n\t\t\tmacro = _macros[name];\n\t\t}\n\t\t/* legacy macro support */\n\t\telse if (macros.hasOwnProperty(name) && typeof macros[name].handler === 'function') {\n\t\t\tmacro = macros[name];\n\t\t}\n\t\t/* /legacy macro support */\n\n\t\treturn macro;\n\t}\n\n\tfunction macrosInit(handler = 'init') { // eslint-disable-line no-unused-vars\n\t\tObject.keys(_macros).forEach(name => {\n\t\t\tif (typeof _macros[name][handler] === 'function') {\n\t\t\t\t_macros[name][handler](name);\n\t\t\t}\n\t\t});\n\n\t\t/* legacy macro support */\n\t\tObject.keys(macros).forEach(name => {\n\t\t\tif (typeof macros[name][handler] === 'function') {\n\t\t\t\tmacros[name][handler](name);\n\t\t\t}\n\t\t});\n\t\t/* /legacy macro support */\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTags Functions.\n\t*******************************************************************************************************************/\n\tfunction tagsRegister(parent, bodyTags) {\n\t\tif (!parent) {\n\t\t\tthrow new Error('no parent specified');\n\t\t}\n\n\t\tconst endTags = [`/${parent}`, `end${parent}`]; // automatically create the closing tags\n\t\tconst allTags = [].concat(endTags, Array.isArray(bodyTags) ? bodyTags : []);\n\n\t\tfor (let i = 0; i < allTags.length; ++i) {\n\t\t\tconst tag = allTags[i];\n\n\t\t\tif (macrosHas(tag)) {\n\t\t\t\tthrow new Error('cannot register tag for an existing macro');\n\t\t\t}\n\n\t\t\tif (tagsHas(tag)) {\n\t\t\t\tif (!_tags[tag].includes(parent)) {\n\t\t\t\t\t_tags[tag].push(parent);\n\t\t\t\t\t_tags[tag].sort();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_tags[tag] = [parent];\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction tagsUnregister(parent) {\n\t\tif (!parent) {\n\t\t\tthrow new Error('no parent specified');\n\t\t}\n\n\t\tObject.keys(_tags).forEach(tag => {\n\t\t\tconst i = _tags[tag].indexOf(parent);\n\n\t\t\tif (i !== -1) {\n\t\t\t\tif (_tags[tag].length === 1) {\n\t\t\t\t\tdelete _tags[tag];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_tags[tag].splice(i, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction tagsHas(name) {\n\t\treturn _tags.hasOwnProperty(name);\n\t}\n\n\tfunction tagsGet(name) {\n\t\treturn tagsHas(name) ? _tags[name] : null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tMacro Functions.\n\t\t*/\n\t\tadd     : { value : macrosAdd },\n\t\tdelete  : { value : macrosDelete },\n\t\tisEmpty : { value : macrosIsEmpty },\n\t\thas     : { value : macrosHas },\n\t\tget     : { value : macrosGet },\n\t\tinit    : { value : macrosInit },\n\n\t\t/*\n\t\t\tTags Functions.\n\t\t*/\n\t\ttags : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tregister   : { value : tagsRegister },\n\t\t\t\tunregister : { value : tagsUnregister },\n\t\t\t\thas        : { value : tagsHas },\n\t\t\t\tget        : { value : tagsGet }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tevalStatements : { value : (...args) => Scripting.evalJavaScript(...args) } // SEE: `markup/scripting.js`.\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macrocontext.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, DebugView, Patterns, State, Wikifier, throwError */\n\nvar MacroContext = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tMacroContext Class.\n\t*******************************************************************************************************************/\n\tclass MacroContext {\n\t\tconstructor(contextData) {\n\t\t\tconst context = Object.assign({\n\t\t\t\tparent  : null,\n\t\t\t\tmacro   : null,\n\t\t\t\tname    : '',\n\t\t\t\targs    : null,\n\t\t\t\tpayload : null,\n\t\t\t\tparser  : null,\n\t\t\t\tsource  : ''\n\t\t\t}, contextData);\n\n\t\t\tif (context.macro === null || context.name === '' || context.parser === null) {\n\t\t\t\tthrow new TypeError('context object missing required properties');\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tself : {\n\t\t\t\t\tvalue : context.macro\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : context.name\n\t\t\t\t},\n\n\t\t\t\targs : {\n\t\t\t\t\tvalue : context.args\n\t\t\t\t},\n\n\t\t\t\tpayload : {\n\t\t\t\t\tvalue : context.payload\n\t\t\t\t},\n\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : context.source\n\t\t\t\t},\n\n\t\t\t\tparent : {\n\t\t\t\t\tvalue : context.parent\n\t\t\t\t},\n\n\t\t\t\tparser : {\n\t\t\t\t\tvalue : context.parser\n\t\t\t\t},\n\n\t\t\t\t_output : {\n\t\t\t\t\tvalue : context.parser.output\n\t\t\t\t},\n\n\t\t\t\t_shadows : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_debugView : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_debugViewEnabled : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : Config.debug\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tget output() {\n\t\t\treturn this._debugViewEnabled ? this.debugView.output : this._output;\n\t\t}\n\n\t\tget shadows() {\n\t\t\treturn [...this._shadows];\n\t\t}\n\n\t\tget shadowView() {\n\t\t\tconst view = new Set();\n\t\t\tthis.contextSelectAll(ctx => ctx._shadows)\n\t\t\t\t.forEach(ctx => ctx._shadows.forEach(name => view.add(name)));\n\t\t\treturn [...view];\n\t\t}\n\n\t\tget debugView() {\n\t\t\tif (this._debugViewEnabled) {\n\t\t\t\treturn this._debugView !== null ? this._debugView : this.createDebugView();\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tcontextHas(filter) {\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tcontextSelect(filter) {\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\treturn context;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tcontextSelectAll(filter) {\n\t\t\tconst result = [];\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\tresult.push(context);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\taddShadow(...names) {\n\t\t\tif (!this._shadows) {\n\t\t\t\tthis._shadows = new Set();\n\t\t\t}\n\n\t\t\tconst varRe = new RegExp(`^${Patterns.variable}$`);\n\n\t\t\tnames\n\t\t\t\t.flat(Infinity)\n\t\t\t\t.forEach(name => {\n\t\t\t\t\tif (typeof name !== 'string') {\n\t\t\t\t\t\tthrow new TypeError(`variable name must be a string; type: ${typeof name}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!varRe.test(name)) {\n\t\t\t\t\t\tthrow new Error(`invalid variable name \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._shadows.add(name);\n\t\t\t\t});\n\t\t}\n\n\t\tcreateShadowWrapper(callback, doneCallback, startCallback) {\n\t\t\tconst shadowContext = this;\n\t\t\tlet shadowStore;\n\n\t\t\tif (typeof callback === 'function') {\n\t\t\t\tshadowStore = {};\n\t\t\t\tthis.shadowView.forEach(varName => {\n\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\t\t\tshadowStore[varName] = store[varKey];\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn function (...args) {\n\t\t\t\tif (typeof startCallback === 'function') {\n\t\t\t\t\tstartCallback.apply(this, args);\n\t\t\t\t}\n\n\t\t\t\tif (typeof callback === 'function') {\n\t\t\t\t\tconst shadowNames = Object.keys(shadowStore);\n\t\t\t\t\tconst valueCache  = shadowNames.length > 0 ? {} : null;\n\t\t\t\t\tconst macroParser = Wikifier.Parser.get('macro');\n\t\t\t\t\tlet contextCache;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t\tcallback.\n\t\t\t\t\t*/\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tCache the existing values of the variables to be shadowed and assign the\n\t\t\t\t\t\t\tshadow values.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tstore[varKey] = shadowStore[varName];\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Cache the existing macro execution context and assign the shadow context.\n\t\t\t\t\t\tcontextCache = macroParser.context;\n\t\t\t\t\t\tmacroParser.context = shadowContext;\n\n\t\t\t\t\t\t// Call the callback function.\n\t\t\t\t\t\tcallback.apply(this, args);\n\t\t\t\t\t}\n\t\t\t\t\tfinally {\n\t\t\t\t\t\t// Revert the macro execution context shadowing.\n\t\t\t\t\t\tif (contextCache !== undefined) {\n\t\t\t\t\t\t\tmacroParser.context = contextCache;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Revert the variable shadowing.\n\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tUpdate the shadow store with the variable's current value, in case it\n\t\t\t\t\t\t\t\twas modified during the callback.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\n\t\t\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (typeof doneCallback === 'function') {\n\t\t\t\t\tdoneCallback.apply(this, args);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tcreateDebugView(name, title) {\n\t\t\tthis._debugView = new DebugView(\n\t\t\t\tthis._output,\n\t\t\t\t'macro',\n\t\t\t\tname ? name : this.name,\n\t\t\t\ttitle ? title : this.source\n\t\t\t);\n\n\t\t\tif (this.payload !== null && this.payload.length > 0) {\n\t\t\t\tthis._debugView.modes({ nonvoid : true });\n\t\t\t}\n\n\t\t\tthis._debugViewEnabled = true;\n\t\t\treturn this._debugView;\n\t\t}\n\n\t\tremoveDebugView() {\n\t\t\tif (this._debugView !== null) {\n\t\t\t\tthis._debugView.remove();\n\t\t\t\tthis._debugView = null;\n\t\t\t}\n\n\t\t\tthis._debugViewEnabled = false;\n\t\t}\n\n\t\terror(message, source, stack) {\n\t\t\treturn throwError(this._output, `<<${this.name}>>: ${message}`, source ? source : this.source, stack);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn MacroContext;\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macrolib.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, DebugView, Engine, Has, L10n, Macro, Patterns, Scripting, SimpleAudio, State, Story,\n\t       TempState, Util, Wikifier, postdisplay, prehistory, storage, toStringOrDefault\n*/\n\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tVariables Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<capture>>\n\t*/\n\tMacro.add('capture', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tif (this.args.raw.length === 0) {\n\t\t\t\treturn this.error('no story/temporary variable list specified');\n\t\t\t}\n\n\t\t\tconst valueCache = {};\n\n\t\t\t/*\n\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t`Wikifier` call.\n\t\t\t*/\n\t\t\ttry {\n\t\t\t\tconst varRe = new RegExp(`(${Patterns.variable})`,'g');\n\t\t\t\tlet match;\n\n\t\t\t\t/*\n\t\t\t\t\tCache the existing values of the variables and add a shadow.\n\t\t\t\t*/\n\t\t\t\twhile ((match = varRe.exec(this.args.raw)) !== null) {\n\t\t\t\t\tconst varName = match[1];\n\t\t\t\t\tconst varKey  = varName.slice(1);\n\t\t\t\t\tconst store   = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.addShadow(varName);\n\t\t\t\t}\n\n\t\t\t\tnew Wikifier(this.output, this.payload[0].contents);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\t// Revert the variable shadowing.\n\t\t\t\tthis.shadows.forEach(varName => {\n\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<set>>\n\t*/\n\tMacro.add('set', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<unset>>\n\t*/\n\tMacro.add('unset', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no story/temporary variable list specified');\n\t\t\t}\n\n\t\t\tconst re = new RegExp(\n\t\t\t\t`State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})`,\n\t\t\t\t'g'\n\t\t\t);\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst store = State[match[1]];\n\t\t\t\tconst name  = match[2];\n\n\t\t\t\tif (store.hasOwnProperty(name)) {\n\t\t\t\t\tdelete store[name];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<remember>>\n\t*/\n\tMacro.add('remember', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\tconst remember = storage.get('remember') || {};\n\t\t\tconst re       = new RegExp(`State\\\\.variables\\\\.(${Patterns.identifier})`, 'g');\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst name = match[1];\n\t\t\t\tremember[name] = State.variables[name];\n\t\t\t}\n\n\t\t\tif (!storage.set('remember', remember)) {\n\t\t\t\treturn this.error(`unknown error, cannot remember: ${this.args.raw}`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t},\n\n\t\tinit() {\n\t\t\tconst remember = storage.get('remember');\n\n\t\t\tif (remember) {\n\t\t\t\tObject.keys(remember).forEach(name => State.variables[name] = remember[name]);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<forget>>\n\t*/\n\tMacro.add('forget', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no story variable list specified');\n\t\t\t}\n\n\t\t\tconst remember = storage.get('remember');\n\t\t\tconst re       = new RegExp(`State\\\\.variables\\\\.(${Patterns.identifier})`, 'g');\n\t\t\tlet match;\n\t\t\tlet needStore = false;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst name = match[1];\n\n\t\t\t\tif (State.variables.hasOwnProperty(name)) {\n\t\t\t\t\tdelete State.variables[name];\n\t\t\t\t}\n\n\t\t\t\tif (remember && remember.hasOwnProperty(name)) {\n\t\t\t\t\tneedStore = true;\n\t\t\t\t\tdelete remember[name];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (needStore) {\n\t\t\t\tif (Object.keys(remember).length === 0) {\n\t\t\t\t\tif (!storage.delete('remember')) {\n\t\t\t\t\t\treturn this.error('unknown error, cannot update remember store');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (!storage.set('remember', remember)) {\n\t\t\t\t\treturn this.error('unknown error, cannot update remember store');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tScripting Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<run>>\n\t*/\n\tMacro.add('run', 'set'); // add <<run>> as an alias of <<set>>\n\n\t/*\n\t\t<<script>>\n\t*/\n\tMacro.add('script', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tconst output = document.createDocumentFragment();\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.payload[0].contents, output);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.createDebugView();\n\t\t\t}\n\n\t\t\tif (output.hasChildNodes()) {\n\t\t\t\tthis.output.appendChild(output);\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tDisplay Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<include>>\n\t*/\n\tMacro.add('include', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = this.args[0].link;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the passage name.\n\t\t\t\tpassage = this.args[0];\n\t\t\t}\n\n\t\t\tif (!Story.has(passage)) {\n\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tpassage = Story.get(passage);\n\t\t\tlet $el;\n\n\t\t\tif (this.args[1]) {\n\t\t\t\t$el = jQuery(document.createElement(this.args[1]))\n\t\t\t\t\t.addClass(`${passage.domId} macro-${this.name}`)\n\t\t\t\t\t.attr('data-passage', passage.title)\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$el = jQuery(this.output);\n\t\t\t}\n\n\t\t\t$el.wiki(passage.processText());\n\t\t}\n\t});\n\n\t/*\n\t\t<<nobr>>\n\t*/\n\tMacro.add('nobr', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\t/*\n\t\t\t\tWikify the contents, after removing all leading & trailing newlines and compacting\n\t\t\t\tall internal sequences of newlines into single spaces.\n\t\t\t*/\n\t\t\tnew Wikifier(this.output, this.payload[0].contents.replace(/^\\n+|\\n+$/g, '').replace(/\\n+/g, ' '));\n\t\t}\n\t});\n\n\t/*\n\t\t<<print>>, <<=>>, & <<->>\n\t*/\n\tMacro.add(['print', '=', '-'], {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = toStringOrDefault(Scripting.evalJavaScript(this.args.full), null);\n\n\t\t\t\tif (result !== null) {\n\t\t\t\t\tnew Wikifier(this.output, this.name === '-' ? Util.escape(result) : result);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<silently>>\n\t*/\n\tMacro.add('silently', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, this.payload[0].contents.trim());\n\n\t\t\tif (Config.debug) {\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tthis.debugView.modes({ block : true, hidden : true });\n\t\t\t\tthis.output.appendChild(frag);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Discard the output, unless there were errors.\n\t\t\t\tconst errList = [...frag.querySelectorAll('.error')].map(errEl => errEl.textContent);\n\n\t\t\t\tif (errList.length > 0) {\n\t\t\t\t\treturn this.error(`error${errList.length === 1 ? '' : 's'} within contents (${errList.join('; ')})`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] <<display>>\n\t*/\n\tMacro.add('display', 'include'); // add <<display>> as an alias of <<include>>\n\n\n\t/*******************************************************************************************************************\n\t\tControl Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<if>>, <<elseif>>, & <<else>>\n\t*/\n\tMacro.add('if', {\n\t\tskipArgs : true,\n\t\ttags     : ['elseif', 'else'],\n\n\t\thandler() {\n\t\t\tlet i;\n\n\t\t\ttry {\n\t\t\t\tconst len = this.payload.length;\n\n\t\t\t\t// Sanity checks.\n\t\t\t\tfor (/* declared previously */ i = 0; i < len; ++i) {\n\t\t\t\t\t/* eslint-disable prefer-template */\n\t\t\t\t\tswitch (this.payload[i].name) {\n\t\t\t\t\tcase 'else':\n\t\t\t\t\t\tif (this.payload[i].args.raw.length > 0) {\n\t\t\t\t\t\t\tif (/^\\s*if\\b/i.test(this.payload[i].args.raw)) {\n\t\t\t\t\t\t\t\treturn this.error(`whitespace is not allowed between the \"else\" and \"if\" in <<elseif>> clause${i > 0 ? ' (#' + i + ')' : ''}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn this.error(`<<else>> does not accept a conditional expression (perhaps you meant to use <<elseif>>), invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (i + 1 !== len) {\n\t\t\t\t\t\t\treturn this.error('<<else>> must be the final clause');\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif (this.payload[i].args.full.length === 0) {\n\t\t\t\t\t\t\treturn this.error(`no conditional expression specified for <<${this.payload[i].name}>> clause${i > 0 ? ' (#' + i + ')' : ''}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (\n\t\t\t\t\t\t\t   Config.macros.ifAssignmentError\n\t\t\t\t\t\t\t&& /[^!=&^|<>*/%+-]=[^=>]/.test(this.payload[i].args.full)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn this.error(`assignment operator found within <<${this.payload[i].name}>> clause${i > 0 ? ' (#' + i + ')' : ''} (perhaps you meant to use an equality operator: ==, ===, eq, is), invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable prefer-template */\n\t\t\t\t}\n\n\t\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\t\tlet success = false;\n\n\t\t\t\t// Evaluate the clauses.\n\t\t\t\tfor (/* declared previously */ i = 0; i < len; ++i) {\n\t\t\t\t\t// Custom debug view setup for the current clause.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({ nonvoid : false });\n\t\t\t\t\t}\n\n\t\t\t\t\t// Conditional test.\n\t\t\t\t\tif (this.payload[i].name === 'else' || !!evalJavaScript(this.payload[i].args.full)) {\n\t\t\t\t\t\tsuccess = true;\n\t\t\t\t\t\tnew Wikifier(this.output, this.payload[i].contents);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse if (Config.debug) {\n\t\t\t\t\t\t// Custom debug view setup for a failed conditional.\n\t\t\t\t\t\tthis.debugView.modes({\n\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup for the remaining clauses.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tfor (++i; i < len; ++i) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tFake a debug view for `<</if>>`.  We do this to aid the checking of nesting\n\t\t\t\t\t\tand as a quick indicator of if any of the clauses matched.\n\t\t\t\t\t*/\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : !success,\n\t\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad conditional expression in <<${i === 0 ? 'if' : 'elseif'}>> clause${i > 0 ? ' (#' + i + ')' : ''}: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack); // eslint-disable-line prefer-template\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<switch>>, <<case>>, & <<default>>\n\t*/\n\tMacro.add('switch', {\n\t\tskipArgs : ['switch'],\n\t\ttags     : ['case', 'default'],\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\tconst len = this.payload.length;\n\n\t\t\t// if (len === 1 || !this.payload.some(p => p.name === 'case')) {\n\t\t\tif (len === 1) {\n\t\t\t\treturn this.error('no cases specified');\n\t\t\t}\n\n\t\t\tlet i;\n\n\t\t\t// Sanity checks.\n\t\t\tfor (/* declared previously */ i = 1; i < len; ++i) {\n\t\t\t\tswitch (this.payload[i].name) {\n\t\t\t\tcase 'default':\n\t\t\t\t\tif (this.payload[i].args.length > 0) {\n\t\t\t\t\t\treturn this.error(`<<default>> does not accept values, invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (i + 1 !== len) {\n\t\t\t\t\t\treturn this.error('<<default>> must be the final case');\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tif (this.payload[i].args.length === 0) {\n\t\t\t\t\t\treturn this.error(`no value(s) specified for <<${this.payload[i].name}>> (#${i})`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet result;\n\n\t\t\ttry {\n\t\t\t\tresult = Scripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\tconst debugView = this.debugView; // cache it now, to be modified later\n\t\t\tlet success = false;\n\n\t\t\t// Initial debug view setup for `<<switch>>`.\n\t\t\tif (Config.debug) {\n\t\t\t\tdebugView\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true\n\t\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Evaluate the clauses.\n\t\t\tfor (/* declared previously */ i = 1; i < len; ++i) {\n\t\t\t\t// Custom debug view setup for the current case.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t.modes({ nonvoid : false });\n\t\t\t\t}\n\n\t\t\t\t// Case test(s).\n\t\t\t\tif (this.payload[i].name === 'default' || this.payload[i].args.some(val => val === result)) {\n\t\t\t\t\tsuccess = true;\n\t\t\t\t\tnew Wikifier(this.output, this.payload[i].contents);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (Config.debug) {\n\t\t\t\t\t// Custom debug view setup for a failed case.\n\t\t\t\t\tthis.debugView.modes({\n\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup for the remaining cases.\n\t\t\tif (Config.debug) {\n\t\t\t\tfor (++i; i < len; ++i) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t/*\n\t\t\t\t\tFinalize the debug view for `<<switch>>` and fake a debug view for `<</switch>>`.\n\t\t\t\t\tWe do both as a quick indicator of if any of the cases matched and the latter\n\t\t\t\t\tto aid the checking of nesting.\n\t\t\t\t*/\n\t\t\t\tdebugView\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true, // !success,\n\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t});\n\t\t\t\tthis\n\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true, // !success,\n\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<for>>, <<break>>, & <<continue>>\n\t*/\n\tMacro.add('for', {\n\t\t/* eslint-disable max-len */\n\t\tskipArgs    : true,\n\t\ttags        : null,\n\t\t_hasRangeRe : new RegExp(`^\\\\S${Patterns.anyChar}*?\\\\s+range\\\\s+\\\\S${Patterns.anyChar}*?$`),\n\t\t_rangeRe    : new RegExp(`^(?:State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})\\\\s*,\\\\s*)?State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})\\\\s+range\\\\s+(\\\\S${Patterns.anyChar}*?)$`),\n\t\t_3PartRe    : /^([^;]*?)\\s*;\\s*([^;]*?)\\s*;\\s*([^;]*?)$/,\n\t\t/* eslint-enable max-len */\n\n\t\thandler() {\n\t\t\tconst argsStr = this.args.full.trim();\n\t\t\tconst payload = this.payload[0].contents.replace(/\\n$/, '');\n\n\t\t\t// Empty form.\n\t\t\tif (argsStr.length === 0) {\n\t\t\t\tthis.self._handleFor.call(this, payload, null, true, null);\n\t\t\t}\n\n\t\t\t// Range form.\n\t\t\telse if (this.self._hasRangeRe.test(argsStr)) {\n\t\t\t\tconst parts = argsStr.match(this.self._rangeRe);\n\n\t\t\t\tif (parts === null) {\n\t\t\t\t\treturn this.error('invalid range form syntax, format: [index ,] value range collection');\n\t\t\t\t}\n\n\t\t\t\tthis.self._handleForRange.call(\n\t\t\t\t\tthis,\n\t\t\t\t\tpayload,\n\t\t\t\t\t{ type : parts[1], name : parts[2] },\n\t\t\t\t\t{ type : parts[3], name : parts[4] },\n\t\t\t\t\tparts[5]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Conditional forms.\n\t\t\telse {\n\t\t\t\tlet init;\n\t\t\t\tlet condition;\n\t\t\t\tlet post;\n\n\t\t\t\t// Conditional-only form.\n\t\t\t\tif (argsStr.indexOf(';') === -1) {\n\t\t\t\t\t// Sanity checks.\n\t\t\t\t\tif (/^\\S+\\s+in\\s+\\S+/i.test(argsStr)) {\n\t\t\t\t\t\treturn this.error('invalid syntax, for…in is not supported; see: for…range');\n\t\t\t\t\t}\n\t\t\t\t\telse if (/^\\S+\\s+of\\s+\\S+/i.test(argsStr)) {\n\t\t\t\t\t\treturn this.error('invalid syntax, for…of is not supported; see: for…range');\n\t\t\t\t\t}\n\n\t\t\t\t\tcondition = argsStr;\n\t\t\t\t}\n\n\t\t\t\t// 3-part conditional form.\n\t\t\t\telse {\n\t\t\t\t\tconst parts = argsStr.match(this.self._3PartRe);\n\n\t\t\t\t\tif (parts === null) {\n\t\t\t\t\t\treturn this.error('invalid 3-part conditional form syntax, format: [init] ; [condition] ; [post]');\n\t\t\t\t\t}\n\n\t\t\t\t\tinit      = parts[1];\n\t\t\t\t\tcondition = parts[2].trim();\n\t\t\t\t\tpost      = parts[3];\n\n\t\t\t\t\tif (condition.length === 0) {\n\t\t\t\t\t\tcondition = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis.self._handleFor.call(this, payload, init, condition, post);\n\t\t\t}\n\t\t},\n\n\t\t_handleFor(payload, init, condition, post) {\n\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\tlet first  = true;\n\t\t\tlet safety = Config.macros.maxLoopIterations;\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tTempState.break = null;\n\n\t\t\t\tif (init) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tevalJavaScript(init);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn this.error(`bad init expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\twhile (evalJavaScript(condition)) {\n\t\t\t\t\tif (--safety < 0) {\n\t\t\t\t\t\treturn this.error(`exceeded configured maximum loop iterations (${Config.macros.maxLoopIterations})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tnew Wikifier(this.output, first ? payload.replace(/^\\n/, '') : payload);\n\n\t\t\t\t\tif (first) {\n\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tif (TempState.break === 1) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (TempState.break === 2) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (post) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tevalJavaScript(post);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\treturn this.error(`bad post expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad conditional expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tTempState.break = null;\n\t\t\t}\n\t\t},\n\n\t\t_handleForRange(payload, indexVar, valueVar, rangeExp) {\n\t\t\tlet first     = true;\n\t\t\tlet rangeList;\n\n\t\t\ttry {\n\t\t\t\trangeList = this.self._toRangeList(rangeExp);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(ex.message);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tTempState.break = null;\n\n\t\t\t\tfor (let i = 0; i < rangeList.length; ++i) {\n\t\t\t\t\tif (indexVar.name) {\n\t\t\t\t\t\tState[indexVar.type][indexVar.name] = rangeList[i][0];\n\t\t\t\t\t}\n\n\t\t\t\t\tState[valueVar.type][valueVar.name] = rangeList[i][1];\n\n\t\t\t\t\tnew Wikifier(this.output, first ? payload.replace(/^\\n/, '') : payload);\n\n\t\t\t\t\tif (first) {\n\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tif (TempState.break === 1) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (TempState.break === 2) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tTempState.break = null;\n\t\t\t}\n\t\t},\n\n\t\t_toRangeList(rangeExp) {\n\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\tlet value;\n\n\t\t\ttry {\n\t\t\t\t/*\n\t\t\t\t\tNOTE: If the first character is the left curly brace, then we\n\t\t\t\t\tassume that it's part of an object literal and wrap it within\n\t\t\t\t\tparenthesis to ensure that it is not mistaken for a block\n\t\t\t\t\tduring evaluation—which would cause an error.\n\t\t\t\t*/\n\t\t\t\tvalue = evalJavaScript(rangeExp[0] === '{' ? `(${rangeExp})` : rangeExp);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tif (typeof ex !== 'object') {\n\t\t\t\t\tthrow new Error(`bad range expression: ${ex}`);\n\t\t\t\t}\n\n\t\t\t\tex.message = `bad range expression: ${ex.message}`;\n\t\t\t\tthrow ex;\n\t\t\t}\n\n\t\t\tlet list;\n\n\t\t\tswitch (typeof value) {\n\t\t\tcase 'string':\n\t\t\t\tlist = [];\n\t\t\t\tfor (let i = 0; i < value.length; /* empty */) {\n\t\t\t\t\tconst obj = Util.charAndPosAt(value, i);\n\t\t\t\t\tlist.push([i, obj.char]);\n\t\t\t\t\ti = 1 + obj.end;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'object':\n\t\t\t\tif (Array.isArray(value)) {\n\t\t\t\t\tlist = value.map((val, i) => [i, val]);\n\t\t\t\t}\n\t\t\t\telse if (value instanceof Set) {\n\t\t\t\t\tlist = [...value].map((val, i) => [i, val]);\n\t\t\t\t}\n\t\t\t\telse if (value instanceof Map) {\n\t\t\t\t\tlist = [...value.entries()];\n\t\t\t\t}\n\t\t\t\telse if (Util.toStringTag(value) === 'Object') {\n\t\t\t\t\tlist = Object.keys(value).map(key => [key, value[key]]);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new Error(`unsupported range expression type: ${Util.toStringTag(value)}`);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unsupported range expression type: ${typeof value}`);\n\t\t\t}\n\n\t\t\treturn list;\n\t\t}\n\t});\n\tMacro.add(['break', 'continue'], {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.contextHas(ctx => ctx.name === 'for')) {\n\t\t\t\tTempState.break = this.name === 'continue' ? 1 : 2;\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn this.error('must only be used in conjunction with its parent macro <<for>>');\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tInteractive Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<button>> & <<link>>\n\t*/\n\tMacro.add(['button', 'link'], {\n\t\tisAsync : true,\n\t\ttags    : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error(`no ${this.name === 'button' ? 'button' : 'link'} text specified`);\n\t\t\t}\n\n\t\t\tconst $link = jQuery(document.createElement(this.name === 'button' ? 'button' : 'a'));\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\tconst $image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t.attr('src', this.args[0].source)\n\t\t\t\t\t\t.appendTo($link);\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t}\n\n\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t$link.append(document.createTextNode(this.args[0].text));\n\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the link text.\n\t\t\t\t$link.wikiWithOptions({ profile : 'core' }, this.args[0]);\n\t\t\t\tpassage = this.args.length > 1 ? this.args[1] : undefined;\n\t\t\t}\n\n\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t$link.attr('data-passage', passage);\n\n\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t$link.addClass('link-internal');\n\n\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t$link.addClass('link-visited');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$link.addClass('link-broken');\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$link.addClass('link-internal');\n\t\t\t}\n\n\t\t\t$link\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tnamespace : '.macros',\n\t\t\t\t\tone       : passage != null // lazy equality for null\n\t\t\t\t}, this.createShadowWrapper(\n\t\t\t\t\tthis.payload[0].contents !== ''\n\t\t\t\t\t\t? () => Wikifier.wikifyEval(this.payload[0].contents.trim())\n\t\t\t\t\t\t: null,\n\t\t\t\t\tpassage != null // lazy equality for null\n\t\t\t\t\t\t? () => Engine.play(passage)\n\t\t\t\t\t\t: null\n\t\t\t\t))\n\t\t\t\t.appendTo(this.output);\n\t\t}\n\t});\n\n\t/*\n\t\t<<checkbox>>\n\t*/\n\tMacro.add('checkbox', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 3) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('unchecked value'); }\n\t\t\t\tif (this.args.length < 3) { errors.push('checked value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst uncheckValue = this.args[1];\n\t\t\tconst checkValue   = this.args[2];\n\t\t\tconst el           = document.createElement('input');\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'checkbox',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.checked ? checkValue : uncheckValue);\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and input element to the appropriate value and state, as requested.\n\t\t\t*/\n\t\t\tif (this.args.length > 3 && this.args[3] === 'checked') {\n\t\t\t\tel.checked = true;\n\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tState.setVar(varName, uncheckValue);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<cycle>>, <<listbox>>, <<option>>, & <<optionsfrom>>\n\t*/\n\tMacro.add(['cycle', 'listbox'], {\n\t\tisAsync  : true,\n\t\tskipArgs : ['optionsfrom'],\n\t\ttags     : ['option', 'optionsfrom'],\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no variable name specified');\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId = Util.slugify(varName);\n\t\t\tconst len   = this.payload.length;\n\n\t\t\tif (len === 1) {\n\t\t\t\treturn this.error('no options specified');\n\t\t\t}\n\n\t\t\tconst autoselect = this.args.length > 1 && this.args[1] === 'autoselect';\n\t\t\tconst options    = [];\n\t\t\tconst tagCount   = { option : 0, optionsfrom : 0 };\n\t\t\tlet selectedIdx = -1;\n\n\t\t\t// Get the options and selected index, if any.\n\t\t\tfor (let i = 1; i < len; ++i) {\n\t\t\t\tconst payload = this.payload[i];\n\n\t\t\t\t// <<option label value [selected]>>\n\t\t\t\tif (payload.name === 'option') {\n\t\t\t\t\t++tagCount.option;\n\n\t\t\t\t\tif (payload.args.length === 0) {\n\t\t\t\t\t\treturn this.error(`no arguments specified for <<${payload.name}>> (#${tagCount.option})`);\n\t\t\t\t\t}\n\n\t\t\t\t\toptions.push({\n\t\t\t\t\t\tlabel : String(payload.args[0]),\n\t\t\t\t\t\tvalue : payload.args.length === 1 ? payload.args[0] : payload.args[1]\n\t\t\t\t\t});\n\n\t\t\t\t\tif (payload.args.length > 2 && payload.args[2] === 'selected') {\n\t\t\t\t\t\tif (autoselect) {\n\t\t\t\t\t\t\treturn this.error('cannot specify both the autoselect and selected keywords');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (selectedIdx !== -1) {\n\t\t\t\t\t\t\treturn this.error(`multiple selected keywords specified for <<${payload.name}>> (#${selectedIdx + 1} & #${tagCount.option})`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tselectedIdx = options.length - 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// <<optionsfrom expression>>\n\t\t\t\telse {\n\t\t\t\t\t++tagCount.optionsfrom;\n\n\t\t\t\t\tif (payload.args.full.length === 0) {\n\t\t\t\t\t\treturn this.error(`no expression specified for <<${payload.name}>> (#${tagCount.optionsfrom})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: If the first character is the left curly brace, then we\n\t\t\t\t\t\t\tassume that it's part of an object literal and wrap it within\n\t\t\t\t\t\t\tparenthesis to ensure that it is not mistaken for a block\n\t\t\t\t\t\t\tduring evaluation—which would cause an error.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tconst exp = payload.args.full;\n\t\t\t\t\t\tresult = Scripting.evalJavaScript(exp[0] === '{' ? `(${exp})` : exp);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (typeof result !== 'object' || result === null) {\n\t\t\t\t\t\treturn this.error(`expression must yield a supported collection or generic object (type: ${result === null ? 'null' : typeof result})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (result instanceof Array || result instanceof Set) {\n\t\t\t\t\t\tresult.forEach(val => options.push({ label : String(val), value : val }));\n\t\t\t\t\t}\n\t\t\t\t\telse if (result instanceof Map) {\n\t\t\t\t\t\tresult.forEach((val, key) => options.push({ label : String(key), value : val }));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tconst oType = Util.toStringTag(result);\n\n\t\t\t\t\t\tif (oType !== 'Object') {\n\t\t\t\t\t\t\treturn this.error(`expression must yield a supported collection or generic object (object type: ${oType})`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tObject.keys(result).forEach(key => options.push({ label : key, value : result[key] }));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// No options were selected by the user, so we must select one.\n\t\t\tif (selectedIdx === -1) {\n\t\t\t\t// Attempt to automatically select an option by matching the variable's current value.\n\t\t\t\tif (autoselect) {\n\t\t\t\t\t// NOTE: This will usually fail for objects due to a variety of reasons.\n\t\t\t\t\tconst sameValueZero = Util.sameValueZero;\n\t\t\t\t\tconst curValue      = State.getVar(varName);\n\t\t\t\t\tconst curValueIdx   = options.findIndex(opt => sameValueZero(opt.value, curValue));\n\t\t\t\t\tselectedIdx = curValueIdx === -1 ? 0 : curValueIdx;\n\t\t\t\t}\n\n\t\t\t\t// Simply select the first option.\n\t\t\t\telse {\n\t\t\t\t\tselectedIdx = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set up and append the appropriate element to the output buffer.\n\t\t\tif (this.name === 'cycle') {\n\t\t\t\tlet cycleIdx = selectedIdx;\n\t\t\t\tjQuery(document.createElement('a'))\n\t\t\t\t\t.wikiWithOptions({ profile : 'core' }, options[selectedIdx].label)\n\t\t\t\t\t.attr('id', `${this.name}-${varId}`)\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.ariaClick({ namespace : '.macros' }, this.createShadowWrapper(function () {\n\t\t\t\t\t\tcycleIdx = (cycleIdx + 1) % options.length;\n\t\t\t\t\t\t$(this).empty().wikiWithOptions({ profile : 'core' }, options[cycleIdx].label);\n\t\t\t\t\t\tState.setVar(varName, options[cycleIdx].value);\n\t\t\t\t\t}))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\t\t\telse { // this.name === 'listbox'\n\t\t\t\tconst $select = jQuery(document.createElement('select'));\n\n\t\t\t\toptions.forEach((opt, i) => {\n\t\t\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t\t\t.val(i)\n\t\t\t\t\t\t.text(opt.label)\n\t\t\t\t\t\t.appendTo($select);\n\t\t\t\t});\n\n\t\t\t\t$select\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t\t})\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.val(selectedIdx)\n\t\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\t\tState.setVar(varName, options[Number(this.value)].value);\n\t\t\t\t\t}))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\n\t\t\t// Set the variable to the appropriate value, as requested.\n\t\t\tState.setVar(varName, options[selectedIdx].value);\n\t\t}\n\t});\n\n\t/*\n\t\t<<linkappend>>, <<linkprepend>>, & <<linkreplace>>\n\t*/\n\tMacro.add(['linkappend', 'linkprepend', 'linkreplace'], {\n\t\tisAsync : true,\n\t\ttags    : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no link text specified');\n\t\t\t}\n\n\t\t\tconst $link      = jQuery(document.createElement('a'));\n\t\t\tconst $insert    = jQuery(document.createElement('span'));\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\n\t\t\t$link\n\t\t\t\t.wikiWithOptions({ profile : 'core' }, this.args[0])\n\t\t\t\t.addClass(`link-internal macro-${this.name}`)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tnamespace : '.macros',\n\t\t\t\t\tone       : true\n\t\t\t\t}, this.createShadowWrapper(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tif (this.name === 'linkreplace') {\n\t\t\t\t\t\t\t$link.remove();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t$link\n\t\t\t\t\t\t\t\t.wrap(`<span class=\"macro-${this.name}\"></span>`)\n\t\t\t\t\t\t\t\t.replaceWith(() => $link.html());\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.payload[0].contents !== '') {\n\t\t\t\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\t\t\t\tnew Wikifier(frag, this.payload[0].contents);\n\t\t\t\t\t\t\t$insert.append(frag);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (transition) {\n\t\t\t\t\t\t\tsetTimeout(() => $insert.removeClass(`macro-${this.name}-in`), Engine.minDomActionDelay);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t$insert.addClass(`macro-${this.name}-insert`);\n\n\t\t\tif (transition) {\n\t\t\t\t$insert.addClass(`macro-${this.name}-in`);\n\t\t\t}\n\n\t\t\tif (this.name === 'linkprepend') {\n\t\t\t\t$insert.insertBefore($link);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$insert.insertAfter($link);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<radiobutton>>\n\t*/\n\tMacro.add('radiobutton', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('checked value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId      = Util.slugify(varName);\n\t\t\tconst checkValue = this.args[1];\n\t\t\tconst el         = document.createElement('input');\n\n\t\t\t/*\n\t\t\t\tSet up and initialize the group counter.\n\t\t\t*/\n\t\t\tif (!TempState.hasOwnProperty(this.name)) {\n\t\t\t\tTempState[this.name] = {};\n\t\t\t}\n\n\t\t\tif (!TempState[this.name].hasOwnProperty(varId)) {\n\t\t\t\tTempState[this.name][varId] = 0;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}-${TempState[this.name][varId]++}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'radio',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tif (this.checked) {\n\t\t\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable to the checked value and the input element to checked, if requested.\n\t\t\t*/\n\t\t\tif (this.args.length > 2 && this.args[2] === 'checked') {\n\t\t\t\tel.checked = true;\n\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<textarea>>\n\t*/\n\tMacro.add('textarea', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('default value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst defaultValue = this.args[1];\n\t\t\tconst autofocus    = this.args[2] === 'autofocus';\n\t\t\tconst el           = document.createElement('textarea');\n\n\t\t\t/*\n\t\t\t\tSet up and append the textarea element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\trows     : 4,\n\t\t\t\t\t// cols     : 68, // instead of setting \"cols\" we set the `min-width` in CSS\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.value);\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and textarea element to the default value.\n\t\t\t*/\n\t\t\tState.setVar(varName, defaultValue);\n\t\t\t// Ideally, we should be setting `.defaultValue` here, but IE doesn't support it,\n\t\t\t// so we have to use `.textContent`, which is equivalent.\n\t\t\tel.textContent = defaultValue;\n\n\t\t\t/*\n\t\t\t\tAutofocus the textarea element, if requested.\n\t\t\t*/\n\t\t\tif (autofocus) {\n\t\t\t\t// Set the element's \"autofocus\" attribute.\n\t\t\t\tel.setAttribute('autofocus', 'autofocus');\n\n\t\t\t\t// Set up a single-use post-display task to autofocus the element.\n\t\t\t\tpostdisplay[`#autofocus:${el.id}`] = task => {\n\t\t\t\t\tdelete postdisplay[task]; // single-use task\n\t\t\t\t\tsetTimeout(() => el.focus(), Engine.minDomActionDelay);\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<textbox>>\n\t*/\n\tMacro.add('textbox', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('default value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst defaultValue = this.args[1];\n\t\t\tconst el           = document.createElement('input');\n\t\t\tlet autofocus = false;\n\t\t\tlet passage;\n\n\t\t\tif (this.args.length > 3) {\n\t\t\t\tpassage   = this.args[2];\n\t\t\t\tautofocus = this.args[3] === 'autofocus';\n\t\t\t}\n\t\t\telse if (this.args.length > 2) {\n\t\t\t\tif (this.args[2] === 'autofocus') {\n\t\t\t\t\tautofocus = true;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tpassage = this.args[2];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (typeof passage === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = passage.link;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'text',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.value);\n\t\t\t\t}))\n\t\t\t\t.on('keypress.macros', this.createShadowWrapper(function (ev) {\n\t\t\t\t\t// If Return/Enter is pressed, set the variable and, optionally, forward to another passage.\n\t\t\t\t\tif (ev.which === 13) { // 13 is Return/Enter\n\t\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t\tState.setVar(varName, this.value);\n\n\t\t\t\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and input element to the default value.\n\t\t\t*/\n\t\t\tState.setVar(varName, defaultValue);\n\t\t\tel.value = defaultValue;\n\n\t\t\t/*\n\t\t\t\tAutofocus the input element, if requested.\n\t\t\t*/\n\t\t\tif (autofocus) {\n\t\t\t\t// Set the element's \"autofocus\" attribute.\n\t\t\t\tel.setAttribute('autofocus', 'autofocus');\n\n\t\t\t\t// Set up a single-use post-display task to autofocus the element.\n\t\t\t\tpostdisplay[`#autofocus:${el.id}`] = task => {\n\t\t\t\t\tdelete postdisplay[task]; // single-use task\n\t\t\t\t\tsetTimeout(() => el.focus(), Engine.minDomActionDelay);\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] <<click>>\n\t*/\n\tMacro.add('click', 'link'); // add <<click>> as an alias of <<link>>\n\n\n\t/*******************************************************************************************************************\n\t\tLinks Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<actions>>\n\t*/\n\tMacro.add('actions', {\n\t\thandler() {\n\t\t\tconst $list = jQuery(document.createElement('ul'))\n\t\t\t\t.addClass(this.name)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\tfor (let i = 0; i < this.args.length; ++i) {\n\t\t\t\tlet passage;\n\t\t\t\tlet text;\n\t\t\t\tlet $image;\n\t\t\t\tlet setFn;\n\n\t\t\t\tif (typeof this.args[i] === 'object') {\n\t\t\t\t\tif (this.args[i].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[i].source);\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[i].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[i].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[i].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tpassage = this.args[i].link;\n\t\t\t\t\t\tsetFn   = this.args[i].setFn;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\ttext    = this.args[i].text;\n\t\t\t\t\t\tpassage = this.args[i].link;\n\t\t\t\t\t\tsetFn   = this.args[i].setFn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\ttext = passage = this.args[i];\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\t   State.variables.hasOwnProperty('#actions')\n\t\t\t\t\t&& State.variables['#actions'].hasOwnProperty(passage)\n\t\t\t\t\t&& State.variables['#actions'][passage]\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tjQuery(Wikifier.createInternalLink(\n\t\t\t\t\tjQuery(document.createElement('li')).appendTo($list),\n\t\t\t\t\tpassage,\n\t\t\t\t\tnull,\n\t\t\t\t\t((passage, fn) => () => {\n\t\t\t\t\t\tif (!State.variables.hasOwnProperty('#actions')) {\n\t\t\t\t\t\t\tState.variables['#actions'] = {};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tState.variables['#actions'][passage] = true;\n\n\t\t\t\t\t\tif (typeof fn === 'function') {\n\t\t\t\t\t\t\tfn();\n\t\t\t\t\t\t}\n\t\t\t\t\t})(passage, setFn)\n\t\t\t\t))\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.append($image || document.createTextNode(text));\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<back>> & <<return>>\n\t*/\n\tMacro.add(['back', 'return'], {\n\t\thandler() {\n\t\t\t/* legacy */\n\t\t\tif (this.args.length > 1) {\n\t\t\t\treturn this.error('too many arguments specified, check the documentation for details');\n\t\t\t}\n\t\t\t/* /legacy */\n\n\t\t\tlet momentIndex = -1;\n\t\t\tlet passage;\n\t\t\tlet text;\n\t\t\tlet $image;\n\n\t\t\tif (this.args.length === 1) {\n\t\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[0].source);\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('link')) {\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\tif (this.args[0].count === 1) {\n\t\t\t\t\t\t\t// Simple link syntax: `[[...]]`.\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Pretty link syntax: `[[...|...]]`.\n\t\t\t\t\t\t\ttext    = this.args[0].text;\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (this.args.length === 1) {\n\t\t\t\t\t// Argument was simply the link text.\n\t\t\t\t\ttext = this.args[0];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\t/*\n\t\t\t\t\tFind the index and title of the most recent moment whose title does not match\n\t\t\t\t\tthat of the active (present) moment's.\n\t\t\t\t*/\n\t\t\t\tfor (let i = State.length - 2; i >= 0; --i) {\n\t\t\t\t\tif (State.history[i].title !== State.passage) {\n\t\t\t\t\t\tmomentIndex = i;\n\t\t\t\t\t\tpassage = State.history[i].title;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If we failed to find a passage and we're `<<return>>`, fallback to `State.expired`.\n\t\t\t\tif (passage == null && this.name === 'return') { // lazy equality for null\n\t\t\t\t\tfor (let i = State.expired.length - 1; i >= 0; --i) {\n\t\t\t\t\t\tif (State.expired[i] !== State.passage) {\n\t\t\t\t\t\t\tpassage = State.expired[i];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (!Story.has(passage)) {\n\t\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tif (this.name === 'back') {\n\t\t\t\t\t/*\n\t\t\t\t\t\tFind the index of the most recent moment whose title matches that of the\n\t\t\t\t\t\tspecified passage.\n\t\t\t\t\t*/\n\t\t\t\t\tfor (let i = State.length - 2; i >= 0; --i) {\n\t\t\t\t\t\tif (State.history[i].title === passage) {\n\t\t\t\t\t\t\tmomentIndex = i;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (momentIndex === -1) {\n\t\t\t\t\t\treturn this.error(`cannot find passage \"${passage}\" in the current story history`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn this.error('cannot find passage');\n\t\t\t}\n\n\t\t\t// if (this.name === \"back\" && momentIndex === -1) {\n\t\t\t// \t// no-op; we're already at the first passage in the current story history\n\t\t\t// \treturn;\n\t\t\t// }\n\n\t\t\tlet $el;\n\n\t\t\tif (this.name !== 'back' || momentIndex !== -1) {\n\t\t\t\t$el = jQuery(document.createElement('a'))\n\t\t\t\t\t.addClass('link-internal')\n\t\t\t\t\t.ariaClick(\n\t\t\t\t\t\t{ one : true },\n\t\t\t\t\t\tthis.name === 'return'\n\t\t\t\t\t\t\t? () => Engine.play(passage)\n\t\t\t\t\t\t\t: () => Engine.goTo(momentIndex)\n\t\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$el = jQuery(document.createElement('span'))\n\t\t\t\t\t.addClass('link-disabled');\n\t\t\t}\n\n\t\t\t$el\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.append($image || document.createTextNode(text || L10n.get(`macro${this.name.toUpperFirst()}Text`)))\n\t\t\t\t.appendTo(this.output);\n\t\t}\n\t});\n\n\t/*\n\t\t<<choice>>\n\t*/\n\tMacro.add('choice', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tconst choiceId = State.passage;\n\t\t\tlet passage;\n\t\t\tlet text;\n\t\t\tlet $image;\n\t\t\tlet setFn;\n\n\t\t\tif (this.args.length === 1) {\n\t\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[0].source);\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\tsetFn   = this.args[0].setFn;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\ttext    = this.args[0].text;\n\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\tsetFn   = this.args[0].setFn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\ttext = passage = this.args[0];\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// NOTE: The arguments here are backwards.\n\t\t\t\tpassage = this.args[0];\n\t\t\t\ttext    = this.args[1];\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t   State.variables.hasOwnProperty('#choice')\n\t\t\t\t&& State.variables['#choice'].hasOwnProperty(choiceId)\n\t\t\t\t&& State.variables['#choice'][choiceId]\n\t\t\t) {\n\t\t\t\tjQuery(document.createElement('span'))\n\t\t\t\t\t.addClass(`link-disabled macro-${this.name}`)\n\t\t\t\t\t.attr('tabindex', -1)\n\t\t\t\t\t.append($image || document.createTextNode(text))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tjQuery(Wikifier.createInternalLink(this.output, passage, null, () => {\n\t\t\t\tif (!State.variables.hasOwnProperty('#choice')) {\n\t\t\t\t\tState.variables['#choice'] = {};\n\t\t\t\t}\n\n\t\t\t\tState.variables['#choice'][choiceId] = true;\n\n\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\tsetFn();\n\t\t\t\t}\n\t\t\t}))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.append($image || document.createTextNode(text));\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tDOM Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<addclass>> & <<toggleclass>>\n\t*/\n\tMacro.add(['addclass', 'toggleclass'], {\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('selector'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('class names'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tswitch (this.name) {\n\t\t\tcase 'addclass':\n\t\t\t\t$targets.addClass(this.args[1].trim());\n\t\t\t\tbreak;\n\n\t\t\tcase 'toggleclass':\n\t\t\t\t$targets.toggleClass(this.args[1].trim());\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<removeclass>>\n\t*/\n\tMacro.add('removeclass', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tif (this.args.length > 1) {\n\t\t\t\t$targets.removeClass(this.args[1].trim());\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$targets.removeClass();\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<copy>>\n\t*/\n\tMacro.add('copy', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tjQuery(this.output).append($targets.html());\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<append>>, <<prepend>>, & <<replace>>\n\t*/\n\tMacro.add(['append', 'prepend', 'replace'], {\n\t\ttags : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tif (this.payload[0].contents !== '') {\n\t\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\t\tlet $insert;\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$insert = jQuery(document.createElement('span'));\n\t\t\t\t\t$insert.addClass(`macro-${this.name}-insert macro-${this.name}-in`);\n\t\t\t\t\tsetTimeout(() => $insert.removeClass(`macro-${this.name}-in`), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$insert = jQuery(document.createDocumentFragment());\n\t\t\t\t}\n\n\t\t\t\t$insert.wiki(this.payload[0].contents);\n\n\t\t\t\tswitch (this.name) {\n\t\t\t\tcase 'replace':\n\t\t\t\t\t$targets.empty();\n\t\t\t\t\t/* falls through */\n\n\t\t\t\tcase 'append':\n\t\t\t\t\t$targets.append($insert);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'prepend':\n\t\t\t\t\t$targets.prepend($insert);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (this.name === 'replace') {\n\t\t\t\t$targets.empty();\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<remove>>\n\t*/\n\tMacro.add('remove', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\t$targets.remove();\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAudio Macros.\n\t*******************************************************************************************************************/\n\tif (Has.audio) {\n\t\tconst errorOnePlaybackAction = (cur, prev) => `only one playback action allowed per invocation, \"${cur}\" cannot be combined with \"${prev}\"`;\n\n\t\t/*\n\t\t\t<<audio>>\n\t\t*/\n\t\tMacro.add('audio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\tconst errors = [];\n\t\t\t\t\tif (this.args.length < 1) { errors.push('track and/or group IDs'); }\n\t\t\t\t\tif (this.args.length < 2) { errors.push('actions'); }\n\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t}\n\n\t\t\t\tlet selected;\n\n\t\t\t\t// Process the track and/or group IDs.\n\t\t\t\ttry {\n\t\t\t\t\tselected = SimpleAudio.select(this.args[0]);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\tconst args = this.args.slice(1);\n\t\t\t\tlet action;\n\t\t\t\tlet fadeOver = 5;\n\t\t\t\tlet fadeTo;\n\t\t\t\tlet loop;\n\t\t\t\tlet mute;\n\t\t\t\tlet passage;\n\t\t\t\tlet time;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\tcase 'play':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadein':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 1;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeout':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 0;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('fadeto missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeoverto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length < 2) {\n\t\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\t\tif (args.length < 1) { errors.push('seconds'); }\n\t\t\t\t\t\t\tif (args.length < 2) { errors.push('level'); }\n\t\t\t\t\t\t\treturn this.error(`fadeoverto missing required ${errors.join(' and ')} value${errors.length > 1 ? 's' : ''}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeOver = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeOver) || !Number.isFinite(fadeOver)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'time':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('time missing required seconds value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\ttime = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(time) || !Number.isFinite(time)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse time: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'loop':\n\t\t\t\t\tcase 'unloop':\n\t\t\t\t\t\tloop = arg === 'loop';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'goto':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('goto missing required passage title');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\n\t\t\t\t\t\tif (typeof raw === 'object') {\n\t\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\t\tpassage = raw.link;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\t\t\tpassage = raw;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!Story.has(passage)) {\n\t\t\t\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tselected.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (time != null) { // lazy equality for null\n\t\t\t\t\t\tselected.time(time);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tselected.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (loop != null) { // lazy equality for null\n\t\t\t\t\t\tselected.loop(loop);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t\t\tconst nsEnded = `ended.macros.macro-${this.name}_goto`;\n\t\t\t\t\t\tselected\n\t\t\t\t\t\t\t.off(nsEnded)\n\t\t\t\t\t\t\t.one(nsEnded, () => {\n\t\t\t\t\t\t\t\tselected.off(nsEnded);\n\t\t\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'fade':\n\t\t\t\t\t\tselected.fade(fadeOver, fadeTo);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tselected.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\t\tselected.pause();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'play':\n\t\t\t\t\t\tselected.playWhenAllowed();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tselected.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tselected.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<cacheaudio track_id source_list>>\n\t\t*/\n\t\tMacro.add('cacheaudio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\tconst errors = [];\n\t\t\t\t\tif (this.args.length < 1) { errors.push('track ID'); }\n\t\t\t\t\tif (this.args.length < 2) { errors.push('sources'); }\n\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t}\n\n\t\t\t\tconst id       = String(this.args[0]).trim();\n\t\t\t\tconst oldFmtRe = /^format:\\s*([\\w-]+)\\s*;\\s*/i;\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.tracks.add(id, this.args.slice(1).map(source => {\n\t\t\t\t\t\t/* legacy */\n\t\t\t\t\t\t// Transform an old format specifier into the new style.\n\t\t\t\t\t\tif (oldFmtRe.test(source)) {\n\t\t\t\t\t\t\t// If in Test Mode, return an error.\n\t\t\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\t\t\treturn this.error(`track ID \"${id}\": format specifier migration required, \"format:formatId;\" \\u2192 \"formatId|\"`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tsource = source.replace(oldFmtRe, '$1|'); // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn source;\n\t\t\t\t\t\t/* /legacy */\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// If in Test Mode and no supported sources were specified, return an error.\n\t\t\t\tif (Config.debug && !SimpleAudio.tracks.get(id).hasSource()) {\n\t\t\t\t\treturn this.error(`track ID \"${id}\": no supported audio sources found`);\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<createaudiogroup group_id>>\n\t\t\t\t<<track track_id>>\n\t\t\t\t…\n\t\t\t<</createaudiogroup>>\n\t\t*/\n\t\tMacro.add('createaudiogroup', {\n\t\t\ttags : ['track'],\n\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no group ID specified');\n\t\t\t\t}\n\n\t\t\t\tif (this.payload.length === 1) {\n\t\t\t\t\treturn this.error('no tracks defined via <<track>>');\n\t\t\t\t}\n\n\t\t\t\t// Initial debug view setup for `<<createaudiogroup>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst groupId  = String(this.args[0]).trim();\n\t\t\t\tconst trackIds = [];\n\n\t\t\t\tfor (let i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\tif (this.payload[i].args.length < 1) {\n\t\t\t\t\t\treturn this.error('no track ID specified');\n\t\t\t\t\t}\n\n\t\t\t\t\ttrackIds.push(String(this.payload[i].args[0]).trim());\n\n\t\t\t\t\t// Custom debug view setup for the current `<<track>>`.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.groups.add(groupId, trackIds);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Custom fake debug view setup for `<</createaudiogroup>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<createplaylist list_id>>\n\t\t\t\t<<track track_id action_list>>\n\t\t\t\t…\n\t\t\t<</createplaylist>>\n\t\t*/\n\t\tMacro.add('createplaylist', {\n\t\t\ttags : ['track'],\n\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no list ID specified');\n\t\t\t\t}\n\n\t\t\t\tif (this.payload.length === 1) {\n\t\t\t\t\treturn this.error('no tracks defined via <<track>>');\n\t\t\t\t}\n\n\t\t\t\tconst playlist = Macro.get('playlist');\n\n\t\t\t\tif (playlist.from !== null && playlist.from !== 'createplaylist') {\n\t\t\t\t\treturn this.error('a playlist has already been defined with <<setplaylist>>');\n\t\t\t\t}\n\n\t\t\t\t// Initial debug view setup for `<<createplaylist>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst listId    = String(this.args[0]).trim();\n\t\t\t\tconst trackObjs = [];\n\n\t\t\t\tfor (let i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\tif (this.payload[i].args.length === 0) {\n\t\t\t\t\t\treturn this.error('no track ID specified');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst trackObj = { id : String(this.payload[i].args[0]).trim() };\n\t\t\t\t\tconst args     = this.payload[i].args.slice(1);\n\n\t\t\t\t\t// Process arguments.\n\t\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\t\tlet raw;\n\t\t\t\t\t\tlet parsed;\n\n\t\t\t\t\t\tswitch (arg) {\n\t\t\t\t\t\tcase 'copy': // [DEPRECATED]\n\t\t\t\t\t\tcase 'own':\n\t\t\t\t\t\t\ttrackObj.own = true;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'rate':\n\t\t\t\t\t\t\t// if (args.length === 0) {\n\t\t\t\t\t\t\t// \treturn this.error('rate missing required speed value');\n\t\t\t\t\t\t\t// }\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// raw = args.shift();\n\t\t\t\t\t\t\t// parsed = Number.parseFloat(raw);\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// if (Number.isNaN(parsed) || !Number.isFinite(parsed)) {\n\t\t\t\t\t\t\t// \treturn this.error(`cannot parse rate: ${raw}`);\n\t\t\t\t\t\t\t// }\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// trackObj.rate = parsed;\n\t\t\t\t\t\t\tif (args.length > 0) {\n\t\t\t\t\t\t\t\targs.shift();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\t\tparsed = Number.parseFloat(raw);\n\n\t\t\t\t\t\t\tif (Number.isNaN(parsed) || !Number.isFinite(parsed)) {\n\t\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ttrackObj.volume = parsed;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\ttrackObjs.push(trackObj);\n\n\t\t\t\t\t// Custom debug view setup for the current `<<track>>`.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.lists.add(listId, trackObjs);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Lock `<<playlist>>` into our syntax.\n\t\t\t\tif (playlist.from === null) {\n\t\t\t\t\tplaylist.from = 'createplaylist';\n\t\t\t\t}\n\n\t\t\t\t// Custom fake debug view setup for `<</createplaylist>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<masteraudio action_list>>\n\t\t*/\n\t\tMacro.add('masteraudio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no actions specified');\n\t\t\t\t}\n\n\t\t\t\tconst args = this.args.slice(0);\n\t\t\t\tlet action;\n\t\t\t\tlet mute;\n\t\t\t\tlet muteOnHide;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'muteonhide':\n\t\t\t\t\tcase 'nomuteonhide':\n\t\t\t\t\t\tmuteOnHide = arg === 'muteonhide';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (muteOnHide != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.muteOnHidden(muteOnHide);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tSimpleAudio.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tSimpleAudio.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tSimpleAudio.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<playlist list_id action_list>>  ← <<createplaylist>> syntax\n\t\t\t<<playlist action_list>>          ← <<setplaylist>> syntax\n\t\t*/\n\t\tMacro.add('playlist', {\n\t\t\tfrom : null,\n\n\t\t\thandler() {\n\t\t\t\tconst from = this.self.from;\n\n\t\t\t\tif (from === null) {\n\t\t\t\t\treturn this.error('no playlists have been created');\n\t\t\t\t}\n\n\t\t\t\tlet list;\n\t\t\t\tlet args;\n\n\t\t\t\tif (from === 'createplaylist') {\n\t\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\tif (this.args.length < 1) { errors.push('list ID'); }\n\t\t\t\t\t\tif (this.args.length < 2) { errors.push('actions'); }\n\t\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\t\tif (!SimpleAudio.lists.has(id)) {\n\t\t\t\t\t\treturn this.error(`playlist \"${id}\" does not exist`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlist = SimpleAudio.lists.get(id);\n\t\t\t\t\targs = this.args.slice(1);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\t\treturn this.error('no actions specified');\n\t\t\t\t\t}\n\n\t\t\t\t\tlist = SimpleAudio.lists.get('setplaylist');\n\t\t\t\t\targs = this.args.slice(0);\n\t\t\t\t}\n\n\t\t\t\tlet action;\n\t\t\t\tlet fadeOver = 5;\n\t\t\t\tlet fadeTo;\n\t\t\t\tlet loop;\n\t\t\t\tlet mute;\n\t\t\t\tlet shuffle;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\tcase 'play':\n\t\t\t\t\tcase 'skip':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadein':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 1;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeout':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 0;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('fadeto missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeoverto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length < 2) {\n\t\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\t\tif (args.length < 1) { errors.push('seconds'); }\n\t\t\t\t\t\t\tif (args.length < 2) { errors.push('level'); }\n\t\t\t\t\t\t\treturn this.error(`fadeoverto missing required ${errors.join(' and ')} value${errors.length > 1 ? 's' : ''}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeOver = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeOver) || !Number.isFinite(fadeOver)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'loop':\n\t\t\t\t\tcase 'unloop':\n\t\t\t\t\t\tloop = arg === 'loop';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'shuffle':\n\t\t\t\t\tcase 'unshuffle':\n\t\t\t\t\t\tshuffle = arg === 'shuffle';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tlist.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tlist.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (loop != null) { // lazy equality for null\n\t\t\t\t\t\tlist.loop(loop);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (shuffle != null) { // lazy equality for null\n\t\t\t\t\t\tlist.shuffle(shuffle);\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'fade':\n\t\t\t\t\t\tlist.fade(fadeOver, fadeTo);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tlist.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\t\tlist.pause();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'play':\n\t\t\t\t\t\tlist.playWhenAllowed();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'skip':\n\t\t\t\t\t\tlist.skip();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tlist.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tlist.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<removeaudiogroup group_id>>\n\t\t*/\n\t\tMacro.add('removeaudiogroup', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no group ID specified');\n\t\t\t\t}\n\n\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\tif (!SimpleAudio.groups.has(id)) {\n\t\t\t\t\treturn this.error(`group \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tSimpleAudio.groups.delete(id);\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<removeplaylist list_id>>\n\t\t*/\n\t\tMacro.add('removeplaylist', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no list ID specified');\n\t\t\t\t}\n\n\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\tif (!SimpleAudio.lists.has(id)) {\n\t\t\t\t\treturn this.error(`playlist \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tSimpleAudio.lists.delete(id);\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<waitforaudio>>\n\t\t*/\n\t\tMacro.add('waitforaudio', {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\tSimpleAudio.loadWithScreen();\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t[DEPRECATED] <<setplaylist track_id_list>>\n\t\t*/\n\t\tMacro.add('setplaylist', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no track ID(s) specified');\n\t\t\t\t}\n\n\t\t\t\tconst playlist = Macro.get('playlist');\n\n\t\t\t\tif (playlist.from !== null && playlist.from !== 'setplaylist') {\n\t\t\t\t\treturn this.error('playlists have already been defined with <<createplaylist>>');\n\t\t\t\t}\n\n\t\t\t\t// Create the new playlist.\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.lists.add('setplaylist', this.args.slice(0));\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Lock `<<playlist>>` into our syntax.\n\t\t\t\tif (playlist.from === null) {\n\t\t\t\t\tplaylist.from = 'setplaylist';\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t[DEPRECATED] <<stopallaudio>>\n\t\t*/\n\t\tMacro.add('stopallaudio', {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\tSimpleAudio.select(':all').stop();\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\telse {\n\t\t/* The HTML5 <audio> API appears to be missing or disabled, set up no-op macros. */\n\t\tMacro.add([\n\t\t\t'audio',\n\t\t\t'cacheaudio',\n\t\t\t'createaudiogroup',\n\t\t\t'createplaylist',\n\t\t\t'masteraudio',\n\t\t\t'playlist',\n\t\t\t'removeaudiogroup',\n\t\t\t'removeplaylist',\n\t\t\t'waitforaudio',\n\n\t\t\t// Deprecated.\n\t\t\t'setplaylist',\n\t\t\t'stopallaudio'\n\t\t], {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\t/* no-op */\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMiscellaneous Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<goto>>\n\t*/\n\tMacro.add('goto', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = this.args[0].link;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the passage name.\n\t\t\t\tpassage = this.args[0];\n\t\t\t}\n\n\t\t\tif (!Story.has(passage)) {\n\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tCall `Engine.play()` asynchronously.\n\n\t\t\t\tNOTE: This does not terminate the current Wikifier call chain,\n\t\t\t\tthough, ideally, it should.  Doing so would not be trivial, however,\n\t\t\t\tand there's also the question of whether that behavior would be\n\t\t\t\tunwanted by users, who are used to the current behavior from\n\t\t\t\tsimilar macros and constructs.\n\t\t\t*/\n\t\t\tsetTimeout(() => Engine.play(passage), Engine.minDomActionDelay);\n\t\t}\n\t});\n\n\t/*\n\t\t<<repeat>> & <<stop>>\n\t*/\n\tMacro.add('repeat', {\n\t\tisAsync : true,\n\t\ttags    : null,\n\t\ttimers  : new Set(),\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no time value specified');\n\t\t\t}\n\n\t\t\tlet delay;\n\n\t\t\ttry {\n\t\t\t\tdelay = Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.args[0]));\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(ex.message);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\tconst $wrapper   = jQuery(document.createElement('span'))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t// Register the timer.\n\t\t\tthis.self.registerInterval(this.createShadowWrapper(() => {\n\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(frag, this.payload[0].contents);\n\n\t\t\t\tlet $output = $wrapper;\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$output = jQuery(document.createElement('span'))\n\t\t\t\t\t\t.addClass('macro-repeat-insert macro-repeat-in')\n\t\t\t\t\t\t.appendTo($output);\n\t\t\t\t}\n\n\t\t\t\t$output.append(frag);\n\n\t\t\t\tif (transition) {\n\t\t\t\t\tsetTimeout(() => $output.removeClass('macro-repeat-in'), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t}), delay);\n\t\t},\n\n\t\tregisterInterval(callback, delay) {\n\t\t\tif (typeof callback !== 'function') {\n\t\t\t\tthrow new TypeError('callback parameter must be a function');\n\t\t\t}\n\n\t\t\tconst turnId = State.turns;\n\t\t\tconst timers = this.timers;\n\t\t\tlet timerId = null;\n\n\t\t\t// Set up the interval.\n\t\t\ttimerId = setInterval(() => {\n\t\t\t\t// Terminate the timer if the turn IDs do not match.\n\t\t\t\tif (turnId !== State.turns) {\n\t\t\t\t\tclearInterval(timerId);\n\t\t\t\t\ttimers.delete(timerId);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet timerIdCache;\n\t\t\t\t/*\n\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t`Wikifier` call.\n\t\t\t\t*/\n\t\t\t\ttry {\n\t\t\t\t\tTempState.break = null;\n\n\t\t\t\t\t// Set up the `repeatTimerId` value, caching the existing value, if necessary.\n\t\t\t\t\tif (TempState.hasOwnProperty('repeatTimerId')) {\n\t\t\t\t\t\ttimerIdCache = TempState.repeatTimerId;\n\t\t\t\t\t}\n\n\t\t\t\t\tTempState.repeatTimerId = timerId;\n\n\t\t\t\t\t// Execute the callback.\n\t\t\t\t\tcallback.call(this);\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\t// Teardown the `repeatTimerId` property, restoring the cached value, if necessary.\n\t\t\t\t\tif (typeof timerIdCache !== 'undefined') {\n\t\t\t\t\t\tTempState.repeatTimerId = timerIdCache;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdelete TempState.repeatTimerId;\n\t\t\t\t\t}\n\n\t\t\t\t\tTempState.break = null;\n\t\t\t\t}\n\t\t\t}, delay);\n\t\t\ttimers.add(timerId);\n\n\t\t\t// Set up a single-use `prehistory` task to remove pending timers.\n\t\t\tif (!prehistory.hasOwnProperty('#repeat-timers-cleanup')) {\n\t\t\t\tprehistory['#repeat-timers-cleanup'] = task => {\n\t\t\t\t\tdelete prehistory[task]; // single-use task\n\t\t\t\t\ttimers.forEach(timerId => clearInterval(timerId));\n\t\t\t\t\ttimers.clear();\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\tMacro.add('stop', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (!TempState.hasOwnProperty('repeatTimerId')) {\n\t\t\t\treturn this.error('must only be used in conjunction with its parent macro <<repeat>>');\n\t\t\t}\n\n\t\t\tconst timers  = Macro.get('repeat').timers;\n\t\t\tconst timerId = TempState.repeatTimerId;\n\t\t\tclearInterval(timerId);\n\t\t\ttimers.delete(timerId);\n\t\t\tTempState.break = 2;\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<timed>> & <<next>>\n\t*/\n\tMacro.add('timed', {\n\t\tisAsync : true,\n\t\ttags    : ['next'],\n\t\ttimers  : new Set(),\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no time value specified in <<timed>>');\n\t\t\t}\n\n\t\t\tconst items = [];\n\n\t\t\ttry {\n\t\t\t\titems.push({\n\t\t\t\t\tname    : this.name,\n\t\t\t\t\tsource  : this.source,\n\t\t\t\t\tdelay   : Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.args[0])),\n\t\t\t\t\tcontent : this.payload[0].contents\n\t\t\t\t});\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`${ex.message} in <<timed>>`);\n\t\t\t}\n\n\t\t\tif (this.payload.length > 1) {\n\t\t\t\tlet i;\n\n\t\t\t\ttry {\n\t\t\t\t\tlet len;\n\n\t\t\t\t\tfor (i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\t\titems.push({\n\t\t\t\t\t\t\tname   : this.payload[i].name,\n\t\t\t\t\t\t\tsource : this.payload[i].source,\n\t\t\t\t\t\t\tdelay  : this.payload[i].args.length === 0\n\t\t\t\t\t\t\t\t? items[items.length - 1].delay\n\t\t\t\t\t\t\t\t: Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.payload[i].args[0])),\n\t\t\t\t\t\t\tcontent : this.payload[i].contents\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`${ex.message} in <<next>> (#${i})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\tconst $wrapper   = jQuery(document.createElement('span'))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t// Register the timer.\n\t\t\tthis.self.registerTimeout(this.createShadowWrapper(item => {\n\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(frag, item.content);\n\n\t\t\t\t// Output.\n\t\t\t\tlet $output = $wrapper;\n\n\t\t\t\t// Custom debug view setup for `<<next>>`.\n\t\t\t\tif (Config.debug && item.name === 'next') {\n\t\t\t\t\t$output = jQuery((new DebugView( // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t$output[0],\n\t\t\t\t\t\t'macro',\n\t\t\t\t\t\titem.name,\n\t\t\t\t\t\titem.source\n\t\t\t\t\t)).output);\n\t\t\t\t}\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$output = jQuery(document.createElement('span'))\n\t\t\t\t\t\t.addClass('macro-timed-insert macro-timed-in')\n\t\t\t\t\t\t.appendTo($output);\n\t\t\t\t}\n\n\t\t\t\t$output.append(frag);\n\n\t\t\t\tif (transition) {\n\t\t\t\t\tsetTimeout(() => $output.removeClass('macro-timed-in'), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t}), items);\n\t\t},\n\n\t\tregisterTimeout(callback, items) {\n\t\t\tif (typeof callback !== 'function') {\n\t\t\t\tthrow new TypeError('callback parameter must be a function');\n\t\t\t}\n\n\t\t\tconst turnId = State.turns;\n\t\t\tconst timers = this.timers;\n\t\t\tlet timerId  = null;\n\t\t\tlet nextItem = items.shift();\n\n\t\t\tconst worker = function () {\n\t\t\t\t// Bookkeeping.\n\t\t\t\ttimers.delete(timerId);\n\n\t\t\t\tif (turnId !== State.turns) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Set the current item and set up the next worker, if any.\n\t\t\t\tconst curItem = nextItem;\n\n\t\t\t\tif ((nextItem = items.shift()) != null) { // lazy equality for null\n\t\t\t\t\ttimerId = setTimeout(worker, nextItem.delay);\n\t\t\t\t\ttimers.add(timerId);\n\t\t\t\t}\n\n\t\t\t\t// Execute the callback.\n\t\t\t\tcallback.call(this, curItem);\n\t\t\t};\n\n\t\t\t// Setup the timeout.\n\t\t\ttimerId = setTimeout(worker, nextItem.delay);\n\t\t\ttimers.add(timerId);\n\n\t\t\t// Set up a single-use `prehistory` task to remove pending timers.\n\t\t\tif (!prehistory.hasOwnProperty('#timed-timers-cleanup')) {\n\t\t\t\tprehistory['#timed-timers-cleanup'] = task => {\n\t\t\t\t\tdelete prehistory[task]; // single-use task\n\t\t\t\t\ttimers.forEach(timerId => clearTimeout(timerId)); // eslint-disable-line no-shadow\n\t\t\t\t\ttimers.clear();\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<widget>>\n\t*/\n\tMacro.add('widget', {\n\t\ttags : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no widget name specified');\n\t\t\t}\n\n\t\t\tconst widgetName = this.args[0];\n\n\t\t\tif (Macro.has(widgetName)) {\n\t\t\t\tif (!Macro.get(widgetName).isWidget) {\n\t\t\t\t\treturn this.error(`cannot clobber existing macro \"${widgetName}\"`);\n\t\t\t\t}\n\n\t\t\t\t// Delete the existing widget.\n\t\t\t\tMacro.delete(widgetName);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tMacro.add(widgetName, {\n\t\t\t\t\tisWidget : true,\n\t\t\t\t\thandler  : (function (contents) {\n\t\t\t\t\t\treturn function () {\n\t\t\t\t\t\t\tlet argsCache;\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t// Cache the existing value of the `$args` variable, if necessary.\n\t\t\t\t\t\t\t\tif (State.variables.hasOwnProperty('args')) {\n\t\t\t\t\t\t\t\t\targsCache = State.variables.args;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Set up the widget `$args` variable and add a shadow.\n\t\t\t\t\t\t\t\tState.variables.args = [...this.args];\n\t\t\t\t\t\t\t\tState.variables.args.raw = this.args.raw;\n\t\t\t\t\t\t\t\tState.variables.args.full = this.args.full;\n\t\t\t\t\t\t\t\tthis.addShadow('$args');\n\n\t\t\t\t\t\t\t\t// Set up the error trapping variables.\n\t\t\t\t\t\t\t\tconst resFrag = document.createDocumentFragment();\n\t\t\t\t\t\t\t\tconst errList = [];\n\n\t\t\t\t\t\t\t\t// Wikify the widget contents.\n\t\t\t\t\t\t\t\tnew Wikifier(resFrag, contents);\n\n\t\t\t\t\t\t\t\t// Carry over the output, unless there were errors.\n\t\t\t\t\t\t\t\tArray.from(resFrag.querySelectorAll('.error')).forEach(errEl => {\n\t\t\t\t\t\t\t\t\terrList.push(errEl.textContent);\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tif (errList.length === 0) {\n\t\t\t\t\t\t\t\t\tthis.output.appendChild(resFrag);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\treturn this.error(`error${errList.length > 1 ? 's' : ''} within widget contents (${errList.join('; ')})`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\treturn this.error(`cannot execute widget: ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t// Revert the `$args` variable shadowing.\n\t\t\t\t\t\t\t\tif (typeof argsCache !== 'undefined') {\n\t\t\t\t\t\t\t\t\tState.variables.args = argsCache;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tdelete State.variables.args;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t})(this.payload[0].contents)\n\t\t\t\t});\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`cannot create widget macro \"${widgetName}\": ${ex.message}`);\n\t\t\t}\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tdialog.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Has, L10n, safeActiveElement */\n\nvar Dialog = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Dialog element caches.\n\tlet _$overlay       = null;\n\tlet _$dialog        = null;\n\tlet _$dialogTitle   = null;\n\tlet _$dialogBody    = null;\n\n\t// The last active/focused non-dialog element.\n\tlet _lastActive     = null;\n\n\t// The width of the browser's scrollbars.\n\tlet _scrollbarWidth = 0;\n\n\t// Dialog mutation resize handler.\n\tlet _dialogObserver = null;\n\n\n\t/*******************************************************************************\n\t\tDialog Functions.\n\t*******************************************************************************/\n\n\t/*\n\t\t[DEPRECATED] Adds a click hander to the target element(s) which opens the dialog modal.\n\t*/\n\tfunction dialogAddClickHandler(targets, options, startFn, doneFn, closeFn) {\n\t\treturn jQuery(targets).ariaClick(ev => {\n\t\t\tev.preventDefault();\n\n\t\t\t// Call the start function.\n\t\t\tif (typeof startFn === 'function') {\n\t\t\t\tstartFn(ev);\n\t\t\t}\n\n\t\t\t// Open the dialog.\n\t\t\tdialogOpen(options, closeFn);\n\n\t\t\t// Call the done function.\n\t\t\tif (typeof doneFn === 'function') {\n\t\t\t\tdoneFn(ev);\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction dialogBodyAppend(...args) {\n\t\t_$dialogBody.append(...args);\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogBody() {\n\t\treturn _$dialogBody.get(0);\n\t}\n\n\tfunction dialogClose(ev) {\n\t\t// Trigger a `:dialogclosing` event on the dialog body.\n\t\t_$dialogBody.trigger(':dialogclosing');\n\n\t\t// Largely reverse the actions taken in `dialogOpen()`.\n\t\tjQuery(document)\n\t\t\t.off('.dialog-close');\n\t\tif (_dialogObserver) {\n\t\t\t_dialogObserver.disconnect();\n\t\t\t_dialogObserver = null;\n\t\t}\n\t\telse {\n\t\t\t_$dialogBody\n\t\t\t\t.off('.dialog-resize');\n\t\t}\n\t\tjQuery(window)\n\t\t\t.off('.dialog-resize');\n\t\t_$dialog\n\t\t\t.removeClass('open')\n\t\t\t.css({ left : '', right : '', top : '', bottom : '' });\n\n\t\tjQuery('#ui-bar,#story')\n\t\t\t.find('[tabindex=-2]')\n\t\t\t.removeAttr('aria-hidden')\n\t\t\t.attr('tabindex', 0);\n\t\tjQuery('body>[tabindex=-3]')\n\t\t\t.removeAttr('aria-hidden')\n\t\t\t.removeAttr('tabindex');\n\n\t\t_$overlay\n\t\t\t.removeClass('open');\n\t\tjQuery(document.documentElement)\n\t\t\t.removeAttr('data-dialog');\n\n\t\t// Clear the dialog's content.\n\t\t_$dialogTitle\n\t\t\t.empty();\n\t\t_$dialogBody\n\t\t\t.empty()\n\t\t\t.removeClass();\n\n\t\t// Attempt to restore focus to whichever element had it prior to opening the dialog.\n\t\tif (_lastActive !== null) {\n\t\t\tjQuery(_lastActive).focus();\n\t\t\t_lastActive = null;\n\t\t}\n\n\t\t// Call the given \"on close\" callback function, if any.\n\t\tif (ev && ev.data && typeof ev.data.closeFn === 'function') {\n\t\t\tev.data.closeFn(ev);\n\t\t}\n\n\t\t// Trigger a `:dialogclosed` event on the dialog body.\n\t\t/* legacy */\n\t\t_$dialogBody.trigger(':dialogclose');\n\t\t/* /legacy */\n\t\t_$dialogBody.trigger(':dialogclosed');\n\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogInit() {\n\t\tif (DEBUG) { console.log('[Dialog/dialogInit()]'); }\n\n\t\tif (document.getElementById('ui-dialog')) {\n\t\t\treturn;\n\t\t}\n\n\t\t/*\n\t\t\tCalculate and cache the width of scrollbars.\n\t\t*/\n\t\t_scrollbarWidth = (() => {\n\t\t\tlet scrollbarWidth;\n\n\t\t\ttry {\n\t\t\t\tconst inner = document.createElement('p');\n\t\t\t\tconst outer = document.createElement('div');\n\n\t\t\t\tinner.style.width      = '100%';\n\t\t\t\tinner.style.height     = '200px';\n\t\t\t\touter.style.position   = 'absolute';\n\t\t\t\touter.style.left       = '0px';\n\t\t\t\touter.style.top        = '0px';\n\t\t\t\touter.style.width      = '100px';\n\t\t\t\touter.style.height     = '100px';\n\t\t\t\touter.style.visibility = 'hidden';\n\t\t\t\touter.style.overflow   = 'hidden';\n\n\t\t\t\touter.appendChild(inner);\n\t\t\t\tdocument.body.appendChild(outer);\n\n\t\t\t\tconst w1 = inner.offsetWidth;\n\t\t\t\t/*\n\t\t\t\t\tThe `overflow: scroll` style property value does not work consistently\n\t\t\t\t\twith scrollbars which are styled with `::-webkit-scrollbar`, so we use\n\t\t\t\t\t`overflow: auto` with dimensions guaranteed to force a scrollbar.\n\t\t\t\t*/\n\t\t\t\touter.style.overflow = 'auto';\n\t\t\t\tlet w2 = inner.offsetWidth;\n\n\t\t\t\tif (w1 === w2) {\n\t\t\t\t\tw2 = outer.clientWidth;\n\t\t\t\t}\n\n\t\t\t\tdocument.body.removeChild(outer);\n\n\t\t\t\tscrollbarWidth = w1 - w2;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn scrollbarWidth || 17; // 17px is a reasonable failover\n\t\t})();\n\n\t\t/*\n\t\t\tGenerate the dialog elements.\n\t\t*/\n\t\tconst $elems = jQuery(document.createDocumentFragment())\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  '<div id=\"ui-overlay\" class=\"ui-close\"></div>'\n\t\t\t\t+ '<div id=\"ui-dialog\" tabindex=\"0\" role=\"dialog\" aria-labelledby=\"ui-dialog-title\">'\n\t\t\t\t+     '<div id=\"ui-dialog-titlebar\">'\n\t\t\t\t+         '<h1 id=\"ui-dialog-title\"></h1>'\n\t\t\t\t+         `<button id=\"ui-dialog-close\" class=\"ui-close\" tabindex=\"0\" aria-label=\"${L10n.get('close')}\">\\uE804</button>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div id=\"ui-dialog-body\"></div>'\n\t\t\t\t+ '</div>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t);\n\n\t\t/*\n\t\t\tCache the dialog elements, since they're going to be used often.\n\n\t\t\tNOTE: We rewrap the elements themselves, rather than simply using\n\t\t\tthe results of `find()`, so that we cache uncluttered jQuery-wrappers\n\t\t\t(i.e. `context` refers to the elements and there is no `prevObject`).\n\t\t*/\n\t\t_$overlay     = jQuery($elems.find('#ui-overlay').get(0));\n\t\t_$dialog      = jQuery($elems.find('#ui-dialog').get(0));\n\t\t_$dialogTitle = jQuery($elems.find('#ui-dialog-title').get(0));\n\t\t_$dialogBody  = jQuery($elems.find('#ui-dialog-body').get(0));\n\n\t\t/*\n\t\t\tInsert the dialog elements into the page before the main script.\n\t\t*/\n\t\t$elems.insertBefore('body>script#script-sugarcube');\n\t}\n\n\tfunction dialogIsOpen(classNames) {\n\t\treturn _$dialog.hasClass('open')\n\t\t\t&& (classNames ? classNames.splitOrEmpty(/\\s+/).every(cn => _$dialogBody.hasClass(cn)) : true);\n\t}\n\n\tfunction dialogOpen(options, closeFn) {\n\t\t// Trigger a `:dialogopening` event on the dialog body.\n\t\t_$dialogBody.trigger(':dialogopening');\n\n\t\t// Grab the options we care about.\n\t\tconst { top } = jQuery.extend({ top : 50 }, options);\n\n\t\t// Record the last active/focused non-dialog element.\n\t\tif (!dialogIsOpen()) {\n\t\t\t_lastActive = safeActiveElement();\n\t\t}\n\n\t\t// Add the `data-dialog` attribute to <html> (mostly used to style <body>).\n\t\tjQuery(document.documentElement)\n\t\t\t.attr('data-dialog', 'open');\n\n\t\t// Display the overlay.\n\t\t_$overlay\n\t\t\t.addClass('open');\n\n\t\t/*\n\t\t\tAdd the imagesLoaded handler to the dialog body, if necessary.\n\n\t\t\tNOTE: We use `querySelector()` here as jQuery has no simple way to\n\t\t\tcheck if, and only if, at least one element of the specified type\n\t\t\texists.  The best that jQuery offers is analogous to `querySelectorAll()`,\n\t\t\twhich enumerates all elements of the specified type.\n\t\t*/\n\t\tif (_$dialogBody[0].querySelector('img') !== null) {\n\t\t\t_$dialogBody\n\t\t\t\t.imagesLoaded()\n\t\t\t\t.always(() => _resizeHandler({ data : { top } }));\n\t\t}\n\n\t\t// Add `aria-hidden=true` to all direct non-dialog-children of <body> to\n\t\t// hide the underlying page from screen readers while the dialog is open.\n\t\tjQuery('body>:not(script,#store-area,tw-storydata,#ui-bar,#ui-overlay,#ui-dialog)')\n\t\t\t.attr('tabindex', -3)\n\t\t\t.attr('aria-hidden', true);\n\t\tjQuery('#ui-bar,#story')\n\t\t\t.find('[tabindex]:not([tabindex^=-])')\n\t\t\t.attr('tabindex', -2)\n\t\t\t.attr('aria-hidden', true);\n\n\t\t// Display the dialog.\n\t\t_$dialog\n\t\t\t.css(_calcPosition(top))\n\t\t\t.addClass('open')\n\t\t\t.focus();\n\n\t\t// Add the UI resize handler.\n\t\tjQuery(window)\n\t\t\t.on('resize.dialog-resize', null, { top }, jQuery.throttle(40, _resizeHandler));\n\n\t\t// Add the dialog mutation resize handler.\n\t\tif (Has.mutationObserver) {\n\t\t\t_dialogObserver = new MutationObserver(mutations => {\n\t\t\t\tfor (let i = 0; i < mutations.length; ++i) {\n\t\t\t\t\tif (mutations[i].type === 'childList') {\n\t\t\t\t\t\t_resizeHandler({ data : { top } });\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t_dialogObserver.observe(_$dialogBody[0], {\n\t\t\t\tchildList : true,\n\t\t\t\tsubtree   : true\n\t\t\t});\n\t\t}\n\t\telse {\n\t\t\t_$dialogBody\n\t\t\t\t.on(\n\t\t\t\t\t'DOMNodeInserted.dialog-resize DOMNodeRemoved.dialog-resize',\n\t\t\t\t\tnull,\n\t\t\t\t\t{ top },\n\t\t\t\t\tjQuery.throttle(40, _resizeHandler)\n\t\t\t\t);\n\t\t}\n\n\t\t// Set up the delegated UI close handler.\n\t\tjQuery(document)\n\t\t\t.on('click.dialog-close', '.ui-close', { closeFn }, dialogClose)\n\t\t\t.on('keypress.dialog-close', '.ui-close', function (ev) {\n\t\t\t\t// 13 is Enter/Return, 32 is Space.\n\t\t\t\tif (ev.which === 13 || ev.which === 32) {\n\t\t\t\t\tjQuery(this).trigger('click');\n\t\t\t\t}\n\t\t\t});\n\n\t\t// Trigger a `:dialogopened` event on the dialog body.\n\t\t/* legacy */\n\t\t_$dialogBody.trigger(':dialogopen');\n\t\t/* /legacy */\n\t\t_$dialogBody.trigger(':dialogopened');\n\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogResize(data) {\n\t\treturn _resizeHandler(typeof data === 'object' ? { data } : undefined);\n\t}\n\n\tfunction dialogSetup(title, classNames) {\n\t\t_$dialogBody\n\t\t\t.empty()\n\t\t\t.removeClass();\n\n\t\tif (classNames != null) { // lazy equality for null\n\t\t\t_$dialogBody.addClass(classNames);\n\t\t}\n\n\t\t_$dialogTitle\n\t\t\t.empty()\n\t\t\t.append((title != null ? String(title) : '') || '\\u00A0'); // lazy equality for null\n\n\t\t// TODO: In v3 this should return `Dialog` for chaining.\n\t\treturn _$dialogBody.get(0);\n\t}\n\n\tfunction dialogBodyWiki(...args) {\n\t\t_$dialogBody.wiki(...args);\n\t\treturn Dialog;\n\t}\n\n\n\t/*******************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************/\n\n\tfunction _calcPosition(topPos) {\n\t\tconst top       = topPos != null ? topPos : 50; // lazy equality for null\n\t\tconst $parent   = jQuery(window);\n\t\tconst dialogPos = { left : '', right : '', top : '', bottom : '' };\n\n\t\t// Unset the dialog's positional properties before checking its dimensions.\n\t\t_$dialog.css(dialogPos);\n\n\t\tlet horzSpace = $parent.width() - _$dialog.outerWidth(true) - 1;   // -1 to address a Firefox issue\n\t\tlet vertSpace = $parent.height() - _$dialog.outerHeight(true) - 1; // -1 to address a Firefox issue\n\n\t\tif (horzSpace <= 32 + _scrollbarWidth) {\n\t\t\tvertSpace -= _scrollbarWidth;\n\t\t}\n\n\t\tif (vertSpace <= 32 + _scrollbarWidth) {\n\t\t\thorzSpace -= _scrollbarWidth;\n\t\t}\n\n\t\tif (horzSpace <= 32) {\n\t\t\tdialogPos.left = dialogPos.right = 16;\n\t\t}\n\t\telse {\n\t\t\tdialogPos.left = dialogPos.right = horzSpace / 2 >> 0;\n\t\t}\n\n\t\tif (vertSpace <= 32) {\n\t\t\tdialogPos.top = dialogPos.bottom = 16;\n\t\t}\n\t\telse {\n\t\t\tif (vertSpace / 2 > top) {\n\t\t\t\tdialogPos.top = top;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdialogPos.top = dialogPos.bottom = vertSpace / 2 >> 0;\n\t\t\t}\n\t\t}\n\n\t\tObject.keys(dialogPos).forEach(key => {\n\t\t\tif (dialogPos[key] !== '') {\n\t\t\t\tdialogPos[key] += 'px';\n\t\t\t}\n\t\t});\n\n\t\treturn dialogPos;\n\t}\n\n\tfunction _resizeHandler(ev) {\n\t\tconst top = ev && ev.data && typeof ev.data.top !== 'undefined' ? ev.data.top : 50;\n\n\t\tif (_$dialog.css('display') === 'block') {\n\t\t\t// Stow the dialog.\n\t\t\t_$dialog.css({ display : 'none' });\n\n\t\t\t// Restore the dialog with its new positional properties.\n\t\t\t_$dialog.css(jQuery.extend({ display : '' }, _calcPosition(top)));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tappend : { value : dialogBodyAppend },\n\t\tbody   : { value : dialogBody },\n\t\tclose  : { value : dialogClose },\n\t\tinit   : { value : dialogInit },\n\t\tisOpen : { value : dialogIsOpen },\n\t\topen   : { value : dialogOpen },\n\t\tresize : { value : dialogResize },\n\t\tsetup  : { value : dialogSetup },\n\t\twiki   : { value : dialogBodyWiki },\n\n\t\t// Legacy Functions.\n\t\taddClickHandler : { value : dialogAddClickHandler }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tengine.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Config, DebugView, Dialog, Has, LoadScreen, Save, State, Story, StyleWrapper, UI, UIBar, Util,\n\t       Wikifier, postdisplay, postrender, predisplay, prehistory, prerender, setDisplayTitle\n*/\n\nvar Engine = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Engine state types object (pseudo-enumeration).\n\tconst States = Util.toEnum({\n\t\tIdle      : 'idle',\n\t\tPlaying   : 'playing',\n\t\tRendering : 'rendering'\n\t});\n\n\t// Minimum delay for DOM actions (in milliseconds).\n\tconst minDomActionDelay = 40;\n\n\t// Current state of the engine (default: `Engine.States.Idle`).\n\tlet _state = States.Idle;\n\n\t// Last time `enginePlay()` was called (in milliseconds).\n\tlet _lastPlay = null;\n\n\t// Cache of the debug view for the StoryInit special passage.\n\tlet _storyInitDebugView = null;\n\n\t// Cache of the outline patching <style> element (`StyleWrapper`-wrapped).\n\tlet _outlinePatch = null;\n\n\t// List of objects describing `StoryInterface` elements to update via passages during navigation.\n\tlet _updating = null;\n\n\n\t/*******************************************************************************************************************\n\t\tEngine Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tInitialize the core story elements and perform some bookkeeping.\n\t*/\n\tfunction engineInit() {\n\t\tif (DEBUG) { console.log('[Engine/engineInit()]'); }\n\n\t\t/*\n\t\t\tRemove #init-no-js & #init-lacking from #init-screen.\n\t\t*/\n\t\tjQuery('#init-no-js,#init-lacking').remove();\n\n\t\t/*\n\t\t\tGenerate the core story elements and insert them into the page before the store area.\n\t\t*/\n\t\t(() => {\n\t\t\tconst $elems = jQuery(document.createDocumentFragment());\n\t\t\tconst markup = Story.has('StoryInterface') && Story.get('StoryInterface').text.trim();\n\n\t\t\tif (markup) {\n\t\t\t\t// Remove the UI bar, its styles, and events.\n\t\t\t\tUIBar.destroy();\n\n\t\t\t\t// Remove the core display area styles.\n\t\t\t\tjQuery(document.head).find('#style-core-display').remove();\n\n\t\t\t\t$elems.append(markup);\n\n\t\t\t\tif ($elems.find('#passages').length === 0) {\n\t\t\t\t\tthrow new Error('no element with ID \"passages\" found within \"StoryInterface\" special passage');\n\t\t\t\t}\n\n\t\t\t\tconst updating = [];\n\n\t\t\t\t$elems.find('[data-passage]').each((i, el) => {\n\t\t\t\t\tif (el.id === 'passages') {\n\t\t\t\t\t\tthrow new Error(`\"StoryInterface\" element <${el.nodeName.toLowerCase()} id=\"passages\"> must not contain a \"data-passage\" content attribute`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst passage = el.getAttribute('data-passage').trim();\n\n\t\t\t\t\tif (el.firstElementChild !== null) {\n\t\t\t\t\t\tthrow new Error(`\"StoryInterface\" element <${el.nodeName.toLowerCase()} data-passage=\"${passage}\"> contains child elements`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tupdating.push({\n\t\t\t\t\t\t\tpassage,\n\t\t\t\t\t\t\telement : el\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (updating.length > 0) {\n\t\t\t\t\t_updating = updating;\n\t\t\t\t}\n\n\t\t\t\tConfig.ui.updateStoryElements = false;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$elems.append('<div id=\"story\" role=\"main\"><div id=\"passages\"></div></div>');\n\t\t\t}\n\n\t\t\t// Insert the core UI elements into the page before the main script.\n\t\t\t$elems.insertBefore('body>script#script-sugarcube');\n\t\t})();\n\n\t\t/*\n\t\t\tGenerate and cache the ARIA outlines <style> element (`StyleWrapper`-wrapped)\n\t\t\tand set up the handler to manipulate the outlines.\n\n\t\t\tIDEA: http://www.paciellogroup.com/blog/2012/04/how-to-remove-css-outlines-in-an-accessible-manner/\n\t\t*/\n\t\t_outlinePatch = new StyleWrapper((\n\t\t\t() => jQuery(document.createElement('style'))\n\t\t\t\t.attr({\n\t\t\t\t\tid   : 'style-aria-outlines',\n\t\t\t\t\ttype : 'text/css'\n\t\t\t\t})\n\t\t\t\t.appendTo(document.head)\n\t\t\t\t.get(0) // return the <style> element itself\n\t\t)());\n\t\tlet _lastOutlineEvent;\n\t\tjQuery(document).on(\n\t\t\t'mousedown.aria-outlines keydown.aria-outlines',\n\t\t\tev => {\n\t\t\t\tif (ev.type !== _lastOutlineEvent) {\n\t\t\t\t\t_lastOutlineEvent = ev.type;\n\n\t\t\t\t\tif (ev.type === 'keydown') {\n\t\t\t\t\t\t_showOutlines();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t_hideOutlines();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\t/*\n\t\tStarts the story.\n\t*/\n\tfunction engineStart() {\n\t\tif (DEBUG) { console.log('[Engine/engineStart()]'); }\n\n\t\t/*\n\t\t\tExecute the StoryInit special passage.\n\t\t*/\n\t\tif (Story.has('StoryInit')) {\n\t\t\ttry {\n\t\t\t\tconst debugBuffer = Wikifier.wikifyEval(Story.get('StoryInit').text);\n\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tconst debugView = new DebugView(\n\t\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t\t'special',\n\t\t\t\t\t\t'StoryInit',\n\t\t\t\t\t\t'StoryInit'\n\t\t\t\t\t);\n\t\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\t\tdebugView.append(debugBuffer);\n\t\t\t\t\t_storyInitDebugView = debugView.output;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('StoryInit', ex.message);\n\t\t\t}\n\t\t}\n\n\t\t// Sanity checks.\n\t\tif (Config.passages.start == null) { // lazy equality for null\n\t\t\tthrow new Error('starting passage not selected');\n\t\t}\n\t\tif (!Story.has(Config.passages.start)) {\n\t\t\tthrow new Error(`starting passage (\"${Config.passages.start}\") not found`);\n\t\t}\n\n\t\t// Focus the document element initially.\n\t\tjQuery(document.documentElement).focus();\n\n\t\t/*\n\t\t\tAttempt to restore an active session.  Failing that, attempt to autoload the autosave,\n\t\t\tif requested.  Failing that, display the starting passage.\n\t\t*/\n\t\tif (State.restore()) {\n\t\t\tengineShow();\n\t\t}\n\t\telse {\n\t\t\tlet loadStart = true;\n\n\t\t\tswitch (typeof Config.saves.autoload) {\n\t\t\tcase 'boolean':\n\t\t\t\tif (Config.saves.autoload && Save.autosave.ok() && Save.autosave.has()) {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\t\tloadStart = !Save.autosave.load();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'string':\n\t\t\t\tif (Config.saves.autoload === 'prompt' && Save.autosave.ok() && Save.autosave.has()) {\n\t\t\t\t\tloadStart = false;\n\t\t\t\t\tUI.buildAutoload();\n\t\t\t\t\tDialog.open();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'function':\n\t\t\t\tif (Save.autosave.ok() && Save.autosave.has() && !!Config.saves.autoload()) {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\t\tloadStart = !Save.autosave.load();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (loadStart) {\n\t\t\t\tif (DEBUG) { console.log(`\\tstarting passage: \"${Config.passages.start}\"`); }\n\n\t\t\t\tenginePlay(Config.passages.start);\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t\tRestarts the story.\n\t*/\n\tfunction engineRestart() {\n\t\tif (DEBUG) { console.log('[Engine/engineRestart()]'); }\n\n\t\t/*\n\t\t\tShow the loading screen to hide any unsightly rendering shenanigans during the\n\t\t\tpage reload.\n\t\t*/\n\t\tLoadScreen.show();\n\n\t\t/*\n\t\t\tScroll the window to the top.\n\n\t\t\tThis is required by most browsers for the starting passage or it will remain at\n\t\t\twhatever its current scroll position is after the page reload.  We do it generally,\n\t\t\trather than only for the currently set starting passage, since the starting passage\n\t\t\tmay be dynamically manipulated.\n\t\t*/\n\t\twindow.scroll(0, 0);\n\n\t\t/*\n\t\t\tDelete the active session.\n\t\t*/\n\t\tState.reset();\n\n\t\t/*\n\t\t\tTrigger an ':enginerestart' event.\n\t\t*/\n\t\tjQuery.event.trigger(':enginerestart');\n\n\t\t/*\n\t\t\tReload the page.\n\t\t*/\n\t\twindow.location.reload();\n\t}\n\n\t/*\n\t\tReturns the current state of the engine.\n\t*/\n\tfunction engineState() {\n\t\treturn _state;\n\t}\n\n\t/*\n\t\tReturns whether the engine is idle.\n\t*/\n\tfunction engineIsIdle() {\n\t\treturn _state === States.Idle;\n\t}\n\n\t/*\n\t\tReturns whether the engine is playing.\n\t*/\n\tfunction engineIsPlaying() {\n\t\treturn _state !== States.Idle;\n\t}\n\n\t/*\n\t\tReturns whether the engine is rendering.\n\t*/\n\tfunction engineIsRendering() {\n\t\treturn _state === States.Rendering;\n\t}\n\n\t/*\n\t\tReturns a timestamp representing the last time `Engine.play()` was called.\n\t*/\n\tfunction engineLastPlay() {\n\t\treturn _lastPlay;\n\t}\n\n\t/*\n\t\tActivate the moment at the given index within the state history and show it.\n\t*/\n\tfunction engineGoTo(idx) {\n\t\tconst succeded = State.goTo(idx);\n\n\t\tif (succeded) {\n\t\t\tengineShow();\n\t\t}\n\n\t\treturn succeded;\n\t}\n\n\t/*\n\t\tActivate the moment at the given offset from the active moment within the state history\n\t\tand show it.\n\t*/\n\tfunction engineGo(offset) {\n\t\tconst succeded = State.go(offset);\n\n\t\tif (succeded) {\n\t\t\tengineShow();\n\t\t}\n\n\t\treturn succeded;\n\t}\n\n\t/*\n\t\tGo to the moment which directly precedes the active moment and show it.\n\t*/\n\tfunction engineBackward() {\n\t\treturn engineGo(-1);\n\t}\n\n\t/*\n\t\tGo to the moment which directly follows the active moment and show it.\n\t*/\n\tfunction engineForward() {\n\t\treturn engineGo(1);\n\t}\n\n\t/*\n\t\tRenders and displays the active (present) moment's associated passage without adding\n\t\ta new moment to the history.\n\t*/\n\tfunction engineShow() {\n\t\treturn enginePlay(State.passage, true);\n\t}\n\n\t/*\n\t\tRenders and displays the passage referenced by the given title, optionally without\n\t\tadding a new moment to the history.\n\t*/\n\tfunction enginePlay(title, noHistory) {\n\t\tif (DEBUG) { console.log(`[Engine/enginePlay(title: \"${title}\", noHistory: ${noHistory})]`); }\n\n\t\tlet passageTitle = title;\n\n\t\t// Update the engine state.\n\t\t_state = States.Playing;\n\n\t\t// Reset the temporary state and variables objects.\n\t\tTempState = {}; // eslint-disable-line no-undef\n\t\tState.clearTemporary();\n\n\t\t// Debug view setup.\n\t\tlet passageReadyOutput;\n\t\tlet passageDoneOutput;\n\n\t\t// Execute the navigation override callback.\n\t\tif (typeof Config.navigation.override === 'function') {\n\t\t\ttry {\n\t\t\t\tconst overrideTitle = Config.navigation.override(passageTitle);\n\n\t\t\t\tif (overrideTitle) {\n\t\t\t\t\tpassageTitle = overrideTitle;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\t\t}\n\n\t\t// Retrieve the passage by the given title.\n\t\t//\n\t\t// NOTE: The values of the `title` parameter and `passageTitle` variable\n\t\t// may be empty, strings, or numbers (though using a number as reference\n\t\t// to a numeric title should be discouraged), so after loading the passage,\n\t\t// always refer to `passage.title` and never to the others.\n\t\tconst passage = Story.get(passageTitle);\n\n\t\t// Execute the pre-history events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype : ':passageinit',\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(prehistory).forEach(task => {\n\t\t\tif (typeof prehistory[task] === 'function') {\n\t\t\t\tprehistory[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\t// Create a new entry in the history.\n\t\tif (!noHistory) {\n\t\t\tState.create(passage.title);\n\t\t}\n\n\t\t// Clear the document body's classes.\n\t\tif (document.body.className) {\n\t\t\tdocument.body.className = '';\n\t\t}\n\n\t\t// Update the last play time.\n\t\t//\n\t\t// NOTE: This is mostly for event, task, and special passage code,\n\t\t// though the likelihood of it being needed this early is low.  This\n\t\t// will be updated again later at the end.\n\t\t_lastPlay = Util.now();\n\n\t\t// Execute pre-display tasks and the `PassageReady` special passage.\n\t\tObject.keys(predisplay).forEach(task => {\n\t\t\tif (typeof predisplay[task] === 'function') {\n\t\t\t\tpredisplay[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\tif (Story.has('PassageReady')) {\n\t\t\ttry {\n\t\t\t\tpassageReadyOutput = Wikifier.wikifyEval(Story.get('PassageReady').text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('PassageReady', ex.message);\n\t\t\t}\n\t\t}\n\n\t\t// Update the engine state.\n\t\t_state = States.Rendering;\n\n\t\t// Get the passage's tags as a string, or `null` if there aren't any.\n\t\tconst dataTags = passage.tags.length > 0 ? passage.tags.join(' ') : null;\n\n\t\t// Create and set up the incoming passage element.\n\t\tconst passageEl = document.createElement('div');\n\t\tjQuery(passageEl)\n\t\t\t.attr({\n\t\t\t\tid             : passage.domId,\n\t\t\t\t'data-passage' : passage.title,\n\t\t\t\t'data-tags'    : dataTags\n\t\t\t})\n\t\t\t.addClass(`passage ${passage.className}`);\n\n\t\t// Add the passage's classes and tags to the document body.\n\t\tjQuery(document.body)\n\t\t\t.attr('data-tags', dataTags)\n\t\t\t.addClass(passage.className);\n\n\t\t// Add the passage's tags to the document element.\n\t\tjQuery(document.documentElement)\n\t\t\t.attr('data-tags', dataTags);\n\n\t\t// Execute pre-render events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagestart',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(prerender).forEach(task => {\n\t\t\tif (typeof prerender[task] === 'function') {\n\t\t\t\tprerender[task].call(passage, passageEl, task);\n\t\t\t}\n\t\t});\n\n\t\t// Render the `PassageHeader` passage, if it exists, into the passage element.\n\t\tif (Story.has('PassageHeader')) {\n\t\t\tnew Wikifier(passageEl, Story.get('PassageHeader').processText());\n\t\t}\n\n\t\t// Render the passage into its element.\n\t\tpassageEl.appendChild(passage.render());\n\n\t\t// Render the `PassageFooter` passage, if it exists, into the passage element.\n\t\tif (Story.has('PassageFooter')) {\n\t\t\tnew Wikifier(passageEl, Story.get('PassageFooter').processText());\n\t\t}\n\n\t\t// Execute post-render events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagerender',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(postrender).forEach(task => {\n\t\t\tif (typeof postrender[task] === 'function') {\n\t\t\t\tpostrender[task].call(passage, passageEl, task);\n\t\t\t}\n\t\t});\n\n\t\t// Cache the passage container.\n\t\tconst containerEl = document.getElementById('passages');\n\n\t\t// Empty the passage container.\n\t\tif (containerEl.hasChildNodes()) {\n\t\t\tif (\n\t\t\t\t   typeof Config.passages.transitionOut === 'number'\n\t\t\t\t|| typeof Config.passages.transitionOut === 'string'\n\t\t\t\t&& Config.passages.transitionOut !== ''\n\t\t\t\t&& Has.transitionEndEvent\n\t\t\t) {\n\t\t\t\t[...containerEl.childNodes].forEach(outgoing => {\n\t\t\t\t\tconst $outgoing = jQuery(outgoing);\n\n\t\t\t\t\tif (outgoing.nodeType === Node.ELEMENT_NODE && $outgoing.hasClass('passage')) {\n\t\t\t\t\t\tif ($outgoing.hasClass('passage-out')) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$outgoing\n\t\t\t\t\t\t\t.attr('id', `out-${$outgoing.attr('id')}`)\n\t\t\t\t\t\t\t.addClass('passage-out');\n\n\t\t\t\t\t\tif (typeof Config.passages.transitionOut === 'string') {\n\t\t\t\t\t\t\t$outgoing.on(Has.transitionEndEvent, ev => {\n\t\t\t\t\t\t\t\tif (ev.originalEvent.propertyName === Config.passages.transitionOut) {\n\t\t\t\t\t\t\t\t\t$outgoing.remove();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tsetTimeout(\n\t\t\t\t\t\t\t\t() => $outgoing.remove(),\n\t\t\t\t\t\t\t\tMath.max(minDomActionDelay, Config.passages.transitionOut)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t$outgoing.remove();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery(containerEl).empty();\n\t\t\t}\n\t\t}\n\n\t\t// Append the passage element to the passage container and set up its transition.\n\t\tjQuery(passageEl)\n\t\t\t.addClass('passage-in')\n\t\t\t.appendTo(containerEl);\n\t\tsetTimeout(() => jQuery(passageEl).removeClass('passage-in'), minDomActionDelay);\n\n\t\t// Update the story display title, if necessary.\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\t// NOTE: We don't have an `else` here because that case will be handled later (below).\n\t\t\tif (_updating !== null || !Config.ui.updateStoryElements) {\n\t\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t\t}\n\t\t}\n\t\telse if (Config.passages.displayTitles && passage.title !== Config.passages.start) {\n\t\t\tdocument.title = `${passage.title} | ${Story.title}`;\n\t\t}\n\n\t\t// Scroll the window to the top.\n\t\twindow.scroll(0, 0);\n\n\t\t// Update the engine state.\n\t\t_state = States.Playing;\n\n\t\t// Execute post-display events, tasks, and the `PassageDone` special passage.\n\t\tif (Story.has('PassageDone')) {\n\t\t\ttry {\n\t\t\t\tpassageDoneOutput = Wikifier.wikifyEval(Story.get('PassageDone').text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('PassageDone', ex.message);\n\t\t\t}\n\t\t}\n\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagedisplay',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(postdisplay).forEach(task => {\n\t\t\tif (typeof postdisplay[task] === 'function') {\n\t\t\t\tpostdisplay[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\t// Update the other interface elements, if necessary.\n\t\tif (_updating !== null) {\n\t\t\t_updating.forEach(pair => {\n\t\t\t\tjQuery(pair.element).empty();\n\t\t\t\tnew Wikifier(pair.element, Story.get(pair.passage).processText().trim());\n\t\t\t});\n\t\t}\n\t\telse if (Config.ui.updateStoryElements) {\n\t\t\tUIBar.update();\n\t\t}\n\n\t\t// Add the completed debug views for `StoryInit`, `PassageReady`, and `PassageDone`\n\t\t// to the incoming passage element.\n\t\tif (Config.debug) {\n\t\t\tlet debugView;\n\n\t\t\t// Prepend the `PassageReady` debug view.\n\t\t\tif (passageReadyOutput != null) { // lazy equality for null\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t'special',\n\t\t\t\t\t'PassageReady',\n\t\t\t\t\t'PassageReady'\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\tdebugView.append(passageReadyOutput);\n\t\t\t\tjQuery(passageEl).prepend(debugView.output);\n\t\t\t}\n\n\t\t\t// Append the `PassageDone` debug view.\n\t\t\tif (passageDoneOutput != null) { // lazy equality for null\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t'special',\n\t\t\t\t\t'PassageDone',\n\t\t\t\t\t'PassageDone'\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\tdebugView.append(passageDoneOutput);\n\t\t\t\tjQuery(passageEl).append(debugView.output);\n\t\t\t}\n\n\t\t\t// Prepend the cached `StoryInit` debug view, if we're showing the first moment/turn.\n\t\t\tif (State.turns === 1 && _storyInitDebugView != null) { // lazy equality for null\n\t\t\t\tjQuery(passageEl).prepend(_storyInitDebugView);\n\t\t\t}\n\t\t}\n\n\t\t// Last second post-processing for accessibility and other things.\n\t\t_hideOutlines(); // initially hide outlines\n\t\tjQuery('#story')\n\t\t\t// Add `link-external` to all `href` bearing `<a>` elements which don't have it.\n\t\t\t.find('a[href]:not(.link-external)')\n\t\t\t.addClass('link-external')\n\t\t\t.end()\n\t\t\t// Add `tabindex=0` to all interactive elements which don't have it.\n\t\t\t.find('a,link,button,input,select,textarea')\n\t\t\t.not('[tabindex]')\n\t\t\t.attr('tabindex', 0);\n\n\t\t// Handle autosaves.\n\t\tswitch (typeof Config.saves.autosave) {\n\t\tcase 'boolean':\n\t\t\tif (Config.saves.autosave) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'object':\n\t\t\tif (passage.tags.some(tag => Config.saves.autosave.includes(tag))) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'function':\n\t\t\tif (Config.saves.autosave()) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// Execute post-play events.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passageend',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\n\t\t// Reset the engine state.\n\t\t_state = States.Idle;\n\n\t\t// Update the last play time.\n\t\t_lastPlay = Util.now();\n\n\t\treturn passageEl;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tLegacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Play the given passage, optionally without altering the history.\n\t*/\n\tfunction engineDisplay(title, link, option) {\n\t\tif (DEBUG) { console.log('[Engine/engineDisplay()]'); }\n\n\t\tlet noHistory = false;\n\n\t\t// Process the option parameter.\n\t\tswitch (option) {\n\t\tcase undefined:\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'replace':\n\t\tcase 'back':\n\t\t\tnoHistory = true;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new Error(`Engine.display option parameter called with obsolete value \"${option}\"; please notify the developer`);\n\t\t}\n\n\t\tenginePlay(title, noHistory);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _hideOutlines() {\n\t\t_outlinePatch.set('*:focus{outline:none;}');\n\t}\n\n\tfunction _showOutlines() {\n\t\t_outlinePatch.clear();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tConstants.\n\t\t*/\n\t\tStates            : { value : States },\n\t\tminDomActionDelay : { value : minDomActionDelay },\n\n\t\t/*\n\t\t\tCore Functions.\n\t\t*/\n\t\tinit        : { value : engineInit },\n\t\tstart       : { value : engineStart },\n\t\trestart     : { value : engineRestart },\n\t\tstate       : { get : engineState },\n\t\tisIdle      : { value : engineIsIdle },\n\t\tisPlaying   : { value : engineIsPlaying },\n\t\tisRendering : { value : engineIsRendering },\n\t\tlastPlay    : { get : engineLastPlay },\n\t\tgoTo        : { value : engineGoTo },\n\t\tgo          : { value : engineGo },\n\t\tbackward    : { value : engineBackward },\n\t\tforward     : { value : engineForward },\n\t\tshow        : { value : engineShow },\n\t\tplay        : { value : enginePlay },\n\n\t\t/*\n\t\t\tLegacy Functions.\n\t\t*/\n\t\tdisplay : { value : engineDisplay }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tpassage.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, L10n, Util, Wikifier */\n\nvar Passage = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tlet _tagsToSkip;\n\tlet _twine1Unescape;\n\n\t/*\n\t\tTags which should not be transformed into classes:\n\t\t\tdebug      → special tag\n\t\t\tnobr       → special tag\n\t\t\tpassage    → the default class\n\t\t\tscript     → special tag (only in Twine 1)\n\t\t\tstylesheet → special tag (only in Twine 1)\n\t\t\ttwine.*    → special tag\n\t\t\twidget     → special tag\n\t*/\n\t// For Twine 1\n\tif (TWINE1) {\n\t\t_tagsToSkip = /^(?:debug|nobr|passage|script|stylesheet|widget|twine\\..*)$/i;\n\t}\n\t// For Twine 2\n\telse {\n\t\t_tagsToSkip = /^(?:debug|nobr|passage|widget|twine\\..*)$/i;\n\t}\n\n\t// For Twine 1\n\tif (TWINE1) {\n\t\t/*\n\t\t\tReturns a decoded version of the passed Twine 1 passage store encoded string.\n\t\t*/\n\t\tconst _twine1EscapesRe    = /(?:\\\\n|\\\\t|\\\\s|\\\\|\\r)/g;\n\t\tconst _hasTwine1EscapesRe = new RegExp(_twine1EscapesRe.source); // to drop the global flag\n\t\tconst _twine1EscapesMap   = Object.freeze({\n\t\t\t'\\\\n' : '\\n',\n\t\t\t'\\\\t' : '\\t',\n\t\t\t'\\\\s' : '\\\\',\n\t\t\t'\\\\'  : '\\\\',\n\t\t\t'\\r'  : ''\n\t\t});\n\n\t\t_twine1Unescape = function (str) {\n\t\t\tif (str == null) { // lazy equality for null\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tconst val = String(str);\n\t\t\treturn val && _hasTwine1EscapesRe.test(val)\n\t\t\t\t? val.replace(_twine1EscapesRe, esc => _twine1EscapesMap[esc])\n\t\t\t\t: val;\n\t\t};\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPassage Class.\n\t*******************************************************************************************************************/\n\tclass Passage {\n\t\tconstructor(title, el) {\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// Passage title/ID.\n\t\t\t\ttitle : {\n\t\t\t\t\tvalue : Util.unescape(title)\n\t\t\t\t},\n\n\t\t\t\t// Passage data element (within the story data element; i.e. T1: '[tiddler]', T2: 'tw-passagedata').\n\t\t\t\telement : {\n\t\t\t\t\tvalue : el || null\n\t\t\t\t},\n\n\t\t\t\t// Passage tags array (sorted and unique).\n\t\t\t\ttags : {\n\t\t\t\t\tvalue : Object.freeze(el && el.hasAttribute('tags')\n\t\t\t\t\t\t? el.getAttribute('tags')\n\t\t\t\t\t\t\t.trim()\n\t\t\t\t\t\t\t.splitOrEmpty(/\\s+/)\n\t\t\t\t\t\t\t.sort()\n\t\t\t\t\t\t\t.filter((tag, i, aref) => i === 0 || aref[i - 1] !== tag)\n\t\t\t\t\t\t: [])\n\t\t\t\t},\n\n\t\t\t\t// Passage excerpt.  Used by the `description()` method.\n\t\t\t\t_excerpt : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Properties dependant upon the above set.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// Passage DOM-compatible ID.\n\t\t\t\tdomId : {\n\t\t\t\t\tvalue : `passage-${Util.slugify(this.title)}`\n\t\t\t\t},\n\n\t\t\t\t// Passage classes array (sorted and unique).\n\t\t\t\tclasses : {\n\t\t\t\t\tvalue : Object.freeze(this.tags.length === 0 ? [] : (() =>\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tReturn the sorted list of unique classes.\n\n\t\t\t\t\t\t\tNOTE: The `this.tags` array is already sorted and unique,\n\t\t\t\t\t\t\tso we only need to filter and map here.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tthis.tags\n\t\t\t\t\t\t\t.filter(tag => !_tagsToSkip.test(tag))\n\t\t\t\t\t\t\t.map(tag => Util.slugify(tag))\n\t\t\t\t\t)())\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// Getters.\n\t\tget className() {\n\t\t\treturn this.classes.join(' ');\n\t\t}\n\n\t\t// TODO: (v3) This should be → `get source`.\n\t\tget text() {\n\t\t\tif (this.element == null) { // lazy equality for null\n\t\t\t\tconst passage = Util.escape(this.title);\n\t\t\t\tconst mesg    = `${L10n.get('errorTitle')}: ${L10n.get('errorNonexistentPassage', { passage })}`;\n\t\t\t\treturn `<div class=\"error-view\"><span class=\"error\">${mesg}</span></div>`;\n\t\t\t}\n\n\t\t\t// For Twine 1\n\t\t\tif (TWINE1) {\n\t\t\t\treturn _twine1Unescape(this.element.textContent);\n\t\t\t}\n\t\t\t// For Twine 2\n\t\t\telse { // eslint-disable-line no-else-return\n\t\t\t\treturn this.element.textContent.replace(/\\r/g, '');\n\t\t\t}\n\t\t}\n\n\t\tdescription() {\n\t\t\tconst descriptions = Config.passages.descriptions;\n\n\t\t\tif (descriptions != null) { // lazy equality for null\n\t\t\t\tswitch (typeof descriptions) {\n\t\t\t\tcase 'boolean':\n\t\t\t\t\tif (descriptions) {\n\t\t\t\t\t\treturn this.title;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\tif (descriptions instanceof Map && descriptions.has(this.title)) {\n\t\t\t\t\t\treturn descriptions.get(this.title);\n\t\t\t\t\t}\n\t\t\t\t\telse if (descriptions.hasOwnProperty(this.title)) {\n\t\t\t\t\t\treturn descriptions[this.title];\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'function':\n\t\t\t\t\t{\n\t\t\t\t\t\tconst result = descriptions.call(this);\n\n\t\t\t\t\t\tif (result) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new TypeError('Config.passages.descriptions must be a boolean, object, or function');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Initialize the excerpt cache from the raw passage text, if necessary.\n\t\t\tif (this._excerpt === null) {\n\t\t\t\tthis._excerpt = Passage.getExcerptFromText(this.text);\n\t\t\t}\n\n\t\t\treturn this._excerpt;\n\t\t}\n\n\t\t// TODO: (v3) This should be → `get text`.\n\t\tprocessText() {\n\t\t\tif (this.element == null) { // lazy equality for null\n\t\t\t\treturn this.text;\n\t\t\t}\n\n\t\t\t// Handle image passage transclusion.\n\t\t\tif (this.tags.includes('Twine.image')) {\n\t\t\t\treturn `[img[${this.text}]]`;\n\t\t\t}\n\n\t\t\tlet processed = this.text;\n\n\t\t\t// Handle `Config.passages.onProcess`.\n\t\t\tif (Config.passages.onProcess) {\n\t\t\t\tprocessed = Config.passages.onProcess.call(null, {\n\t\t\t\t\ttitle : this.title,\n\t\t\t\t\ttags  : this.tags,\n\t\t\t\t\ttext  : processed\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Handle `Config.passages.nobr` and the `nobr` tag.\n\t\t\tif (Config.passages.nobr || this.tags.includes('nobr')) {\n\t\t\t\t// Remove all leading & trailing newlines and compact all internal sequences\n\t\t\t\t// of newlines into single spaces.\n\t\t\t\tprocessed = processed.replace(/^\\n+|\\n+$/g, '').replace(/\\n+/g, ' ');\n\t\t\t}\n\n\t\t\treturn processed;\n\t\t}\n\n\t\trender(options) {\n\t\t\t// Wikify the passage into a document fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, this.processText(), options);\n\n\t\t\t// Update the excerpt cache to reflect the rendered text, if we need it for the passage description\n\t\t\tif (Config.passages.descriptions == null) {\n\t\t\t\tthis._excerpt = Passage.getExcerptFromNode(frag);\n\t\t\t}\n\n\t\t\treturn frag;\n\t\t}\n\n\t\tstatic getExcerptFromNode(node, count) {\n\t\t\tif (!node.hasChildNodes()) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tlet excerpt = node.textContent.trim();\n\n\t\t\tif (excerpt !== '') {\n\t\t\t\tconst excerptRe = new RegExp(`(\\\\S+(?:\\\\s+\\\\S+){0,${count > 0 ? count - 1 : 7}})`);\n\t\t\t\texcerpt = excerpt\n\t\t\t\t\t// Compact whitespace.\n\t\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t\t// Attempt to match the excerpt regexp.\n\t\t\t\t\t.match(excerptRe);\n\t\t\t}\n\n\t\t\treturn excerpt ? `${excerpt[1]}\\u2026` : '\\u2026'; // horizontal ellipsis\n\t\t}\n\n\t\tstatic getExcerptFromText(text, count) {\n\t\t\tif (text === '') {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tconst excerptRe = new RegExp(`(\\\\S+(?:\\\\s+\\\\S+){0,${count > 0 ? count - 1 : 7}})`);\n\t\t\tconst excerpt   = text\n\t\t\t\t// Strip macro tags (replace with a space).\n\t\t\t\t.replace(/<<.*?>>/g, ' ')\n\t\t\t\t// Strip html tags (replace with a space).\n\t\t\t\t.replace(/<.*?>/g, ' ')\n\t\t\t\t// The above might have left problematic whitespace, so trim.\n\t\t\t\t.trim()\n\t\t\t\t// Strip table markup.\n\t\t\t\t.replace(/^\\s*\\|.*\\|.*?$/gm, '')\n\t\t\t\t// Strip image markup.\n\t\t\t\t.replace(/\\[[<>]?img\\[[^\\]]*\\]\\]/g, '')\n\t\t\t\t// Clean link markup (remove all but the link text).\n\t\t\t\t.replace(/\\[\\[([^|\\]]*?)(?:(?:\\||->|<-)[^\\]]*)?\\]\\]/g, '$1')\n\t\t\t\t// Clean heading markup.\n\t\t\t\t.replace(/^\\s*!+(.*?)$/gm, '$1')\n\t\t\t\t// Clean bold/italic/underline/highlight styles.\n\t\t\t\t.replace(/'{2}|\\/{2}|_{2}|@{2}/g, '')\n\t\t\t\t// A final trim.\n\t\t\t\t.trim()\n\t\t\t\t// Compact whitespace.\n\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t// Attempt to match the excerpt regexp.\n\t\t\t\t.match(excerptRe);\n\t\t\treturn excerpt ? `${excerpt[1]}\\u2026` : '\\u2026'; // horizontal ellipsis\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Passage;\n})();\n\n/***********************************************************************************************************************\n\n\tsave.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Dialog, Engine, L10n, State, Story, UI, storage */\n\nvar Save = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// The upper bound of the saves slots.\n\tlet _slotsUBound = -1;\n\n\n\t/*******************************************************************************************************************\n\t\tSaves Functions.\n\t*******************************************************************************************************************/\n\tfunction savesInit() {\n\t\tif (DEBUG) { console.log('[Save/savesInit()]'); }\n\n\t\t// Disable save slots and the autosave when Web Storage is unavailable.\n\t\tif (storage.name === 'cookie') {\n\t\t\tsavesObjClear();\n\t\t\tConfig.saves.autoload = undefined;\n\t\t\tConfig.saves.autosave = undefined;\n\t\t\tConfig.saves.slots = 0;\n\t\t\treturn false;\n\t\t}\n\n\t\tlet saves   = savesObjGet();\n\t\tlet updated = false;\n\n\t\t/* legacy */\n\t\t// Convert an ancient saves array into a new saves object.\n\t\tif (Array.isArray(saves)) {\n\t\t\tsaves = {\n\t\t\t\tautosave : null,\n\t\t\t\tslots    : saves\n\t\t\t};\n\t\t\tupdated = true;\n\t\t}\n\t\t/* /legacy */\n\n\t\t// Handle the author changing the number of save slots.\n\t\tif (Config.saves.slots !== saves.slots.length) {\n\t\t\tif (Config.saves.slots < saves.slots.length) {\n\t\t\t\t// Attempt to decrease the number of slots; this will only compact\n\t\t\t\t// the slots array, by removing empty slots, no saves will be deleted.\n\t\t\t\tsaves.slots.reverse();\n\n\t\t\t\tsaves.slots = saves.slots.filter(function (val) {\n\t\t\t\t\tif (val === null && this.count > 0) {\n\t\t\t\t\t\t--this.count;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\t\t\t\t}, { count : saves.slots.length - Config.saves.slots });\n\n\t\t\t\tsaves.slots.reverse();\n\t\t\t}\n\t\t\telse if (Config.saves.slots > saves.slots.length) {\n\t\t\t\t// Attempt to increase the number of slots.\n\t\t\t\t_appendSlots(saves.slots, Config.saves.slots - saves.slots.length);\n\t\t\t}\n\n\t\t\tupdated = true;\n\t\t}\n\n\t\t/* legacy */\n\t\t// Update saves with old/obsolete properties.\n\t\tif (_savesObjUpdate(saves.autosave)) {\n\t\t\tupdated = true;\n\t\t}\n\n\t\tfor (let i = 0; i < saves.slots.length; ++i) {\n\t\t\tif (_savesObjUpdate(saves.slots[i])) {\n\t\t\t\tupdated = true;\n\t\t\t}\n\t\t}\n\n\t\t// Remove save stores which are empty.\n\t\tif (_savesObjIsEmpty(saves)) {\n\t\t\tstorage.delete('saves');\n\t\t\tupdated = false;\n\t\t}\n\t\t/* /legacy */\n\n\t\t// If the saves object was updated, then update the store.\n\t\tif (updated) {\n\t\t\t_savesObjSave(saves);\n\t\t}\n\n\t\t_slotsUBound = saves.slots.length - 1;\n\n\t\treturn true;\n\t}\n\n\tfunction savesObjCreate() {\n\t\treturn {\n\t\t\tautosave : null,\n\t\t\tslots    : _appendSlots([], Config.saves.slots)\n\t\t};\n\t}\n\n\tfunction savesObjGet() {\n\t\tconst saves = storage.get('saves');\n\t\treturn saves === null ? savesObjCreate() : saves;\n\t}\n\n\tfunction savesObjClear() {\n\t\tstorage.delete('saves');\n\t\treturn true;\n\t}\n\n\tfunction savesOk() {\n\t\treturn autosaveOk() || slotsOk();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAutosave Functions.\n\t*******************************************************************************************************************/\n\tfunction autosaveOk() {\n\t\treturn storage.name !== 'cookie' && typeof Config.saves.autosave !== 'undefined';\n\t}\n\n\tfunction autosaveHas() {\n\t\tconst saves = savesObjGet();\n\n\t\tif (saves.autosave === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction autosaveGet() {\n\t\tconst saves = savesObjGet();\n\t\treturn saves.autosave;\n\t}\n\n\tfunction autosaveLoad() {\n\t\tconst saves = savesObjGet();\n\n\t\tif (saves.autosave === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn _unmarshal(saves.autosave);\n\t}\n\n\tfunction autosaveSave(title, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves        = savesObjGet();\n\t\tconst supplemental = {\n\t\t\ttitle : title || Story.get(State.passage).description(),\n\t\t\tdate  : Date.now()\n\t\t};\n\n\t\tif (metadata != null) { // lazy equality for null\n\t\t\tsupplemental.metadata = metadata;\n\t\t}\n\n\t\tsaves.autosave = _marshal(supplemental);\n\n\t\treturn _savesObjSave(saves);\n\t}\n\n\tfunction autosaveDelete() {\n\t\tconst saves = savesObjGet();\n\t\tsaves.autosave = null;\n\t\treturn _savesObjSave(saves);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSlots Functions.\n\t*******************************************************************************************************************/\n\tfunction slotsOk() {\n\t\treturn storage.name !== 'cookie' && _slotsUBound !== -1;\n\t}\n\n\tfunction slotsLength() {\n\t\treturn _slotsUBound + 1;\n\t}\n\n\tfunction slotsCount() {\n\t\tif (!slotsOk()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\t\tlet count = 0;\n\n\t\tfor (let i = 0, iend = saves.slots.length; i < iend; ++i) {\n\t\t\tif (saves.slots[i] !== null) {\n\t\t\t\t++count;\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n\n\tfunction slotsIsEmpty() {\n\t\treturn slotsCount() === 0;\n\t}\n\n\tfunction slotsHas(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length || saves.slots[slot] === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction slotsGet(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn saves.slots[slot];\n\t}\n\n\tfunction slotsLoad(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length || saves.slots[slot] === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn _unmarshal(saves.slots[slot]);\n\t}\n\n\tfunction slotsSave(slot, title, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst supplemental = {\n\t\t\ttitle : title || Story.get(State.passage).description(),\n\t\t\tdate  : Date.now()\n\t\t};\n\n\t\tif (metadata != null) { // lazy equality for null\n\t\t\tsupplemental.metadata = metadata;\n\t\t}\n\n\t\tsaves.slots[slot] = _marshal(supplemental);\n\n\t\treturn _savesObjSave(saves);\n\t}\n\n\tfunction slotsDelete(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tsaves.slots[slot] = null;\n\t\treturn _savesObjSave(saves);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tDisk Import/Export Functions.\n\t*******************************************************************************************************************/\n\tfunction exportToDisk(filename, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tfunction datestamp() {\n\t\t\tconst now = new Date();\n\t\t\tlet MM = now.getMonth() + 1;\n\t\t\tlet DD = now.getDate();\n\t\t\tlet hh = now.getHours();\n\t\t\tlet mm = now.getMinutes();\n\t\t\tlet ss = now.getSeconds();\n\n\t\t\tif (MM < 10) { MM = `0${MM}`; }\n\t\t\tif (DD < 10) { DD = `0${DD}`; }\n\t\t\tif (hh < 10) { hh = `0${hh}`; }\n\t\t\tif (mm < 10) { mm = `0${mm}`; }\n\t\t\tif (ss < 10) { ss = `0${ss}`; }\n\n\t\t\treturn `${now.getFullYear()}${MM}${DD}-${hh}${mm}${ss}`;\n\t\t}\n\n\t\tfunction legalizeName(str) {\n\t\t\t/*\n\t\t\t\tNOTE: The range of illegal characters consists of: C0 controls, double quote,\n\t\t\t\tnumber, dollar, percent, ampersand, single quote, asterisk, plus, comma,\n\t\t\t\tforward slash, colon, semi-colon, less-than, equals, greater-than, question,\n\t\t\t\tbackslash, caret, backquote/grave, pipe/vertical-bar, delete, C1 controls.\n\t\t\t*/\n\t\t\treturn String(str).trim()\n\t\t\t\t.replace(/[\\x00-\\x1f\"#$%&'*+,/:;<=>?\\\\^`|\\x7f-\\x9f]+/g, '') // eslint-disable-line no-control-regex\n\t\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-'); // legacy\n\t\t}\n\n\t\tconst baseName     = filename == null ? Story.domId : legalizeName(filename); // lazy equality for null\n\t\tconst saveName     = `${baseName}-${datestamp()}.save`;\n\t\tconst supplemental = metadata == null ? {} : { metadata }; // lazy equality for null\n\t\tconst saveObj      = LZString.compressToBase64(JSON.stringify(_marshal(supplemental)));\n\t\tsaveAs(new Blob([saveObj], { type : 'text/plain;charset=UTF-8' }), saveName);\n\t}\n\n\tfunction importFromDisk(event) {\n\t\tconst file   = event.target.files[0];\n\t\tconst reader = new FileReader();\n\n\t\t// Add the handler that will capture the file information once the load is finished.\n\t\tjQuery(reader).on('load', ev => {\n\t\t\tconst target = ev.currentTarget;\n\n\t\t\tif (!target.result) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet saveObj;\n\n\t\t\ttry {\n\t\t\t\tsaveObj = JSON.parse(\n\t\t\t\t\t/* legacy */ /\\.json$/i.test(file.name) || /^\\{/.test(target.result)\n\t\t\t\t\t\t? target.result\n\t\t\t\t\t\t: /* /legacy */ LZString.decompressFromBase64(target.result)\n\t\t\t\t);\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op; `_unmarshal()` will handle the error */ }\n\n\t\t\t_unmarshal(saveObj);\n\t\t});\n\n\t\t// Initiate the file load.\n\t\treader.readAsText(file);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSerialization Functions.\n\t*******************************************************************************************************************/\n\tfunction serialize(metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tconst supplemental = metadata == null ? {} : { metadata }; // lazy equality for null\n\t\treturn LZString.compressToBase64(JSON.stringify(_marshal(supplemental)));\n\t}\n\n\tfunction deserialize(base64Str) {\n\t\t/*\n\t\t\tNOTE: We purposefully do not attempt to catch parameter shenanigans\n\t\t\there, instead relying on `_unmarshal()` to do the heavy lifting.\n\t\t*/\n\n\t\tlet saveObj;\n\n\t\ttry {\n\t\t\tsaveObj = JSON.parse(LZString.decompressFromBase64(base64Str));\n\t\t}\n\t\tcatch (ex) { /* no-op; `_unmarshal()` will handle the error */ }\n\n\t\tif (!_unmarshal(saveObj)) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn saveObj.metadata;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _appendSlots(array, num) {\n\t\tfor (let i = 0; i < num; ++i) {\n\t\t\tarray.push(null);\n\t\t}\n\n\t\treturn array;\n\t}\n\n\tfunction _savesObjIsEmpty(saves) {\n\t\tconst slots = saves.slots;\n\t\tlet isSlotsEmpty = true;\n\n\t\tfor (let i = 0, iend = slots.length; i < iend; ++i) {\n\t\t\tif (slots[i] !== null) {\n\t\t\t\tisSlotsEmpty = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn saves.autosave === null && isSlotsEmpty;\n\t}\n\n\tfunction _savesObjSave(saves) {\n\t\tif (_savesObjIsEmpty(saves)) {\n\t\t\tstorage.delete('saves');\n\t\t\treturn true;\n\t\t}\n\n\t\treturn storage.set('saves', saves);\n\t}\n\n\tfunction _savesObjUpdate(saveObj) {\n\t\tif (saveObj == null || typeof saveObj !== 'object') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tlet updated = false;\n\n\t\t/* eslint-disable no-param-reassign */\n\t\tif (\n\t\t\t   !saveObj.hasOwnProperty('state')\n\t\t\t|| !saveObj.state.hasOwnProperty('delta')\n\t\t\t|| !saveObj.state.hasOwnProperty('index')\n\t\t) {\n\t\t\tif (saveObj.hasOwnProperty('data')) {\n\t\t\t\tdelete saveObj.mode;\n\t\t\t\tsaveObj.state = {\n\t\t\t\t\tdelta : State.deltaEncode(saveObj.data)\n\t\t\t\t};\n\t\t\t\tdelete saveObj.data;\n\t\t\t}\n\t\t\telse if (!saveObj.state.hasOwnProperty('delta')) {\n\t\t\t\tdelete saveObj.state.mode;\n\t\t\t\tsaveObj.state.delta = State.deltaEncode(saveObj.state.history);\n\t\t\t\tdelete saveObj.state.history;\n\t\t\t}\n\t\t\telse if (!saveObj.state.hasOwnProperty('index')) {\n\t\t\t\tdelete saveObj.state.mode;\n\t\t\t}\n\n\t\t\tsaveObj.state.index = saveObj.state.delta.length - 1;\n\t\t\tupdated = true;\n\t\t}\n\n\t\tif (saveObj.state.hasOwnProperty('rseed')) {\n\t\t\tsaveObj.state.seed = saveObj.state.rseed;\n\t\t\tdelete saveObj.state.rseed;\n\n\t\t\tsaveObj.state.delta.forEach((_, i, delta) => {\n\t\t\t\tif (delta[i].hasOwnProperty('rcount')) {\n\t\t\t\t\tdelta[i].pull = delta[i].rcount;\n\t\t\t\t\tdelete delta[i].rcount;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tupdated = true;\n\t\t}\n\n\t\tif (\n\t\t\t   saveObj.state.hasOwnProperty('expired') && typeof saveObj.state.expired === 'number'\n\t\t\t||  saveObj.state.hasOwnProperty('unique')\n\t\t\t||  saveObj.state.hasOwnProperty('last')\n\t\t) {\n\t\t\tif (saveObj.state.hasOwnProperty('expired') && typeof saveObj.state.expired === 'number') {\n\t\t\t\tdelete saveObj.state.expired;\n\t\t\t}\n\n\t\t\tif (saveObj.state.hasOwnProperty('unique') || saveObj.state.hasOwnProperty('last')) {\n\t\t\t\tsaveObj.state.expired = [];\n\n\t\t\t\tif (saveObj.state.hasOwnProperty('unique')) {\n\t\t\t\t\tsaveObj.state.expired.push(saveObj.state.unique);\n\t\t\t\t\tdelete saveObj.state.unique;\n\t\t\t\t}\n\n\t\t\t\tif (saveObj.state.hasOwnProperty('last')) {\n\t\t\t\t\tsaveObj.state.expired.push(saveObj.state.last);\n\t\t\t\t\tdelete saveObj.state.last;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tupdated = true;\n\t\t}\n\t\t/* eslint-enable no-param-reassign */\n\n\t\treturn updated;\n\t}\n\n\tfunction _marshal(supplemental) {\n\t\tif (DEBUG) { console.log('[Save/_marshal()]'); }\n\n\t\tif (supplemental != null && typeof supplemental !== 'object') { // lazy equality for null\n\t\t\tthrow new Error('supplemental parameter must be an object');\n\t\t}\n\n\t\tconst saveObj = Object.assign({}, supplemental, {\n\t\t\tid    : Config.saves.id,\n\t\t\tstate : State.marshalForSave()\n\t\t});\n\n\t\tif (Config.saves.version) {\n\t\t\tsaveObj.version = Config.saves.version;\n\t\t}\n\n\t\tif (typeof Config.saves.onSave === 'function') {\n\t\t\tConfig.saves.onSave(saveObj);\n\t\t}\n\n\t\t// Delta encode the state history and delete the non-encoded property.\n\t\tsaveObj.state.delta = State.deltaEncode(saveObj.state.history);\n\t\tdelete saveObj.state.history;\n\n\t\treturn saveObj;\n\t}\n\n\tfunction _unmarshal(saveObj) {\n\t\tif (DEBUG) { console.log('[Save/_unmarshal()]'); }\n\n\t\ttry {\n\t\t\t/* eslint-disable no-param-reassign */\n\t\t\t/* legacy */\n\t\t\t// Update saves with old/obsolete properties.\n\t\t\t_savesObjUpdate(saveObj);\n\t\t\t/* /legacy */\n\n\t\t\tif (!saveObj || !saveObj.hasOwnProperty('id') || !saveObj.hasOwnProperty('state')) {\n\t\t\t\tthrow new Error(L10n.get('errorSaveMissingData'));\n\t\t\t}\n\n\t\t\t// Delta decode the state history and delete the encoded property.\n\t\t\tsaveObj.state.history = State.deltaDecode(saveObj.state.delta);\n\t\t\tdelete saveObj.state.delta;\n\n\t\t\tif (typeof Config.saves.onLoad === 'function') {\n\t\t\t\tConfig.saves.onLoad(saveObj);\n\t\t\t}\n\n\t\t\tif (saveObj.id !== Config.saves.id) {\n\t\t\t\tthrow new Error(L10n.get('errorSaveIdMismatch'));\n\t\t\t}\n\n\t\t\t// Restore the state.\n\t\t\tState.unmarshalForSave(saveObj.state); // may also throw exceptions\n\n\t\t\t// Show the active moment.\n\t\t\tEngine.show();\n\t\t\t/* eslint-enable no-param-reassign */\n\t\t}\n\t\tcatch (ex) {\n\t\t\tUI.alert(`${ex.message.toUpperFirst()}.</p><p>${L10n.get('aborting')}.`);\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tSave Functions.\n\t\t*/\n\t\tinit  : { value : savesInit },\n\t\tget   : { value : savesObjGet },\n\t\tclear : { value : savesObjClear },\n\t\tok    : { value : savesOk },\n\n\t\t/*\n\t\t\tAutosave Functions.\n\t\t*/\n\t\tautosave : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tok     : { value : autosaveOk },\n\t\t\t\thas    : { value : autosaveHas },\n\t\t\t\tget    : { value : autosaveGet },\n\t\t\t\tload   : { value : autosaveLoad },\n\t\t\t\tsave   : { value : autosaveSave },\n\t\t\t\tdelete : { value : autosaveDelete }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tSlots Functions.\n\t\t*/\n\t\tslots : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tok      : { value : slotsOk },\n\t\t\t\tlength  : { get : slotsLength },\n\t\t\t\tisEmpty : { value : slotsIsEmpty },\n\t\t\t\tcount   : { value : slotsCount },\n\t\t\t\thas     : { value : slotsHas },\n\t\t\t\tget     : { value : slotsGet },\n\t\t\t\tload    : { value : slotsLoad },\n\t\t\t\tsave    : { value : slotsSave },\n\t\t\t\tdelete  : { value : slotsDelete }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tDisk Import/Export Functions.\n\t\t*/\n\t\texport : { value : exportToDisk },\n\t\timport : { value : importFromDisk },\n\n\t\t/*\n\t\t\tSerialization Functions.\n\t\t*/\n\t\tserialize   : { value : serialize },\n\t\tdeserialize : { value : deserialize }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tsetting.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util, settings:true, storage */\n\nvar Setting = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Setting control types object (pseudo-enumeration).\n\tconst Types = Util.toEnum({\n\t\tHeader : 0,\n\t\tToggle : 1,\n\t\tList   : 2,\n\t\tRange  : 3\n\t});\n\n\t// Setting definition array.\n\tconst _definitions = [];\n\n\n\t/*******************************************************************************************************************\n\t\tSettings Functions.\n\t*******************************************************************************************************************/\n\tfunction settingsInit() {\n\t\tif (DEBUG) { console.log('[Setting/settingsInit()]'); }\n\n\t\t/* legacy */\n\t\t// Attempt to migrate an existing `options` store to `settings`.\n\t\tif (storage.has('options')) {\n\t\t\tconst old = storage.get('options');\n\n\t\t\tif (old !== null) {\n\t\t\t\twindow.SugarCube.settings = settings = Object.assign(settingsCreate(), old);\n\t\t\t}\n\n\t\t\tsettingsSave();\n\t\t\tstorage.delete('options');\n\t\t}\n\t\t/* /legacy */\n\n\t\t// Load existing settings.\n\t\tsettingsLoad();\n\n\t\t// Execute `onInit` callbacks.\n\t\t_definitions.forEach(def => {\n\t\t\tif (def.hasOwnProperty('onInit')) {\n\t\t\t\tconst thisArg = {\n\t\t\t\t\tname    : def.name,\n\t\t\t\t\tvalue   : settings[def.name],\n\t\t\t\t\tdefault : def.default\n\t\t\t\t};\n\n\t\t\t\tif (def.hasOwnProperty('list')) {\n\t\t\t\t\tthisArg.list = def.list;\n\t\t\t\t}\n\n\t\t\t\tdef.onInit.call(thisArg);\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction settingsCreate() {\n\t\treturn Object.create(null);\n\t}\n\n\tfunction settingsSave() {\n\t\tconst savedSettings = settingsCreate();\n\n\t\tif (Object.keys(settings).length > 0) {\n\t\t\t_definitions\n\t\t\t\t.filter(def => def.type !== Types.Header && settings[def.name] !== def.default)\n\t\t\t\t.forEach(def => savedSettings[def.name] = settings[def.name]);\n\t\t}\n\n\t\tif (Object.keys(savedSettings).length === 0) {\n\t\t\tstorage.delete('settings');\n\t\t\treturn true;\n\t\t}\n\n\t\treturn storage.set('settings', savedSettings);\n\t}\n\n\tfunction settingsLoad() {\n\t\tconst defaultSettings = settingsCreate();\n\t\tconst loadedSettings  = storage.get('settings') || settingsCreate();\n\n\t\t// Load the defaults.\n\t\t_definitions\n\t\t\t.filter(def => def.type !== Types.Header)\n\t\t\t.forEach(def => defaultSettings[def.name] = def.default);\n\n\t\t// Assign to the `settings` object while overwriting the defaults with the loaded settings.\n\t\twindow.SugarCube.settings = settings = Object.assign(defaultSettings, loadedSettings);\n\t}\n\n\tfunction settingsClear() {\n\t\twindow.SugarCube.settings = settings = settingsCreate();\n\t\tstorage.delete('settings');\n\t\treturn true;\n\t}\n\n\tfunction settingsReset(name) {\n\t\tif (arguments.length === 0) {\n\t\t\tsettingsClear();\n\t\t\tsettingsLoad();\n\t\t}\n\t\telse {\n\t\t\tif (name == null || !definitionsHas(name)) { // lazy equality for null\n\t\t\t\tthrow new Error(`nonexistent setting \"${name}\"`);\n\t\t\t}\n\n\t\t\tconst def = definitionsGet(name);\n\n\t\t\tif (def.type !== Types.Header) {\n\t\t\t\tsettings[name] = def.default;\n\t\t\t}\n\t\t}\n\n\t\treturn settingsSave();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tDefinitions Functions.\n\t*******************************************************************************************************************/\n\tfunction definitionsForEach(callback, thisArg) {\n\t\t_definitions.forEach(callback, thisArg);\n\t}\n\n\tfunction definitionsAdd(type, name, def) {\n\t\tif (arguments.length < 3) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('type'); }\n\t\t\tif (arguments.length < 2) { errors.push('name'); }\n\t\t\tif (arguments.length < 3) { errors.push('definition'); }\n\t\t\tthrow new Error(`missing parameters, no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tif (typeof def !== 'object') {\n\t\t\tthrow new TypeError('definition parameter must be an object');\n\t\t}\n\n\t\tif (definitionsHas(name)) {\n\t\t\tthrow new Error(`cannot clobber existing setting \"${name}\"`);\n\t\t}\n\n\t\t/*\n\t\t\tDefinition object properties and types:\n\t\t\t\ttype      →  (all)   → Setting.Types\n\t\t\t\tname      →  (all)   → string\n\t\t\t\tlabel     →  (all)   → string\n\t\t\t\tdesc      →  (all)   → string\n\t\t\t\tdefault\n\t\t\t\t\t(if defined)\n \t\t\t\t\t\t  →  Toggle  → boolean\n\t\t\t\t\t\t  →  List    → Array\n\t\t\t\t\t\t  →  Range   → number\n\t\t\t\t\t(if undefined)\n\t\t\t\t\t\t  →  Toggle  → false\n\t\t\t\t\t\t  →  List    → list[0]\n\t\t\t\t\t\t  →  Range   → max\n\t\t\t\tlist      →  List    → Array\n\t\t\t\tmin       →  Range   → number\n\t\t\t\tmax       →  Range   → number\n\t\t\t\tstep      →  Range   → number\n\t\t\t\tonInit    →  (all)   → function\n\t\t\t\tonChange  →  (all)   → function\n\t\t*/\n\t\tconst definition = {\n\t\t\ttype,\n\t\t\tname,\n\t\t\tlabel : typeof def.label === 'string' ? def.label.trim() : ''\n\t\t};\n\n\t\tif (typeof def.desc === 'string') {\n\t\t\tconst desc = def.desc.trim();\n\n\t\t\tif (desc !== '') {\n\t\t\t\tdefinition.desc = desc;\n\t\t\t}\n\t\t}\n\n\t\tswitch (type) {\n\t\tcase Types.Header:\n\t\t\tbreak;\n\n\t\tcase Types.Toggle:\n\t\t\tdefinition.default = !!def.default;\n\t\t\tbreak;\n\n\t\tcase Types.List:\n\t\t\tif (!def.hasOwnProperty('list')) {\n\t\t\t\tthrow new Error('no list specified');\n\t\t\t}\n\t\t\telse if (!Array.isArray(def.list)) {\n\t\t\t\tthrow new TypeError('list must be an array');\n\t\t\t}\n\t\t\telse if (def.list.length === 0) {\n\t\t\t\tthrow new Error('list must not be empty');\n\t\t\t}\n\n\t\t\tdefinition.list = Object.freeze(def.list);\n\n\t\t\tif (def.default == null) { // lazy equality for null\n\t\t\t\tdefinition.default = def.list[0];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst defaultIndex = def.list.indexOf(def.default);\n\n\t\t\t\tif (defaultIndex === -1) {\n\t\t\t\t\tthrow new Error('list does not contain default');\n\t\t\t\t}\n\n\t\t\t\tdefinition.default = def.list[defaultIndex];\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase Types.Range:\n\t\t\tif (!def.hasOwnProperty('min')) {\n\t\t\t\tthrow new Error('no min specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.min !== 'number'\n\t\t\t\t|| Number.isNaN(def.min)\n\t\t\t\t|| !Number.isFinite(def.min)\n\t\t\t) {\n\t\t\t\tthrow new TypeError('min must be a finite number');\n\t\t\t}\n\n\t\t\tif (!def.hasOwnProperty('max')) {\n\t\t\t\tthrow new Error('no max specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.max !== 'number'\n\t\t\t\t|| Number.isNaN(def.max)\n\t\t\t\t|| !Number.isFinite(def.max)\n\t\t\t) {\n\t\t\t\tthrow new TypeError('max must be a finite number');\n\t\t\t}\n\n\t\t\tif (!def.hasOwnProperty('step')) {\n\t\t\t\tthrow new Error('no step specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.step !== 'number'\n\t\t\t\t|| Number.isNaN(def.step)\n\t\t\t\t|| !Number.isFinite(def.step)\n\t\t\t\t|| def.step <= 0\n\t\t\t) {\n\t\t\t\tthrow new TypeError('step must be a finite number greater than zero');\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Determine how many fractional digits we need to be concerned with based on the step value.\n\t\t\t\tconst fracDigits = (() => {\n\t\t\t\t\tconst str = String(def.step);\n\t\t\t\t\tconst pos = str.lastIndexOf('.');\n\t\t\t\t\treturn pos === -1 ? 0 : str.length - pos - 1;\n\t\t\t\t})();\n\n\t\t\t\t// Set up a function to validate a given value against the step value.\n\t\t\t\tfunction stepValidate(value) {\n\t\t\t\t\tif (fracDigits > 0) {\n\t\t\t\t\t\tconst ma = Number(`${def.min}e${fracDigits}`);\n\t\t\t\t\t\tconst sa = Number(`${def.step}e${fracDigits}`);\n\t\t\t\t\t\tconst va = Number(`${value}e${fracDigits}`) - ma;\n\t\t\t\t\t\treturn Number(`${va - va % sa + ma}e-${fracDigits}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst va = value - def.min;\n\t\t\t\t\treturn va - va % def.step + def.min;\n\t\t\t\t}\n\n\t\t\t\t// Sanity check the max value against the step value.\n\t\t\t\tif (stepValidate(def.max) !== def.max) {\n\t\t\t\t\tthrow new RangeError(`max (${def.max}) is not a multiple of the step (${def.step}) plus the min (${def.min})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdefinition.max = def.max;\n\t\t\tdefinition.min = def.min;\n\t\t\tdefinition.step = def.step;\n\n\t\t\tif (def.default == null) { // lazy equality for null\n\t\t\t\tdefinition.default = def.max;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (\n\t\t\t\t\t   typeof def.default !== 'number'\n\t\t\t\t\t|| Number.isNaN(def.default)\n\t\t\t\t\t|| !Number.isFinite(def.default)\n\t\t\t\t) {\n\t\t\t\t\tthrow new TypeError('default must be a finite number');\n\t\t\t\t}\n\t\t\t\telse if (def.default < def.min) {\n\t\t\t\t\tthrow new RangeError(`default (${def.default}) is less than min (${def.min})`);\n\t\t\t\t}\n\t\t\t\telse if (def.default > def.max) {\n\t\t\t\t\tthrow new RangeError(`default (${def.default}) is greater than max (${def.max})`);\n\t\t\t\t}\n\n\t\t\t\tdefinition.default = def.default;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new Error(`unknown Setting type: ${type}`);\n\t\t}\n\n\t\tif (typeof def.onInit === 'function') {\n\t\t\tdefinition.onInit = Object.freeze(def.onInit);\n\t\t}\n\n\t\tif (typeof def.onChange === 'function') {\n\t\t\tdefinition.onChange = Object.freeze(def.onChange);\n\t\t}\n\n\t\t_definitions.push(Object.freeze(definition));\n\t}\n\n\tfunction definitionsAddHeader(name, desc) {\n\t\tdefinitionsAdd(Types.Header, name, { desc });\n\t}\n\n\tfunction definitionsAddToggle(...args) {\n\t\tdefinitionsAdd(Types.Toggle, ...args);\n\t}\n\n\tfunction definitionsAddList(...args) {\n\t\tdefinitionsAdd(Types.List, ...args);\n\t}\n\n\tfunction definitionsAddRange(...args) {\n\t\tdefinitionsAdd(Types.Range, ...args);\n\t}\n\n\tfunction definitionsIsEmpty() {\n\t\treturn _definitions.length === 0;\n\t}\n\n\tfunction definitionsHas(name) {\n\t\treturn _definitions.some(definition => definition.name === name);\n\t}\n\n\tfunction definitionsGet(name) {\n\t\treturn _definitions.find(definition => definition.name === name);\n\t}\n\n\tfunction definitionsDelete(name) {\n\t\tif (definitionsHas(name)) {\n\t\t\tdelete settings[name];\n\t\t}\n\n\t\tfor (let i = 0; i < _definitions.length; ++i) {\n\t\t\tif (_definitions[i].name === name) {\n\t\t\t\t_definitions.splice(i, 1);\n\t\t\t\tdefinitionsDelete(name);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tEnumerations.\n\t\t*/\n\t\tTypes : { value : Types },\n\n\t\t/*\n\t\t\tSettings Functions.\n\t\t*/\n\t\tinit   : { value : settingsInit },\n\t\tcreate : { value : settingsCreate },\n\t\tsave   : { value : settingsSave },\n\t\tload   : { value : settingsLoad },\n\t\tclear  : { value : settingsClear },\n\t\treset  : { value : settingsReset },\n\n\t\t/*\n\t\t\tDefinitions Functions.\n\t\t*/\n\t\tforEach   : { value : definitionsForEach },\n\t\tadd       : { value : definitionsAdd },\n\t\taddHeader : { value : definitionsAddHeader },\n\t\taddToggle : { value : definitionsAddToggle },\n\t\taddList   : { value : definitionsAddList },\n\t\taddRange  : { value : definitionsAddRange },\n\t\tisEmpty   : { value : definitionsIsEmpty },\n\t\thas       : { value : definitionsHas },\n\t\tget       : { value : definitionsGet },\n\t\tdelete    : { value : definitionsDelete }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tstory.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Alert, Config, Passage, Scripting, StyleWrapper, Util, Wikifier */\n\nvar Story = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Map of normal passages.\n\tconst _passages = {};\n\n\t// List of script passages.\n\tconst _scripts = [];\n\n\t// List of style passages.\n\tconst _styles = [];\n\n\t// List of widget passages.\n\tconst _widgets = [];\n\n\t// Story title.\n\tlet _title = '';\n\n\t// Story IFID.\n\tlet _ifId = '';\n\n\t// DOM-compatible ID.\n\tlet _domId = '';\n\n\n\t/*******************************************************************************************************************\n\t\tStory Functions.\n\t*******************************************************************************************************************/\n\tfunction storyLoad() {\n\t\tif (DEBUG) { console.log('[Story/storyLoad()]'); }\n\n\t\tconst validationCodeTags = [\n\t\t\t'widget'\n\t\t];\n\t\tconst validationNoCodeTagPassages = [\n\t\t\t'PassageDone',\n\t\t\t'PassageFooter',\n\t\t\t'PassageHeader',\n\t\t\t'PassageReady',\n\t\t\t'StoryAuthor',\n\t\t\t'StoryBanner',\n\t\t\t'StoryCaption',\n\t\t\t'StoryInit',\n\t\t\t'StoryMenu',\n\t\t\t'StoryShare',\n\t\t\t'StorySubtitle'\n\t\t];\n\n\t\tfunction validateStartingPassage(passage) {\n\t\t\tif (passage.tags.includesAny(validationCodeTags)) {\n\t\t\t\tthrow new Error(`starting passage \"${passage.title}\" contains illegal tags; invalid: \"${passage.tags.filter(tag => validationCodeTags.includes(tag)).sort().join('\", \"')}\"`);\n\t\t\t}\n\t\t}\n\n\t\tfunction validateSpecialPassages(passage) {\n\t\t\tif (validationNoCodeTagPassages.includes(passage.title) && passage.tags.includesAny(validationCodeTags)) {\n\t\t\t\tthrow new Error(`special passage \"${passage.title}\" contains illegal tags; invalid: \"${passage.tags.filter(tag => validationCodeTags.includes(tag)).sort().join('\", \"')}\"`);\n\t\t\t}\n\t\t}\n\n\t\t// For Twine 1.\n\t\tif (TWINE1) {\n\t\t\t/*\n\t\t\t\tAdditional Twine 1 validation setup.\n\t\t\t*/\n\t\t\tvalidationCodeTags.unshift('script', 'stylesheet');\n\t\t\tvalidationNoCodeTagPassages.push('StoryTitle');\n\n\t\t\tfunction validateTwine1CodePassages(passage) {\n\t\t\t\tconst codeTags  = [...validationCodeTags];\n\t\t\t\tconst foundTags = [];\n\n\t\t\t\tpassage.tags.forEach(tag => {\n\t\t\t\t\tif (codeTags.includes(tag)) {\n\t\t\t\t\t\tfoundTags.push(...codeTags.delete(tag));\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (foundTags.length > 1) {\n\t\t\t\t\tthrow new Error(`code passage \"${passage.title}\" contains multiple code tags; invalid: \"${foundTags.sort().join('\", \"')}\"`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet the default starting passage.\n\t\t\t*/\n\t\t\tConfig.passages.start = (() => {\n\t\t\t\t/*\n\t\t\t\t\tHandle the Twine 1.4+ Test Play From Here feature.\n\n\t\t\t\t\tWARNING: Do not remove the `String()` wrapper from or change the quote\n\t\t\t\t\tstyle of the `\"START_AT\"` replacement target.  The former is there to\n\t\t\t\t\tkeep UglifyJS from pruning the code into oblivion—i.e. minifying the\n\t\t\t\t\tcode into something broken.  The latter is there because the Twine 1\n\t\t\t\t\tpattern that matches it depends upon the double quotes.\n\n\t\t\t\t*/\n\t\t\t\tconst testPlay = String(\"START_AT\"); // eslint-disable-line quotes\n\n\t\t\t\tif (testPlay !== '') {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tTest play; starting passage: \"${testPlay}\"`); }\n\n\t\t\t\t\tConfig.debug = true;\n\t\t\t\t\treturn testPlay;\n\t\t\t\t}\n\n\t\t\t\t// In the absence of a `testPlay` value, return 'Start'.\n\t\t\t\treturn 'Start';\n\t\t\t})();\n\n\t\t\t/*\n\t\t\t\tProcess the passages, excluding any tagged 'Twine.private' or 'annotation'.\n\t\t\t*/\n\t\t\tjQuery('#store-area')\n\t\t\t\t.children(':not([tags~=\"Twine.private\"],[tags~=\"annotation\"])')\n\t\t\t\t.each(function () {\n\t\t\t\t\tconst $this   = jQuery(this);\n\t\t\t\t\tconst passage = new Passage($this.attr('tiddler'), this);\n\n\t\t\t\t\t// Special cases.\n\t\t\t\t\tif (passage.title === Config.passages.start) {\n\t\t\t\t\t\tvalidateStartingPassage(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('stylesheet')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_styles.push(passage);\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('script')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_scripts.push(passage);\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('widget')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_widgets.push(passage);\n\t\t\t\t\t}\n\n\t\t\t\t\t// All other passages.\n\t\t\t\t\telse {\n\t\t\t\t\t\tvalidateSpecialPassages(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tSet the story title or throw an exception.\n\t\t\t*/\n\t\t\tif (_passages.hasOwnProperty('StoryTitle')) {\n\t\t\t\tconst buf = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(buf, _passages.StoryTitle.processText().trim());\n\t\t\t\t_storySetTitle(buf.textContent);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('cannot find the \"StoryTitle\" special passage');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet the default saves ID (must be done after the call to `_storySetTitle()`).\n\t\t\t*/\n\t\t\tConfig.saves.id = Story.domId;\n\t\t}\n\n\t\t// For Twine 2.\n\t\telse {\n\t\t\tconst $storydata = jQuery('tw-storydata');\n\t\t\tconst startNode  = $storydata.attr('startnode') || '';\n\n\t\t\t/*\n\t\t\t\tSet the default starting passage.\n\t\t\t*/\n\t\t\tConfig.passages.start = null; // no default in Twine 2\n\n\t\t\t/*\n\t\t\t\tProcess story options.\n\n\t\t\t\tNOTE: Currently, the only option of interest is 'debug', so we\n\t\t\t\tsimply use a regular expression to check for it.\n\t\t\t*/\n\t\t\tConfig.debug = /\\bdebug\\b/.test($storydata.attr('options'));\n\n\t\t\t/*\n\t\t\t\tProcess stylesheet passages.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('style') // alternatively: '[type=\"text/twine-css\"]' or '#twine-user-stylesheet'\n\t\t\t\t.each(function (i) {\n\t\t\t\t\t_styles.push(new Passage(`tw-user-style-${i}`, this));\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tProcess script passages.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('script') // alternatively: '[type=\"text/twine-javascript\"]' or '#twine-user-script'\n\t\t\t\t.each(function (i) {\n\t\t\t\t\t_scripts.push(new Passage(`tw-user-script-${i}`, this));\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tProcess normal passages, excluding any tagged 'Twine.private' or 'annotation'.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('tw-passagedata:not([tags~=\"Twine.private\"],[tags~=\"annotation\"])')\n\t\t\t\t.each(function () {\n\t\t\t\t\tconst $this   = jQuery(this);\n\t\t\t\t\tconst pid     = $this.attr('pid') || '';\n\t\t\t\t\tconst passage = new Passage($this.attr('name'), this);\n\n\t\t\t\t\t// Special cases.\n\t\t\t\t\tif (pid === startNode && startNode !== '') {\n\t\t\t\t\t\tConfig.passages.start = passage.title;\n\t\t\t\t\t\tvalidateStartingPassage(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('widget')) {\n\t\t\t\t\t\t_widgets.push(passage);\n\t\t\t\t\t}\n\n\t\t\t\t\t// All other passages.\n\t\t\t\t\telse {\n\t\t\t\t\t\tvalidateSpecialPassages(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tGet the story IFID.\n\t\t\t*/\n\t\t\t_ifId = $storydata.attr('ifid');\n\n\t\t\t/*\n\t\t\t\tSet the story title.\n\n\t\t\t\tFIXME: Maybe `$storydata.attr('name')` should be used instead of `'{{STORY_NAME}}'`?\n\t\t\t*/\n\t\t\t// _storySetTitle($storydata.attr('name'));\n\t\t\t_storySetTitle('{{STORY_NAME}}');\n\n\t\t\t/*\n\t\t\t\tSet the default saves ID (must be done after the call to `_storySetTitle()`).\n\t\t\t*/\n\t\t\tConfig.saves.id = Story.domId;\n\t\t}\n\t}\n\n\tfunction storyInit() {\n\t\tif (DEBUG) { console.log('[Story/storyInit()]'); }\n\n\t\t/*\n\t\t\tAdd the story styles.\n\t\t*/\n\t\t(() => {\n\t\t\tconst storyStyle = document.createElement('style');\n\n\t\t\t(new StyleWrapper(storyStyle))\n\t\t\t\t.add(_styles.map(style => style.text.trim()).join('\\n'));\n\n\t\t\tjQuery(storyStyle)\n\t\t\t\t.appendTo(document.head)\n\t\t\t\t.attr({\n\t\t\t\t\tid   : 'style-story',\n\t\t\t\t\ttype : 'text/css'\n\t\t\t\t});\n\t\t})();\n\n\t\t/*\n\t\t\tEvaluate the story scripts.\n\t\t*/\n\t\tfor (let i = 0; i < _scripts.length; ++i) {\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(_scripts[i].text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error(_scripts[i].title, typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t\tProcess the story widgets.\n\t\t*/\n\t\tfor (let i = 0; i < _widgets.length; ++i) {\n\t\t\ttry {\n\t\t\t\tWikifier.wikifyEval(_widgets[i].processText());\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error(_widgets[i].title, typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction _storySetTitle(rawTitle) {\n\t\tif (rawTitle == null) { // lazy equality for null\n\t\t\tthrow new Error('story title must not be null or undefined');\n\t\t}\n\n\t\tconst title = Util.unescape(String(rawTitle)).trim();\n\n\t\tif (title === '') { // lazy equality for null\n\t\t\tthrow new Error('story title must not be empty or consist solely of whitespace');\n\t\t}\n\n\t\tdocument.title = _title = title;\n\n\t\t// TODO: In v3 the `_domId` should be created from a combination of the\n\t\t// `_title` slug and the IFID, if available, to avoid collisions between\n\t\t// stories whose titles generate identical slugs.\n\t\t_domId = Util.slugify(_title);\n\n\t\t// [v2] Protect the `_domId` against being an empty string.\n\t\t//\n\t\t// If `_domId` is empty, attempt a failover.\n\t\tif (_domId === '') {\n\t\t\t// If `_ifId` is not empty, then use it.\n\t\t\tif (_ifId !== '') {\n\t\t\t\t_domId = _ifId;\n\t\t\t}\n\n\t\t\t// Elsewise generate a string from the `_title`'s code points (in hexadecimal).\n\t\t\telse {\n\t\t\t\tfor (let i = 0, len = _title.length; i < len; ++i) {\n\t\t\t\t\tconst { char, start, end } = Util.charAndPosAt(_title, i);\n\t\t\t\t\t_domId += char.codePointAt(0).toString(16);\n\t\t\t\t\ti += end - start;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction storyTitle() {\n\t\treturn _title;\n\t}\n\n\tfunction storyDomId() {\n\t\treturn _domId;\n\t}\n\n\tfunction storyIfId() {\n\t\treturn _ifId;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPassage Functions.\n\t*******************************************************************************************************************/\n\tfunction passagesAdd(passage) {\n\t\tif (!(passage instanceof Passage)) {\n\t\t\tthrow new TypeError('Story.add passage parameter must be an instance of Passage');\n\t\t}\n\n\t\tconst title = passage.title;\n\n\t\tif (!_passages.hasOwnProperty(title)) {\n\t\t\t_passages[title] = passage;\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tfunction passagesHas(title) {\n\t\tlet type = typeof title;\n\n\t\tswitch (type) {\n\t\t// Valid types.\n\t\tcase 'number':\n\t\tcase 'string':\n\t\t\treturn _passages.hasOwnProperty(String(title));\n\n\t\t// Invalid types.  We do the extra processing just to make a nicer error.\n\t\tcase 'undefined':\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\ttype = title === null ? 'null' : 'an object';\n\t\t\tbreak;\n\n\t\tdefault: // 'bigint', 'boolean', 'function', 'symbol'\n\t\t\ttype = `a ${type}`;\n\t\t\tbreak;\n\t\t}\n\n\t\tthrow new TypeError(`Story.has title parameter cannot be ${type}`);\n\t}\n\n\tfunction passagesGet(title) {\n\t\tlet type = typeof title;\n\n\t\tswitch (type) {\n\t\t// Valid types.\n\t\tcase 'number':\n\t\tcase 'string':\n\t\t/* eslint-disable indent */\n\t\t\t{\n\t\t\t\tconst id = String(title);\n\t\t\t\treturn _passages.hasOwnProperty(id) ? _passages[id] : new Passage(id || '(unknown)');\n\t\t\t}\n\t\t/* eslint-enable indent */\n\n\t\t// Invalid types.  We do the extra processing just to make a nicer error.\n\t\tcase 'undefined':\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\ttype = title === null ? 'null' : 'an object';\n\t\t\tbreak;\n\n\t\tdefault: // 'bigint', 'boolean', 'function', 'symbol'\n\t\t\ttype = `a ${type}`;\n\t\t\tbreak;\n\t\t}\n\n\t\tthrow new TypeError(`Story.get title parameter cannot be ${type}`);\n\t}\n\n\tfunction passagesGetAllRegular() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Object.assign({}, _passages));\n\t}\n\n\tfunction passagesGetAllScript() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_scripts));\n\t}\n\n\tfunction passagesGetAllStylesheet() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_styles));\n\t}\n\n\tfunction passagesGetAllWidget() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_widgets));\n\t}\n\n\tfunction passagesLookup(key, value  /* legacy */, sortKey = 'title'/* /legacy */) {\n\t\tconst results = [];\n\n\t\tObject.keys(_passages).forEach(name => {\n\t\t\tconst passage = _passages[name];\n\n\t\t\t// Objects (sans `null`).\n\t\t\tif (typeof passage[key] === 'object' && passage[key] !== null) {\n\t\t\t\t// The only object type currently supported is `Array`, since the\n\t\t\t\t// non-method `Passage` object properties currently yield only either\n\t\t\t\t// primitives or arrays.\n\t\t\t\tif (passage[key] instanceof Array && passage[key].some(m => Util.sameValueZero(m, value))) {\n\t\t\t\t\tresults.push(passage);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// All other types (incl. `null`).\n\t\t\telse if (Util.sameValueZero(passage[key], value)) {\n\t\t\t\tresults.push(passage);\n\t\t\t}\n\t\t});\n\n\t\t// For v3.\n\t\t// /* eslint-disable no-nested-ternary */\n\t\t// // QUESTION: Do we really need to sort the list?\n\t\t// results.sort((a, b) => a.title === b.title ? 0 : a.title < b.title ? -1 : +1);\n\t\t// /* eslint-enable no-nested-ternary */\n\n\t\t/* legacy */\n\t\t/* eslint-disable eqeqeq, no-nested-ternary, max-len */\n\t\tresults.sort((a, b) => a[sortKey] == b[sortKey] ? 0 : a[sortKey] < b[sortKey] ? -1 : +1); // lazy equality for null\n\t\t/* eslint-enable eqeqeq, no-nested-ternary, max-len */\n\t\t/* /legacy */\n\n\t\treturn results;\n\t}\n\n\tfunction passagesLookupWith(predicate /* legacy */, sortKey = 'title'/* /legacy */) {\n\t\tif (typeof predicate !== 'function') {\n\t\t\tthrow new TypeError('Story.lookupWith predicate parameter must be a function');\n\t\t}\n\n\t\tconst results = [];\n\n\t\tObject.keys(_passages).forEach(name => {\n\t\t\tconst passage = _passages[name];\n\n\t\t\tif (predicate(passage)) {\n\t\t\t\tresults.push(passage);\n\t\t\t}\n\t\t});\n\n\t\t// For v3.\n\t\t// /* eslint-disable no-nested-ternary */\n\t\t// // QUESTION: Do we really need to sort the list?\n\t\t// results.sort((a, b) => a.title === b.title ? 0 : a.title < b.title ? -1 : +1);\n\t\t// /* eslint-enable no-nested-ternary */\n\n\t\t/* legacy */\n\t\t/* eslint-disable eqeqeq, no-nested-ternary, max-len */\n\t\tresults.sort((a, b) => a[sortKey] == b[sortKey] ? 0 : a[sortKey] < b[sortKey] ? -1 : +1); // lazy equality for null\n\t\t/* eslint-enable eqeqeq, no-nested-ternary, max-len */\n\t\t/* /legacy */\n\n\t\treturn results;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Story Functions.\n\t\tload  : { value : storyLoad },\n\t\tinit  : { value : storyInit },\n\t\ttitle : { get : storyTitle },\n\t\tdomId : { get : storyDomId },\n\t\tifId  : { get : storyIfId },\n\n\t\t// Passage Functions.\n\t\tadd              : { value : passagesAdd },\n\t\thas              : { value : passagesHas },\n\t\tget              : { value : passagesGet },\n\t\tgetAllRegular    : { value : passagesGetAllRegular },\n\t\tgetAllScript     : { value : passagesGetAllScript },\n\t\tgetAllStylesheet : { value : passagesGetAllStylesheet },\n\t\tgetAllWidget     : { value : passagesGetAllWidget },\n\t\tlookup           : { value : passagesLookup },\n\t\tlookupWith       : { value : passagesLookupWith }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tui.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Dialog, Engine, Has, L10n, Save, Setting, State, Story, Util, Wikifier, Config, errorPrologRegExp,\n\t       settings\n*/\n\nvar UI = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUI Functions, Core.\n\t*******************************************************************************************************************/\n\tfunction uiAssembleLinkList(passage, listEl) {\n\t\tlet list = listEl;\n\n\t\t// Cache the values of `Config.debug` and `Config.cleanupWikifierOutput`,\n\t\t// then disable them during this method's run.\n\t\tconst debugState = Config.debug;\n\t\tconst cleanState = Config.cleanupWikifierOutput;\n\t\tConfig.debug = false;\n\t\tConfig.cleanupWikifierOutput = false;\n\n\t\ttry {\n\t\t\tif (list == null) { // lazy equality for null\n\t\t\t\tlist = document.createElement('ul');\n\t\t\t}\n\n\t\t\t// Wikify the content of the given source passage into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, Story.get(passage).processText().trim());\n\n\t\t\t// Gather the text of any error elements within the fragment…\n\t\t\tconst errors = [...frag.querySelectorAll('.error')]\n\t\t\t\t.map(errEl => errEl.textContent.replace(errorPrologRegExp, ''));\n\n\t\t\t// …and throw an exception, if there were any errors.\n\t\t\tif (errors.length > 0) {\n\t\t\t\tthrow new Error(errors.join('; '));\n\t\t\t}\n\n\t\t\twhile (frag.hasChildNodes()) {\n\t\t\t\tconst node = frag.firstChild;\n\n\t\t\t\t// Create list items for <a>-element nodes.\n\t\t\t\tif (node.nodeType === Node.ELEMENT_NODE && node.nodeName.toUpperCase() === 'A') {\n\t\t\t\t\tconst li = document.createElement('li');\n\t\t\t\t\tlist.appendChild(li);\n\t\t\t\t\tli.appendChild(node);\n\t\t\t\t}\n\n\t\t\t\t// Discard non-<a>-element nodes.\n\t\t\t\telse {\n\t\t\t\t\tfrag.removeChild(node);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\t// Restore the `Config` settings to their original values.\n\t\t\tConfig.cleanupWikifierOutput = cleanState;\n\t\t\tConfig.debug = debugState;\n\t\t}\n\n\t\treturn list;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUI Functions, Built-ins.\n\t*******************************************************************************************************************/\n\tfunction uiOpenAlert(message, /* options, closeFn */ ...args) {\n\t\tjQuery(Dialog.setup('Alert', 'alert'))\n\t\t\t.append(\n\t\t\t\t  `<p>${message}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"alert-ok\" class=\"ui-close\">${L10n.get(['alertOk', 'ok'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t);\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenJumpto(/* options, closeFn */ ...args) {\n\t\tuiBuildJumpto();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenRestart(/* options, closeFn */ ...args) {\n\t\tuiBuildRestart();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenSaves(/* options, closeFn */ ...args) {\n\t\tuiBuildSaves();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenSettings(/* options, closeFn */ ...args) {\n\t\tuiBuildSettings();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenShare(/* options, closeFn */ ...args) {\n\t\tuiBuildShare();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiBuildAutoload() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildAutoload()]'); }\n\n\t\tjQuery(Dialog.setup(L10n.get('autoloadTitle'), 'autoload'))\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  `<p>${L10n.get('autoloadPrompt')}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"autoload-ok\" class=\"ui-close\">${L10n.get(['autoloadOk', 'ok'])}</button></li>`\n\t\t\t\t+ `<li><button id=\"autoload-cancel\" class=\"ui-close\">${L10n.get(['autoloadCancel', 'cancel'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t);\n\n\t\t// Add an additional delegated click handler for the `.ui-close` elements to handle autoloading.\n\t\tjQuery(document).one('click.autoload', '.ui-close', ev => {\n\t\t\tconst isAutoloadOk = ev.target.id === 'autoload-ok';\n\t\t\tjQuery(document).one(':dialogclosed', () => {\n\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\tif (!isAutoloadOk || !Save.autosave.load()) {\n\t\t\t\t\tEngine.play(Config.passages.start);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildJumpto() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildJumpto()]'); }\n\n\t\tconst list = document.createElement('ul');\n\n\t\tjQuery(Dialog.setup(L10n.get('jumptoTitle'), 'jumpto list'))\n\t\t\t.append(list);\n\n\t\tconst expired = State.expired.length;\n\n\t\tfor (let i = State.size - 1; i >= 0; --i) {\n\t\t\tif (i === State.activeIndex) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst passage = Story.get(State.history[i].title);\n\n\t\t\tif (passage && passage.tags.includes('bookmark')) {\n\t\t\t\tjQuery(document.createElement('li'))\n\t\t\t\t\t.append(\n\t\t\t\t\t\tjQuery(document.createElement('a'))\n\t\t\t\t\t\t\t.ariaClick({ one : true }, (function (idx) {\n\t\t\t\t\t\t\t\treturn () => jQuery(document).one(':dialogclosed', () => Engine.goTo(idx));\n\t\t\t\t\t\t\t})(i))\n\t\t\t\t\t\t\t.addClass('ui-close')\n\t\t\t\t\t\t\t.text(`${L10n.get('jumptoTurn')} ${expired + i + 1}: ${passage.description()}`)\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo(list);\n\t\t\t}\n\t\t}\n\n\t\tif (!list.hasChildNodes()) {\n\t\t\tjQuery(list).append(`<li><a><em>${L10n.get('jumptoUnavailable')}</em></a></li>`);\n\t\t}\n\t}\n\n\tfunction uiBuildRestart() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildRestart()]'); }\n\n\t\tjQuery(Dialog.setup(L10n.get('restartTitle'), 'restart'))\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  `<p>${L10n.get('restartPrompt')}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"restart-ok\">${L10n.get(['restartOk', 'ok'])}</button></li>`\n\t\t\t\t+ `<li><button id=\"restart-cancel\" class=\"ui-close\">${L10n.get(['restartCancel', 'cancel'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t)\n\t\t\t.find('#restart-ok')\n\t\t\t/*\n\t\t\t\tInstead of adding '.ui-close' to '#restart-ok' (to receive the use of the default\n\t\t\t\tdelegated dialog close handler), we set up a special case close handler here.  We\n\t\t\t\tdo this to ensure that the invocation of `Engine.restart()` happens after the dialog\n\t\t\t\thas fully closed.  If we did not, then a race condition could occur, causing display\n\t\t\t\tshenanigans.\n\t\t\t*/\n\t\t\t.ariaClick({ one : true }, () => {\n\t\t\t\tjQuery(document).one(':dialogclosed', () => Engine.restart());\n\t\t\t\tDialog.close();\n\t\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildSaves() {\n\t\tfunction createActionItem(bId, bClass, bText, bAction) {\n\t\t\tconst $btn = jQuery(document.createElement('button'))\n\t\t\t\t.attr('id', `saves-${bId}`)\n\t\t\t\t.html(bText);\n\n\t\t\tif (bClass) {\n\t\t\t\t$btn.addClass(bClass);\n\t\t\t}\n\n\t\t\tif (bAction) {\n\t\t\t\t$btn.ariaClick(bAction);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$btn.ariaDisabled(true);\n\t\t\t}\n\n\t\t\treturn jQuery(document.createElement('li'))\n\t\t\t\t.append($btn);\n\t\t}\n\n\t\tfunction createSaveList() {\n\t\t\tfunction createButton(bId, bClass, bText, bSlot, bAction) {\n\t\t\t\tconst $btn = jQuery(document.createElement('button'))\n\t\t\t\t\t.attr('id', `saves-${bId}-${bSlot}`)\n\t\t\t\t\t.addClass(bId)\n\t\t\t\t\t.html(bText);\n\n\t\t\t\tif (bClass) {\n\t\t\t\t\t$btn.addClass(bClass);\n\t\t\t\t}\n\n\t\t\t\tif (bAction) {\n\t\t\t\t\tif (bSlot === 'auto') {\n\t\t\t\t\t\t$btn.ariaClick({\n\t\t\t\t\t\t\tlabel : `${bText} ${L10n.get('savesLabelAuto')}`\n\t\t\t\t\t\t}, () => bAction());\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t$btn.ariaClick({\n\t\t\t\t\t\t\tlabel : `${bText} ${L10n.get('savesLabelSlot')} ${bSlot + 1}`\n\t\t\t\t\t\t}, () => bAction(bSlot));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$btn.ariaDisabled(true);\n\t\t\t\t}\n\n\t\t\t\treturn $btn;\n\t\t\t}\n\n\t\t\tconst saves  = Save.get();\n\t\t\tconst $tbody = jQuery(document.createElement('tbody'));\n\n\t\t\tif (Save.autosave.ok()) {\n\t\t\t\tconst $tdSlot = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdLoad = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDesc = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDele = jQuery(document.createElement('td'));\n\n\t\t\t\t// Add the slot ID.\n\t\t\t\tjQuery(document.createElement('b'))\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttitle        : L10n.get('savesLabelAuto'),\n\t\t\t\t\t\t'aria-label' : L10n.get('savesLabelAuto')\n\t\t\t\t\t})\n\t\t\t\t\t.text('A') // '\\u25C6' Black Diamond\n\t\t\t\t\t.appendTo($tdSlot);\n\n\t\t\t\tif (saves.autosave) {\n\t\t\t\t\t// Add the load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('load', 'ui-close', L10n.get('savesLabelLoad'), 'auto', () => {\n\t\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.autosave.load());\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description (title and datestamp).\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.text(saves.autosave.title)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.addClass('datestamp')\n\t\t\t\t\t\t.html(\n\t\t\t\t\t\t\tsaves.autosave.date\n\t\t\t\t\t\t\t\t? `${new Date(saves.autosave.date).toLocaleString()}`\n\t\t\t\t\t\t\t\t: `<em>${L10n.get('savesUnknownDate')}</em>`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\n\t\t\t\t\t// Add the delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), 'auto', () => {\n\t\t\t\t\t\t\tSave.autosave.delete();\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Add the disabled load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('load', null, L10n.get('savesLabelLoad'), 'auto')\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description.\n\t\t\t\t\t$tdDesc.addClass('empty').text('\\u2022\\u00a0\\u00a0\\u2022\\u00a0\\u00a0\\u2022');\n\n\t\t\t\t\t// Add the disabled delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), 'auto')\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t.append($tdSlot)\n\t\t\t\t\t.append($tdLoad)\n\t\t\t\t\t.append($tdDesc)\n\t\t\t\t\t.append($tdDele)\n\t\t\t\t\t.appendTo($tbody);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = saves.slots.length; i < iend; ++i) {\n\t\t\t\tconst $tdSlot = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdLoad = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDesc = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDele = jQuery(document.createElement('td'));\n\n\t\t\t\t// Add the slot ID.\n\t\t\t\t$tdSlot.append(document.createTextNode(i + 1));\n\n\t\t\t\tif (saves.slots[i]) {\n\t\t\t\t\t// Add the load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('save', 'ui-close', L10n.get('savesLabelSave'), i, Save.slots.save),\n\t\t\t\t\t\tcreateButton('load', 'ui-close', L10n.get('savesLabelLoad'), i, slot => {\n\t\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.slots.load(slot));\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description (title and datestamp).\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.text(saves.slots[i].title)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.addClass('datestamp')\n\t\t\t\t\t\t.html(\n\t\t\t\t\t\t\tsaves.slots[i].date\n\t\t\t\t\t\t\t\t? `${new Date(saves.slots[i].date).toLocaleString()}`\n\t\t\t\t\t\t\t\t: `<em>${L10n.get('savesUnknownDate')}</em>`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\n\t\t\t\t\t// Add the delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), i, slot => {\n\t\t\t\t\t\t\tSave.slots.delete(slot);\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Add the save button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('save', 'ui-close', L10n.get('savesLabelSave'), i, Save.slots.save)\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description.\n\t\t\t\t\t$tdDesc.addClass('empty').text('\\u2022\\u00a0\\u00a0\\u2022\\u00a0\\u00a0\\u2022');\n\n\t\t\t\t\t// Add the disabled delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), i)\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t.append($tdSlot)\n\t\t\t\t\t.append($tdLoad)\n\t\t\t\t\t.append($tdDesc)\n\t\t\t\t\t.append($tdDele)\n\t\t\t\t\t.appendTo($tbody);\n\t\t\t}\n\n\t\t\treturn jQuery(document.createElement('table'))\n\t\t\t\t.attr('id', 'saves-list')\n\t\t\t\t.append($tbody);\n\t\t}\n\n\t\tif (DEBUG) { console.log('[UI/uiBuildSaves()]'); }\n\n\t\tconst $dialogBody = jQuery(Dialog.setup(L10n.get('savesTitle'), 'saves'));\n\t\tconst savesOk     = Save.ok();\n\n\t\t// Add saves list.\n\t\tif (savesOk) {\n\t\t\t$dialogBody.append(createSaveList());\n\t\t}\n\n\t\t// Add button bar items (export, import, and clear).\n\t\tif (savesOk || Has.fileAPI) {\n\t\t\tconst $btnBar = jQuery(document.createElement('ul'))\n\t\t\t\t.addClass('buttons')\n\t\t\t\t.appendTo($dialogBody);\n\n\t\t\tif (Has.fileAPI) {\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'export',\n\t\t\t\t\t'ui-close',\n\t\t\t\t\tL10n.get('savesLabelExport'),\n\t\t\t\t\t() => Save.export()\n\t\t\t\t));\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'import',\n\t\t\t\t\tnull,\n\t\t\t\t\tL10n.get('savesLabelImport'),\n\t\t\t\t\t() => $dialogBody.find('#saves-import-file').trigger('click')\n\t\t\t\t));\n\n\t\t\t\t// Add the hidden `input[type=file]` element which will be triggered by the `#saves-import` button.\n\t\t\t\tjQuery(document.createElement('input'))\n\t\t\t\t\t.css({\n\t\t\t\t\t\tdisplay    : 'block',\n\t\t\t\t\t\tvisibility : 'hidden',\n\t\t\t\t\t\tposition   : 'fixed',\n\t\t\t\t\t\tleft       : '-9999px',\n\t\t\t\t\t\ttop        : '-9999px',\n\t\t\t\t\t\twidth      : '1px',\n\t\t\t\t\t\theight     : '1px'\n\t\t\t\t\t})\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttype          : 'file',\n\t\t\t\t\t\tid            : 'saves-import-file',\n\t\t\t\t\t\ttabindex      : -1,\n\t\t\t\t\t\t'aria-hidden' : true\n\t\t\t\t\t})\n\t\t\t\t\t.on('change', ev => {\n\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.import(ev));\n\t\t\t\t\t\tDialog.close();\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo($dialogBody);\n\t\t\t}\n\n\t\t\tif (savesOk) {\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'clear',\n\t\t\t\t\tnull,\n\t\t\t\t\tL10n.get('savesLabelClear'),\n\t\t\t\t\tSave.autosave.has() || !Save.slots.isEmpty()\n\t\t\t\t\t\t? () => {\n\t\t\t\t\t\t\tSave.clear();\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t: null\n\t\t\t\t));\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tuiOpenAlert(L10n.get('savesIncapable'));\n\t\treturn false;\n\t}\n\n\tfunction uiBuildSettings() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildSettings()]'); }\n\n\t\tconst $dialogBody = jQuery(Dialog.setup(L10n.get('settingsTitle'), 'settings'));\n\n\t\tSetting.forEach(control => {\n\t\t\tif (control.type === Setting.Types.Header) {\n\t\t\t\tconst name     = control.name;\n\t\t\t\tconst id       = Util.slugify(name);\n\t\t\t\tconst $header  = jQuery(document.createElement('div'));\n\t\t\t\tconst $heading = jQuery(document.createElement('h2'));\n\n\t\t\t\t$header\n\t\t\t\t\t.attr('id', `header-body-${id}`)\n\t\t\t\t\t.append($heading)\n\t\t\t\t\t.appendTo($dialogBody);\n\t\t\t\t$heading\n\t\t\t\t\t.attr('id', `header-heading-${id}`)\n\t\t\t\t\t.wiki(name);\n\n\t\t\t\t// Set up the description, if any.\n\t\t\t\tif (control.desc) {\n\t\t\t\t\tjQuery(document.createElement('p'))\n\t\t\t\t\t\t.attr('id', `header-desc-${id}`)\n\t\t\t\t\t\t.wiki(control.desc)\n\t\t\t\t\t\t.appendTo($header);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst name        = control.name;\n\t\t\tconst id          = Util.slugify(name);\n\t\t\tconst $setting    = jQuery(document.createElement('div'));\n\t\t\tconst $label      = jQuery(document.createElement('label'));\n\t\t\tconst $controlBox = jQuery(document.createElement('div'));\n\t\t\tlet $control;\n\n\t\t\t// Set up the label+control wrapper.\n\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t.append($label)\n\t\t\t\t.append($controlBox)\n\t\t\t\t.appendTo($setting);\n\n\t\t\t// Set up the description, if any.\n\t\t\tif (control.desc) {\n\t\t\t\tjQuery(document.createElement('p'))\n\t\t\t\t\t.attr('id', `setting-desc-${id}`)\n\t\t\t\t\t.wiki(control.desc)\n\t\t\t\t\t.appendTo($setting);\n\t\t\t}\n\n\t\t\t// Set up the label.\n\t\t\t$label\n\t\t\t\t.attr({\n\t\t\t\t\tid  : `setting-label-${id}`,\n\t\t\t\t\tfor : `setting-control-${id}` // must be in sync with $control's ID (see below)\n\t\t\t\t})\n\t\t\t\t.wiki(control.label);\n\n\t\t\t// Set up the control.\n\t\t\tif (settings[name] == null) { // lazy equality for null\n\t\t\t\tsettings[name] = control.default;\n\t\t\t}\n\n\t\t\tswitch (control.type) {\n\t\t\tcase Setting.Types.Toggle:\n\t\t\t\t$control = jQuery(document.createElement('button'));\n\n\t\t\t\tif (settings[name]) {\n\t\t\t\t\t$control\n\t\t\t\t\t\t.addClass('enabled')\n\t\t\t\t\t\t.text(L10n.get('settingsOn'));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$control\n\t\t\t\t\t\t.text(L10n.get('settingsOff'));\n\t\t\t\t}\n\n\t\t\t\t$control.ariaClick(function () {\n\t\t\t\t\tif (settings[name]) {\n\t\t\t\t\t\tjQuery(this)\n\t\t\t\t\t\t\t.removeClass('enabled')\n\t\t\t\t\t\t\t.text(L10n.get('settingsOff'));\n\t\t\t\t\t\tsettings[name] = false;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tjQuery(this)\n\t\t\t\t\t\t\t.addClass('enabled')\n\t\t\t\t\t\t\t.text(L10n.get('settingsOn'));\n\t\t\t\t\t\tsettings[name] = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tSetting.save();\n\n\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\tdefault : control.default\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase Setting.Types.List:\n\t\t\t\t$control = jQuery(document.createElement('select'));\n\n\t\t\t\tfor (let i = 0, iend = control.list.length; i < iend; ++i) {\n\t\t\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t\t\t.val(i)\n\t\t\t\t\t\t.text(control.list[i])\n\t\t\t\t\t\t.appendTo($control);\n\t\t\t\t}\n\n\t\t\t\t$control\n\t\t\t\t\t.val(control.list.indexOf(settings[name]))\n\t\t\t\t\t.attr('tabindex', 0)\n\t\t\t\t\t.on('change', function () {\n\t\t\t\t\t\tsettings[name] = control.list[Number(this.value)];\n\t\t\t\t\t\tSetting.save();\n\n\t\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\t\tdefault : control.default,\n\t\t\t\t\t\t\t\tlist    : control.list\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase Setting.Types.Range:\n\t\t\t\t$control = jQuery(document.createElement('input'));\n\n\t\t\t\t// NOTE: Setting the value with `<jQuery>.val()` can cause odd behavior\n\t\t\t\t// in Edge if it's called before the type is set, so we use the `value`\n\t\t\t\t// content attribute here to dodge the entire issue.\n\t\t\t\t$control\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttype     : 'range',\n\t\t\t\t\t\tmin      : control.min,\n\t\t\t\t\t\tmax      : control.max,\n\t\t\t\t\t\tstep     : control.step,\n\t\t\t\t\t\tvalue    : settings[name],\n\t\t\t\t\t\ttabindex : 0\n\t\t\t\t\t})\n\t\t\t\t\t.on('change input', function () {\n\t\t\t\t\t\tsettings[name] = Number(this.value);\n\t\t\t\t\t\tSetting.save();\n\n\t\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\t\tdefault : control.default,\n\t\t\t\t\t\t\t\tmin     : control.min,\n\t\t\t\t\t\t\t\tmax     : control.max,\n\t\t\t\t\t\t\t\tstep    : control.step\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.on('keypress', ev => {\n\t\t\t\t\t\tif (ev.which === 13) {\n\t\t\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t\t\t$control.trigger('change');\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$control\n\t\t\t\t.attr('id', `setting-control-${id}`)\n\t\t\t\t.appendTo($controlBox);\n\n\t\t\t$setting\n\t\t\t\t.attr('id', `setting-body-${id}`)\n\t\t\t\t.appendTo($dialogBody);\n\t\t});\n\n\t\t// Add the button bar.\n\t\t$dialogBody\n\t\t\t.append(\n\t\t\t\t  '<ul class=\"buttons\">'\n\t\t\t\t+     `<li><button id=\"settings-ok\" class=\"ui-close\">${L10n.get(['settingsOk', 'ok'])}</button></li>`\n\t\t\t\t+     `<li><button id=\"settings-reset\">${L10n.get('settingsReset')}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t)\n\t\t\t.find('#settings-reset')\n\t\t\t/*\n\t\t\t\tInstead of adding '.ui-close' to '#settings-reset' (to receive the use of the default\n\t\t\t\tdelegated dialog close handler), we set up a special case close handler here.  We\n\t\t\t\tdo this to ensure that the invocation of `window.location.reload()` happens after the\n\t\t\t\tdialog has fully closed.  If we did not, then a race condition could occur, causing\n\t\t\t\tdisplay shenanigans.\n\t\t\t*/\n\t\t\t.ariaClick({ one : true }, () => {\n\t\t\t\tjQuery(document).one(':dialogclosed', () => {\n\t\t\t\t\tSetting.reset();\n\t\t\t\t\twindow.location.reload();\n\t\t\t\t});\n\t\t\t\tDialog.close();\n\t\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildShare() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildShare()]'); }\n\n\t\ttry {\n\t\t\tjQuery(Dialog.setup(L10n.get('shareTitle'), 'share list'))\n\t\t\t\t.append(uiAssembleLinkList('StoryShare'));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tconsole.error(ex);\n\t\t\tAlert.error('StoryShare', ex.message);\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tUI Functions, Core.\n\t\t*/\n\t\tassembleLinkList : { value : uiAssembleLinkList },\n\n\t\t/*\n\t\t\tUI Functions, Built-ins.\n\t\t*/\n\t\talert         : { value : uiOpenAlert },\n\t\tjumpto        : { value : uiOpenJumpto },\n\t\trestart       : { value : uiOpenRestart },\n\t\tsaves         : { value : uiOpenSaves },\n\t\tsettings      : { value : uiOpenSettings },\n\t\tshare         : { value : uiOpenShare },\n\t\tbuildAutoload : { value : uiBuildAutoload },\n\t\tbuildJumpto   : { value : uiBuildJumpto },\n\t\tbuildRestart  : { value : uiBuildRestart },\n\t\tbuildSaves    : { value : uiBuildSaves },\n\t\tbuildSettings : { value : uiBuildSettings },\n\t\tbuildShare    : { value : uiBuildShare },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\t// `UIBar` methods.\n\t\t/* global UIBar */\n\t\tstow                     : { value : () => UIBar.stow() },\n\t\tunstow                   : { value : () => UIBar.unstow() },\n\t\tsetStoryElements         : { value : () => UIBar.update() },\n\t\t// `Dialog` methods.\n\t\tisOpen                   : { value : (...args) => Dialog.isOpen(...args) },\n\t\tbody                     : { value : () => Dialog.body() },\n\t\tsetup                    : { value : (...args) => Dialog.setup(...args) },\n\t\taddClickHandler          : { value : (...args) => Dialog.addClickHandler(...args) },\n\t\topen                     : { value : (...args) => Dialog.open(...args) },\n\t\tclose                    : { value : (...args) => Dialog.close(...args) },\n\t\tresize                   : { value : () => Dialog.resize() },\n\t\t// Deprecated method names.\n\t\tbuildDialogAutoload      : { value : uiBuildAutoload },\n\t\tbuildDialogJumpto        : { value : uiBuildJumpto },\n\t\tbuildDialogRestart       : { value : uiBuildRestart },\n\t\tbuildDialogSaves         : { value : uiBuildSaves },\n\t\tbuildDialogSettings      : { value : uiBuildSettings },\n\t\tbuildDialogShare         : { value : uiBuildShare },\n\t\tbuildLinkListFromPassage : { value : uiAssembleLinkList }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tuibar.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Dialog, Engine, L10n, Setting, State, Story, UI, Config, setDisplayTitle, setPageElement\n*/\n\nvar UIBar = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// UI bar element cache.\n\tlet _$uiBar = null;\n\n\n\t/*******************************************************************************\n\t\tUI Bar Functions.\n\t*******************************************************************************/\n\n\tfunction uiBarDestroy() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarDestroy()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Hide the UI bar.\n\t\t_$uiBar.hide();\n\n\t\t// Remove its namespaced events.\n\t\tjQuery(document).off('.ui-bar');\n\n\t\t// Remove its styles.\n\t\tjQuery(document.head).find('#style-ui-bar').remove();\n\n\t\t// Remove it from the DOM.\n\t\t_$uiBar.remove();\n\n\t\t// Drop the reference to the element.\n\t\t_$uiBar = null;\n\t}\n\n\tfunction uiBarHide() {\n\t\tif (_$uiBar) {\n\t\t\t_$uiBar.hide();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarInit() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarInit()]'); }\n\n\t\tif (document.getElementById('ui-bar')) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Generate the UI bar elements.\n\t\tconst $elems = (() => {\n\t\t\tconst toggleLabel   = L10n.get('uiBarToggle');\n\t\t\tconst backwardLabel = L10n.get('uiBarBackward');\n\t\t\tconst jumptoLabel   = L10n.get('uiBarJumpto');\n\t\t\tconst forwardLabel  = L10n.get('uiBarForward');\n\n\t\t\treturn jQuery(document.createDocumentFragment())\n\t\t\t\t.append(\n\t\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t\t  '<div id=\"ui-bar\">'\n\t\t\t\t\t+     '<div id=\"ui-bar-tray\">'\n\t\t\t\t\t+         `<button id=\"ui-bar-toggle\" tabindex=\"0\" title=\"${toggleLabel}\" aria-label=\"${toggleLabel}\"></button>`\n\t\t\t\t\t+         '<div id=\"ui-bar-history\">'\n\t\t\t\t\t+             `<button id=\"history-backward\" tabindex=\"0\" title=\"${backwardLabel}\" aria-label=\"${backwardLabel}\">\\uE821</button>`\n\t\t\t\t\t+             `<button id=\"history-jumpto\" tabindex=\"0\" title=\"${jumptoLabel}\" aria-label=\"${jumptoLabel}\">\\uE839</button>`\n\t\t\t\t\t+             `<button id=\"history-forward\" tabindex=\"0\" title=\"${forwardLabel}\" aria-label=\"${forwardLabel}\">\\uE822</button>`\n\t\t\t\t\t+         '</div>'\n\t\t\t\t\t+     '</div>'\n\t\t\t\t\t+     '<div id=\"ui-bar-body\">'\n\t\t\t\t\t+         '<header id=\"title\" role=\"banner\">'\n\t\t\t\t\t+             '<div id=\"story-banner\"></div>'\n\t\t\t\t\t+             '<h1 id=\"story-title\"></h1>'\n\t\t\t\t\t+             '<div id=\"story-subtitle\"></div>'\n\t\t\t\t\t+             '<div id=\"story-title-separator\"></div>'\n\t\t\t\t\t+             '<p id=\"story-author\"></p>'\n\t\t\t\t\t+         '</header>'\n\t\t\t\t\t+         '<div id=\"story-caption\"></div>'\n\t\t\t\t\t+         '<nav id=\"menu\" role=\"navigation\">'\n\t\t\t\t\t+             '<ul id=\"menu-story\"></ul>'\n\t\t\t\t\t+             '<ul id=\"menu-core\">'\n\t\t\t\t\t+                 `<li id=\"menu-item-saves\"><a tabindex=\"0\">${L10n.get('savesTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-settings\"><a tabindex=\"0\">${L10n.get('settingsTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-restart\"><a tabindex=\"0\">${L10n.get('restartTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-share\"><a tabindex=\"0\">${L10n.get('shareTitle')}</a></li>`\n\t\t\t\t\t+             '</ul>'\n\t\t\t\t\t+         '</nav>'\n\t\t\t\t\t+     '</div>'\n\t\t\t\t\t+ '</div>'\n\t\t\t\t\t/* eslint-enable max-len */\n\t\t\t\t);\n\t\t})();\n\n\t\t/*\n\t\t\tCache the UI bar element, since its going to be used often.\n\n\t\t\tNOTE: We rewrap the element itself, rather than simply using the result\n\t\t\tof `find()`, so that we cache an uncluttered jQuery-wrapper (i.e. `context`\n\t\t\trefers to the element and there is no `prevObject`).\n\t\t*/\n\t\t_$uiBar = jQuery($elems.find('#ui-bar').get(0));\n\n\t\t// Insert the UI bar elements into the page before the main script.\n\t\t$elems.insertBefore('body>script#script-sugarcube');\n\n\t\t// Set up the UI bar's global event handlers.\n\t\tjQuery(document)\n\t\t\t// Set up a handler for the history-backward/-forward buttons.\n\t\t\t.on(':historyupdate.ui-bar', (($backward, $forward) => () => {\n\t\t\t\t$backward.ariaDisabled(State.length < 2);\n\t\t\t\t$forward.ariaDisabled(State.length === State.size);\n\t\t\t})(jQuery('#history-backward'), jQuery('#history-forward')));\n\t}\n\n\tfunction uiBarIsHidden() {\n\t\treturn _$uiBar && _$uiBar.css('display') === 'none';\n\t}\n\n\tfunction uiBarIsStowed() {\n\t\treturn _$uiBar && _$uiBar.hasClass('stowed');\n\t}\n\n\tfunction uiBarShow() {\n\t\tif (_$uiBar) {\n\t\t\t_$uiBar.show();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarStart() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarStart()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Set up the #ui-bar's initial state.\n\t\tif (\n\t\t\ttypeof Config.ui.stowBarInitially === 'boolean'\n\t\t\t\t? Config.ui.stowBarInitially\n\t\t\t\t: jQuery(window).width() <= Config.ui.stowBarInitially\n\t\t) {\n\t\t\tuiBarStow(true);\n\t\t}\n\n\t\t// Set up the #ui-bar-toggle and #ui-bar-history widgets.\n\t\tjQuery('#ui-bar-toggle')\n\t\t\t.ariaClick({\n\t\t\t\tlabel : L10n.get('uiBarToggle')\n\t\t\t}, () => _$uiBar.toggleClass('stowed'));\n\n\t\tif (Config.history.controls) {\n\t\t\tjQuery('#history-backward')\n\t\t\t\t.ariaDisabled(State.length < 2)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tlabel : L10n.get('uiBarBackward')\n\t\t\t\t}, () => Engine.backward());\n\n\t\t\tif (Story.lookup('tags', 'bookmark').length > 0) {\n\t\t\t\tjQuery('#history-jumpto')\n\t\t\t\t\t.ariaClick({\n\t\t\t\t\t\tlabel : L10n.get('uiBarJumpto')\n\t\t\t\t\t}, () => UI.jumpto());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery('#history-jumpto').remove();\n\t\t\t}\n\n\t\t\tjQuery('#history-forward')\n\t\t\t\t.ariaDisabled(State.length === State.size)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tlabel : L10n.get('uiBarForward')\n\t\t\t\t}, () => Engine.forward());\n\t\t}\n\t\telse {\n\t\t\tjQuery('#ui-bar-history').remove();\n\t\t}\n\n\t\t// Set up the story display title.\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t}\n\t\telse {\n\t\t\tif (TWINE1) { // for Twine 1\n\t\t\t\tsetPageElement('story-title', 'StoryTitle', Story.title);\n\t\t\t}\n\t\t\telse { // for Twine 2\n\t\t\t\tjQuery('#story-title').text(Story.title);\n\t\t\t}\n\t\t}\n\n\t\t// Set up the dynamic page elements.\n\t\tif (!Story.has('StoryCaption')) {\n\t\t\tjQuery('#story-caption').remove();\n\t\t}\n\n\t\tif (!Story.has('StoryMenu')) {\n\t\t\tjQuery('#menu-story').remove();\n\t\t}\n\n\t\tif (!Config.ui.updateStoryElements) {\n\t\t\t// We only need to set the story elements here if `Config.ui.updateStoryElements`\n\t\t\t// is falsy, since otherwise they will be set by `Engine.play()`.\n\t\t\tuiBarUpdate();\n\t\t}\n\n\t\t// Set up the Saves menu item.\n\t\tjQuery('#menu-item-saves a')\n\t\t\t.ariaClick(ev => {\n\t\t\t\tev.preventDefault();\n\t\t\t\tUI.buildSaves();\n\t\t\t\tDialog.open();\n\t\t\t})\n\t\t\t.text(L10n.get('savesTitle'));\n\n\t\t// Set up the Settings menu item.\n\t\tif (!Setting.isEmpty()) {\n\t\t\tjQuery('#menu-item-settings a')\n\t\t\t\t.ariaClick(ev => {\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\tUI.buildSettings();\n\t\t\t\t\tDialog.open();\n\t\t\t\t})\n\t\t\t\t.text(L10n.get('settingsTitle'));\n\t\t}\n\t\telse {\n\t\t\tjQuery('#menu-item-settings').remove();\n\t\t}\n\n\t\t// Set up the Restart menu item.\n\t\tjQuery('#menu-item-restart a')\n\t\t\t.ariaClick(ev => {\n\t\t\t\tev.preventDefault();\n\t\t\t\tUI.buildRestart();\n\t\t\t\tDialog.open();\n\t\t\t})\n\t\t\t.text(L10n.get('restartTitle'));\n\n\t\t// Set up the Share menu item.\n\t\tif (Story.has('StoryShare')) {\n\t\t\tjQuery('#menu-item-share a')\n\t\t\t\t.ariaClick(ev => {\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\tUI.buildShare();\n\t\t\t\t\tDialog.open();\n\t\t\t\t})\n\t\t\t\t.text(L10n.get('shareTitle'));\n\t\t}\n\t\telse {\n\t\t\tjQuery('#menu-item-share').remove();\n\t\t}\n\t}\n\n\tfunction uiBarStow(noAnimation) {\n\t\tif (_$uiBar && !_$uiBar.hasClass('stowed')) {\n\t\t\tlet $story;\n\n\t\t\tif (noAnimation) {\n\t\t\t\t$story = jQuery('#story');\n\t\t\t\t$story.addClass('no-transition');\n\t\t\t\t_$uiBar.addClass('no-transition');\n\t\t\t}\n\n\t\t\t_$uiBar.addClass('stowed');\n\n\t\t\tif (noAnimation) {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t$story.removeClass('no-transition');\n\t\t\t\t\t_$uiBar.removeClass('no-transition');\n\t\t\t\t}, Engine.minDomActionDelay);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarUnstow(noAnimation) {\n\t\tif (_$uiBar && _$uiBar.hasClass('stowed')) {\n\t\t\tlet $story;\n\n\t\t\tif (noAnimation) {\n\t\t\t\t$story = jQuery('#story');\n\t\t\t\t$story.addClass('no-transition');\n\t\t\t\t_$uiBar.addClass('no-transition');\n\t\t\t}\n\n\t\t\t_$uiBar.removeClass('stowed');\n\n\t\t\tif (noAnimation) {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t$story.removeClass('no-transition');\n\t\t\t\t\t_$uiBar.removeClass('no-transition');\n\t\t\t\t}, Engine.minDomActionDelay);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarUpdate() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarUpdate()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Set up the (non-navigation) dynamic page elements.\n\t\tsetPageElement('story-banner', 'StoryBanner');\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t}\n\t\tsetPageElement('story-subtitle', 'StorySubtitle');\n\t\tsetPageElement('story-author', 'StoryAuthor');\n\t\tsetPageElement('story-caption', 'StoryCaption');\n\n\t\t// Set up the #menu-story items.\n\t\tconst menuStory = document.getElementById('menu-story');\n\n\t\tif (menuStory !== null) {\n\t\t\tjQuery(menuStory).empty();\n\n\t\t\tif (Story.has('StoryMenu')) {\n\t\t\t\ttry {\n\t\t\t\t\tUI.assembleLinkList('StoryMenu', menuStory);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\tconsole.error(ex);\n\t\t\t\t\tAlert.error('StoryMenu', ex.message);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tdestroy  : { value : uiBarDestroy },\n\t\thide     : { value : uiBarHide },\n\t\tinit     : { value : uiBarInit },\n\t\tisHidden : { value : uiBarIsHidden },\n\t\tisStowed : { value : uiBarIsStowed },\n\t\tshow     : { value : uiBarShow },\n\t\tstart    : { value : uiBarStart },\n\t\tstow     : { value : uiBarStow },\n\t\tunstow   : { value : uiBarUnstow },\n\t\tupdate   : { value : uiBarUpdate },\n\n\t\t// Legacy Functions.\n\t\tsetStoryElements : { value : uiBarUpdate }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tdebugbar.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal DebugView, Engine, L10n, Patterns, State, Util, session\n*/\n\nvar DebugBar = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tconst _variableRe   = new RegExp(`^${Patterns.variable}$`);\n\tconst _numericKeyRe = /^\\d+$/;\n\tconst _watchList    = [];\n\tlet _$debugBar   = null;\n\tlet _$watchBody  = null;\n\tlet _$watchList  = null;\n\tlet _$turnSelect = null;\n\tlet _stowed      = true;\n\n\n\t/*******************************************************************************************************************\n\t\tDebug Bar Functions.\n\t*******************************************************************************************************************/\n\tfunction debugBarInit() {\n\t\tif (DEBUG) { console.log('[DebugBar/debugBarInit()]'); }\n\n\t\t/*\n\t\t\tGenerate the debug bar elements and append them to the `<body>`.\n\t\t*/\n\t\tconst barToggleLabel   = L10n.get('debugBarToggle');\n\t\tconst watchAddLabel    = L10n.get('debugBarAddWatch');\n\t\tconst watchAllLabel    = L10n.get('debugBarWatchAll');\n\t\tconst watchNoneLabel   = L10n.get('debugBarWatchNone');\n\t\tconst watchToggleLabel = L10n.get('debugBarWatchToggle');\n\t\tconst viewsToggleLabel = L10n.get('debugBarViewsToggle');\n\n\t\tjQuery(document.createDocumentFragment())\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  '<div id=\"debug-bar\">'\n\t\t\t\t+     '<div id=\"debug-bar-watch\">'\n\t\t\t\t+         `<div>${L10n.get('debugBarNoWatches')}</div>>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div>'\n\t\t\t\t+         `<button id=\"debug-bar-watch-toggle\" tabindex=\"0\" title=\"${watchToggleLabel}\" aria-label=\"${watchToggleLabel}\">${L10n.get('debugBarLabelWatch')}</button>`\n\t\t\t\t+         `<label id=\"debug-bar-watch-label\" for=\"debug-bar-watch-input\">${L10n.get('debugBarLabelAdd')}</label>`\n\t\t\t\t+         '<input id=\"debug-bar-watch-input\" name=\"debug-bar-watch-input\" type=\"text\" list=\"debug-bar-watch-list\" tabindex=\"0\">'\n\t\t\t\t+         '<datalist id=\"debug-bar-watch-list\" aria-hidden=\"true\" hidden=\"hidden\"></datalist>'\n\t\t\t\t+         `<button id=\"debug-bar-watch-add\" tabindex=\"0\" title=\"${watchAddLabel}\" aria-label=\"${watchAddLabel}\"></button>`\n\t\t\t\t+         `<button id=\"debug-bar-watch-all\" tabindex=\"0\" title=\"${watchAllLabel}\" aria-label=\"${watchAllLabel}\"></button>`\n\t\t\t\t+         `<button id=\"debug-bar-watch-none\" tabindex=\"0\" title=\"${watchNoneLabel}\" aria-label=\"${watchNoneLabel}\"></button>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div>'\n\t\t\t\t+         `<button id=\"debug-bar-views-toggle\" tabindex=\"0\" title=\"${viewsToggleLabel}\" aria-label=\"${viewsToggleLabel}\">${L10n.get('debugBarLabelViews')}</button>`\n\t\t\t\t+         `<label id=\"debug-bar-turn-label\" for=\"debug-bar-turn-select\">${L10n.get('debugBarLabelTurn')}</label>`\n\t\t\t\t+         '<select id=\"debug-bar-turn-select\" tabindex=\"0\"></select>'\n\t\t\t\t+     '</div>'\n\t\t\t\t+     `<button id=\"debug-bar-toggle\" tabindex=\"0\" title=\"${barToggleLabel}\" aria-label=\"${barToggleLabel}\"></button>`\n\t\t\t\t+ '</div>'\n\t\t\t\t+ '<div id=\"debug-bar-hint\"></div>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t)\n\t\t\t.appendTo('body');\n\n\t\t/*\n\t\t\tCache various oft used elements.\n\n\t\t\tNOTE: We rewrap the elements themselves, rather than simply using\n\t\t\tthe results of `find()`, so that we cache uncluttered jQuery-wrappers\n\t\t\t(i.e. `context` refers to the elements and there is no `prevObject`).\n\t\t*/\n\t\t_$debugBar   = jQuery('#debug-bar');\n\t\t_$watchBody  = jQuery(_$debugBar.find('#debug-bar-watch').get(0));\n\t\t_$watchList  = jQuery(_$debugBar.find('#debug-bar-watch-list').get(0));\n\t\t_$turnSelect = jQuery(_$debugBar.find('#debug-bar-turn-select').get(0));\n\n\t\tconst $barToggle   = jQuery(_$debugBar.find('#debug-bar-toggle').get(0));\n\t\tconst $watchToggle = jQuery(_$debugBar.find('#debug-bar-watch-toggle').get(0));\n\t\tconst $watchInput  = jQuery(_$debugBar.find('#debug-bar-watch-input').get(0));\n\t\tconst $watchAdd    = jQuery(_$debugBar.find('#debug-bar-watch-add').get(0));\n\t\tconst $watchAll    = jQuery(_$debugBar.find('#debug-bar-watch-all').get(0));\n\t\tconst $watchNone   = jQuery(_$debugBar.find('#debug-bar-watch-none').get(0));\n\t\tconst $viewsToggle = jQuery(_$debugBar.find('#debug-bar-views-toggle').get(0));\n\n\t\t/*\n\t\t\tSet up the debug bar's local event handlers.\n\t\t*/\n\t\t$barToggle\n\t\t\t.ariaClick(debugBarToggle);\n\t\t$watchToggle\n\t\t\t.ariaClick(debugBarWatchToggle);\n\t\t$watchInput\n\t\t\t.on(':addwatch', function () {\n\t\t\t\tdebugBarWatchAdd(this.value.trim());\n\t\t\t\tthis.value = '';\n\t\t\t})\n\t\t\t.on('keypress', ev => {\n\t\t\t\tif (ev.which === 13) { // 13 is Return/Enter\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t$watchInput.trigger(':addwatch');\n\t\t\t\t}\n\t\t\t});\n\t\t$watchAdd\n\t\t\t.ariaClick(() => $watchInput.trigger(':addwatch'));\n\t\t$watchAll\n\t\t\t.ariaClick(debugBarWatchAddAll);\n\t\t$watchNone\n\t\t\t.ariaClick(debugBarWatchClear);\n\t\t_$turnSelect\n\t\t\t.on('change', function () {\n\t\t\t\tEngine.goTo(Number(this.value));\n\t\t\t});\n\t\t$viewsToggle\n\t\t\t.ariaClick(() => {\n\t\t\t\tDebugView.toggle();\n\t\t\t\t_updateSession();\n\t\t\t});\n\n\t\t/*\n\t\t\tSet up the debug bar's global event handlers.\n\t\t*/\n\t\tjQuery(document)\n\t\t\t// Set up a handler for the history select.\n\t\t\t.on(':historyupdate.debug-bar', _updateTurnSelect)\n\t\t\t// Set up a handler for the variables watch.\n\t\t\t.on(':passageend.debug-bar', () => {\n\t\t\t\t_updateWatchBody();\n\t\t\t\t_updateWatchList();\n\t\t\t})\n\t\t\t// Set up a handler for engine resets to clear the active debug session.\n\t\t\t.on(':enginerestart.debug-bar', _clearSession);\n\n\t\t/*\n\t\t\tInitially enable debug views if there's no active debug session.\n\t\t*/\n\t\tif (!_hasSession()) {\n\t\t\tDebugView.enable();\n\t\t}\n\t}\n\n\tfunction debugBarStart() {\n\t\tif (DEBUG) { console.log('[DebugBar/debugBarStart()]'); }\n\n\t\t// Attempt to restore an existing session.\n\t\t_restoreSession();\n\n\t\t// Update the UI.\n\t\t_updateBar();\n\t\t_updateTurnSelect();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t}\n\n\tfunction debugBarIsStowed() {\n\t\treturn _stowed;\n\t}\n\n\tfunction debugBarStow() {\n\t\t_debugBarStowNoUpdate();\n\t\t_stowed = true;\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarUnstow() {\n\t\t_debugBarUnstowNoUpdate();\n\t\t_stowed = false;\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarToggle() {\n\t\tif (_stowed) {\n\t\t\tdebugBarUnstow();\n\t\t}\n\t\telse {\n\t\t\tdebugBarStow();\n\t\t}\n\t}\n\n\tfunction debugBarWatchAdd(varName) {\n\t\tif (!_variableRe.test(varName)) {\n\t\t\treturn;\n\t\t}\n\n\t\t_watchList.pushUnique(varName);\n\t\t_watchList.sort();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchAddAll() {\n\t\tObject.keys(State.variables).map(name => _watchList.pushUnique(`$${name}`));\n\t\tObject.keys(State.temporary).map(name => _watchList.pushUnique(`_${name}`));\n\n\t\t_watchList.sort();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchClear() {\n\t\tfor (let i = _watchList.length - 1; i >= 0; --i) {\n\t\t\t_watchList.pop();\n\t\t}\n\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchDelete(varName) {\n\t\t_watchList.delete(varName);\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchDisable() {\n\t\t_debugBarWatchDisableNoUpdate();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchEnable() {\n\t\t_debugBarWatchEnableNoUpdate();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchIsEnabled() {\n\t\treturn !_$watchBody.attr('hidden');\n\t}\n\n\tfunction debugBarWatchToggle() {\n\t\tif (_$watchBody.attr('hidden')) {\n\t\t\tdebugBarWatchEnable();\n\t\t}\n\t\telse {\n\t\t\tdebugBarWatchDisable();\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _debugBarStowNoUpdate() {\n\t\t_$debugBar.css('right', `-${_$debugBar.outerWidth()}px`);\n\t}\n\n\tfunction _debugBarUnstowNoUpdate() {\n\t\t_$debugBar.css('right', 0);\n\t}\n\n\tfunction _debugBarWatchDisableNoUpdate() {\n\t\t_$watchBody.attr({\n\t\t\t'aria-hidden' : true,\n\t\t\thidden        : 'hidden'\n\t\t});\n\t}\n\n\tfunction _debugBarWatchEnableNoUpdate() {\n\t\t_$watchBody.removeAttr('aria-hidden hidden');\n\t}\n\n\tfunction _clearSession() {\n\t\tsession.delete('debugState');\n\t}\n\n\tfunction _hasSession() {\n\t\treturn session.has('debugState');\n\t}\n\n\tfunction _restoreSession() {\n\t\tif (!_hasSession()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst debugState = session.get('debugState');\n\n\t\t_stowed = debugState.stowed;\n\n\t\t_watchList.push(...debugState.watchList);\n\n\t\tif (debugState.watchEnabled) {\n\t\t\t_debugBarWatchEnableNoUpdate();\n\t\t}\n\t\telse {\n\t\t\t_debugBarWatchDisableNoUpdate();\n\t\t}\n\n\t\tif (debugState.viewsEnabled) {\n\t\t\tDebugView.enable();\n\t\t}\n\t\telse {\n\t\t\tDebugView.disable();\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction _updateSession() {\n\t\tsession.set('debugState', {\n\t\t\tstowed       : _stowed,\n\t\t\twatchList    : _watchList,\n\t\t\twatchEnabled : debugBarWatchIsEnabled(),\n\t\t\tviewsEnabled : DebugView.isEnabled()\n\t\t});\n\t}\n\n\tfunction _updateBar() {\n\t\tif (_stowed) {\n\t\t\tdebugBarStow();\n\t\t}\n\t\telse {\n\t\t\tdebugBarUnstow();\n\t\t}\n\t}\n\n\tfunction _updateWatchBody() {\n\t\tif (_watchList.length === 0) {\n\t\t\t_$watchBody\n\t\t\t\t.empty()\n\t\t\t\t.append(`<div>${L10n.get('debugBarNoWatches')}</div>`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst delLabel = L10n.get('debugBarDeleteWatch');\n\t\tconst $table   = jQuery(document.createElement('table'));\n\t\tconst $tbody   = jQuery(document.createElement('tbody'));\n\n\t\tfor (let i = 0, len = _watchList.length; i < len; ++i) {\n\t\t\tconst varName = _watchList[i];\n\t\t\tconst varKey  = varName.slice(1);\n\t\t\tconst store   = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\tconst $row    = jQuery(document.createElement('tr'));\n\t\t\tconst $delBtn = jQuery(document.createElement('button'));\n\t\t\tconst $code   = jQuery(document.createElement('code'));\n\n\t\t\t$delBtn\n\t\t\t\t.addClass('watch-delete')\n\t\t\t\t.attr('data-name', varName)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tone   : true,\n\t\t\t\t\tlabel : delLabel\n\t\t\t\t}, () => debugBarWatchDelete(varName));\n\t\t\t$code\n\t\t\t\t.text(_toWatchString(store[varKey]));\n\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.append($delBtn)\n\t\t\t\t.appendTo($row);\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.text(varName)\n\t\t\t\t.appendTo($row);\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.append($code)\n\t\t\t\t.appendTo($row);\n\t\t\t$row\n\t\t\t\t.appendTo($tbody);\n\t\t}\n\n\t\t$table\n\t\t\t.append($tbody);\n\t\t_$watchBody\n\t\t\t.empty()\n\t\t\t.append($table);\n\t}\n\n\tfunction _updateWatchList() {\n\t\tconst svn = Object.keys(State.variables);\n\t\tconst tvn = Object.keys(State.temporary);\n\n\t\tif (svn.length === 0 && tvn.length === 0) {\n\t\t\t_$watchList.empty();\n\t\t\treturn;\n\t\t}\n\n\t\tconst names   = [...svn.map(name => `$${name}`), ...tvn.map(name => `_${name}`)].sort();\n\t\tconst options = document.createDocumentFragment();\n\n\t\tnames.delete(_watchList);\n\n\t\tfor (let i = 0, len = names.length; i < len; ++i) {\n\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t.val(names[i])\n\t\t\t\t.appendTo(options);\n\t\t}\n\n\t\t_$watchList\n\t\t\t.empty()\n\t\t\t.append(options);\n\t}\n\n\tfunction _updateTurnSelect() {\n\t\tconst histLen = State.size;\n\t\tconst expLen  = State.expired.length;\n\t\tconst options = document.createDocumentFragment();\n\n\t\tfor (let i = 0; i < histLen; ++i) {\n\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t.val(i)\n\t\t\t\t.text(`${expLen + i + 1}. ${Util.escape(State.history[i].title)}`)\n\t\t\t\t.appendTo(options);\n\t\t}\n\n\t\t_$turnSelect\n\t\t\t.empty()\n\t\t\t.ariaDisabled(histLen < 2)\n\t\t\t.append(options)\n\t\t\t.val(State.activeIndex);\n\t}\n\n\tfunction _toWatchString(value) {\n\t\t/*\n\t\t\tHandle the `null` primitive.\n\t\t*/\n\t\tif (value === null) {\n\t\t\treturn 'null';\n\t\t}\n\n\t\t/*\n\t\t\tHandle the rest of the primitives and functions.\n\t\t*/\n\t\tswitch (typeof value) {\n\t\tcase 'number':\n\t\t\tif (Number.isNaN(value)) {\n\t\t\t\treturn 'NaN';\n\t\t\t}\n\t\t\telse if (!Number.isFinite(value)) {\n\t\t\t\treturn 'Infinity';\n\t\t\t}\n\t\t\t/* falls through */\n\t\tcase 'boolean':\n\t\tcase 'symbol':\n\t\tcase 'undefined':\n\t\t\treturn String(value);\n\n\t\tcase 'string':\n\t\t\treturn JSON.stringify(value);\n\n\t\t// case 'symbol':\n\t\t// \treturn `Symbol\\u202F\"${String(value).slice(7, -1)}\"`;\n\n\t\tcase 'function':\n\t\t\t// return JSON.stringify(value.toString());\n\t\t\treturn 'Function';\n\t\t}\n\n\t\tconst objType = Util.toStringTag(value);\n\n\t\t// /*\n\t\t// \tHandle instances of the primitive exemplar objects (`Boolean`, `Number`, `String`).\n\t\t// */\n\t\t// if (objType === 'Boolean') {\n\t\t// \treturn `Boolean\\u202F{${String(value)}}`;\n\t\t// }\n\t\t// if (objType === 'Number') {\n\t\t// \treturn `Number\\u202F{${String(value)}}`;\n\t\t// }\n\t\t// if (objType === 'String') {\n\t\t// \treturn `String\\u202F{\"${String(value)}\"}`;\n\t\t// }\n\n\t\t/*\n\t\t\tHandle `Date` objects.\n\t\t*/\n\t\tif (objType === 'Date') {\n\t\t\t// return `Date\\u202F${value.toISOString()}`;\n\t\t\treturn `Date\\u202F{${value.toLocaleString()}}`;\n\t\t}\n\n\t\t/*\n\t\t\tHandle `RegExp` objects.\n\t\t*/\n\t\tif (objType === 'RegExp') {\n\t\t\treturn `RegExp\\u202F${value.toString()}`;\n\t\t}\n\n\t\tconst result = [];\n\n\t\t/*\n\t\t\tHandle `Array` & `Set` objects.\n\t\t*/\n\t\tif (value instanceof Array || value instanceof Set) {\n\t\t\tconst list = value instanceof Array ? value : Array.from(value);\n\n\t\t\t// own numeric properties\n\t\t\t// NOTE: Do not use `<Array>.forEach()` here as it skips undefined members.\n\t\t\tfor (let i = 0, len = list.length; i < len; ++i) {\n\t\t\t\tresult.push(list.hasOwnProperty(i) ? _toWatchString(list[i]) : '<empty>');\n\t\t\t}\n\n\t\t\t// own enumerable non-numeric expando properties\n\t\t\tObject.keys(list)\n\t\t\t\t.filter(key => !_numericKeyRe.test(key))\n\t\t\t\t.forEach(key => result.push(`${_toWatchString(key)}: ${_toWatchString(list[key])}`));\n\n\t\t\treturn `${objType}(${list.length})\\u202F[${result.join(', ')}]`;\n\t\t}\n\n\t\t/*\n\t\t\tHandle `Map` objects.\n\t\t*/\n\t\tif (value instanceof Map) {\n\t\t\tvalue.forEach((val, key) => result.push(`${_toWatchString(key)} \\u2192 ${_toWatchString(val)}`));\n\n\t\t\treturn `${objType}(${value.size})\\u202F{${result.join(', ')}}`;\n\t\t}\n\n\t\t/*\n\t\t\tGeneral object handling.\n\t\t*/\n\t\t// own enumerable properties\n\t\tObject.keys(value)\n\t\t\t.forEach(key => result.push(`${_toWatchString(key)}: ${_toWatchString(value[key])}`));\n\n\t\treturn `${objType}\\u202F{${result.join(', ')}}`;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tDebug Bar Functions.\n\t\t*/\n\t\tinit     : { value : debugBarInit },\n\t\tisStowed : { value : debugBarIsStowed },\n\t\tstart    : { value : debugBarStart },\n\t\tstow     : { value : debugBarStow },\n\t\ttoggle   : { value : debugBarToggle },\n\t\tunstow   : { value : debugBarUnstow },\n\n\t\t/*\n\t\t\tWatch Functions.\n\t\t*/\n\t\twatch : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd       : { value : debugBarWatchAdd },\n\t\t\t\tall       : { value : debugBarWatchAddAll },\n\t\t\t\tclear     : { value : debugBarWatchClear },\n\t\t\t\tdelete    : { value : debugBarWatchDelete },\n\t\t\t\tdisable   : { value : debugBarWatchDisable },\n\t\t\t\tenable    : { value : debugBarWatchEnable },\n\t\t\t\tisEnabled : { value : debugBarWatchIsEnabled },\n\t\t\t\ttoggle    : { value : debugBarWatchToggle }\n\t\t\t}))\n\t\t}\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tloadscreen.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Engine */\n\nvar LoadScreen = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Locks collection.\n\tconst _locks = new Set();\n\n\t// Auto-incrementing lock ID.\n\tlet _autoId = 0;\n\n\n\t/*******************************************************************************************************************\n\t\tLoadScreen Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tInitialize management of the loading screen.\n\t*/\n\tfunction loadScreenInit() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenInit()]'); }\n\n\t\t// Add a `readystatechange` listener for hiding/showing the loading screen.\n\t\tjQuery(document).on('readystatechange.SugarCube', () => {\n\t\t\tif (DEBUG) { console.log(`[LoadScreen/<readystatechange>] document.readyState: \"${document.readyState}\"; locks(${_locks.size}):`, _locks); }\n\n\t\t\tif (_locks.size > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// The value of `document.readyState` may be: 'loading' -> 'interactive' -> 'complete'.\n\t\t\t// Though, to reach this point, it must already be in, at least, the 'interactive' state.\n\t\t\tif (document.readyState === 'complete') {\n\t\t\t\tif (jQuery(document.documentElement).attr('data-init') === 'loading') {\n\t\t\t\t\tif (Config.loadDelay > 0) {\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tif (_locks.size === 0) {\n\t\t\t\t\t\t\t\tloadScreenHide();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, Math.max(Engine.minDomActionDelay, Config.loadDelay));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tloadScreenHide();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloadScreenShow();\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\tClear the loading screen.\n\t*/\n\tfunction loadScreenClear() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenClear()]'); }\n\n\t\t// Remove the event listener.\n\t\tjQuery(document).off('readystatechange.SugarCube');\n\n\t\t// Clear all locks.\n\t\t_locks.clear();\n\n\t\t// Hide the loading screen.\n\t\tloadScreenHide();\n\t}\n\n\t/*\n\t\tHide the loading screen.\n\t*/\n\tfunction loadScreenHide() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenHide()]'); }\n\n\t\tjQuery(document.documentElement).removeAttr('data-init');\n\t}\n\n\t/*\n\t\tShow the loading screen.\n\t*/\n\tfunction loadScreenShow() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenShow()]'); }\n\n\t\tjQuery(document.documentElement).attr('data-init', 'loading');\n\t}\n\n\t/*\n\t\tReturns a new lock ID after locking and showing the loading screen.\n\t*/\n\tfunction loadScreenLock() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenLock()]'); }\n\n\t\t++_autoId;\n\t\t_locks.add(_autoId);\n\n\t\tif (DEBUG) { console.log(`\\tacquired loading screen lock; id: ${_autoId}`); }\n\n\t\tloadScreenShow();\n\t\treturn _autoId;\n\t}\n\n\t/*\n\t\tRemove the lock associated with the given lock ID and, if no locks remain,\n\t\ttrigger a `readystatechange` event.\n\t*/\n\tfunction loadScreenUnlock(id) {\n\t\tif (DEBUG) { console.log(`[LoadScreen/loadScreenUnlock(id: ${id})]`); }\n\n\t\tif (id == null) { // lazy equality for null\n\t\t\tthrow new Error('LoadScreen.unlock called with a null or undefined ID');\n\t\t}\n\n\t\tif (_locks.has(id)) {\n\t\t\t_locks.delete(id);\n\n\t\t\tif (DEBUG) { console.log(`\\treleased loading screen lock; id: ${id}`); }\n\t\t}\n\n\t\tif (_locks.size === 0) {\n\t\t\tjQuery(document).trigger('readystatechange');\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : loadScreenInit },\n\t\tclear  : { value : loadScreenClear },\n\t\thide   : { value : loadScreenHide },\n\t\tshow   : { value : loadScreenShow },\n\t\tlock   : { value : loadScreenLock },\n\t\tunlock : { value : loadScreenUnlock }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tsugarcube.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Browser, Config, Dialog, Engine, Fullscreen, Has, LoadScreen, SimpleStore, L10n, Macro, Passage,\n\t       Save, Scripting, Setting, SimpleAudio, State, Story, UI, UIBar, DebugBar, Util, Visibility, Wikifier\n*/\n/* eslint-disable no-var */\n\n/*\n\tVersion object.\n*/\nvar version = Object.freeze({\n\ttitle      : 'SugarCube',\n\tmajor      : 2,\n\tminor      : 31,\n\tpatch      : 1,\n\tprerelease : null,\n\tbuild      : 21,\n\tdate       : new Date(\"2020-05-06T21:53:59.980Z\"),\n\t/* legacy */\n\textensions : {},\n\t/* /legacy */\n\n\ttoString() {\n\t\t'use strict';\n\n\t\tconst prerelease = this.prerelease ? `-${this.prerelease}` : '';\n\t\treturn `${this.major}.${this.minor}.${this.patch}${prerelease}+${this.build}`;\n\t},\n\n\tshort() {\n\t\t'use strict';\n\n\t\tconst prerelease = this.prerelease ? `-${this.prerelease}` : '';\n\t\treturn `${this.title} (v${this.major}.${this.minor}.${this.patch}${prerelease})`;\n\t},\n\n\tlong() {\n\t\t'use strict';\n\n\t\treturn `${this.title} v${this.toString()} (${this.date.toUTCString()})`;\n\t}\n});\n\n/* eslint-disable no-unused-vars */\n/*\n\tInternal variables.\n*/\n// Temporary state object.\nvar TempState = {};\n\n// Legacy macros object.\nvar macros = {};\n\n// Post-display task callbacks object.\nvar postdisplay = {};\n\n// Post-render task callbacks object.\nvar postrender = {};\n\n// Pre-display task callbacks object.\nvar predisplay = {};\n\n// Pre-history task callbacks object.\nvar prehistory = {};\n\n// Pre-render task callbacks object.\nvar prerender = {};\n\n// Session storage manager object.\nvar session = null;\n\n// Settings object.\nvar settings = {};\n\n// Setup object.\nvar setup = {};\n\n// Persistant storage manager object.\nvar storage = null;\n\n/*\n\tLegacy aliases.\n*/\nvar browser       = Browser;\nvar config        = Config;\nvar has           = Has;\nvar History       = State;\nvar state         = State;\nvar tale          = Story;\nvar TempVariables = State.temporary;\n/* eslint-enable no-unused-vars */\n\n/*\n\tGlobal `SugarCube` object.  Allows scripts to detect if they're running in SugarCube by\n\ttesting for the object (e.g. `\"SugarCube\" in window`) and contains exported identifiers\n\tfor debugging purposes.\n*/\nwindow.SugarCube = {};\n\n/*\n\tMain function, entry point for the story.\n*/\njQuery(() => {\n\t'use strict';\n\n\tif (DEBUG) { console.log('[SugarCube/main()] Document loaded; beginning startup.'); }\n\n\t/*\n\t\tWARNING!\n\n\t\tThe ordering of the code within this function is critically important,\n\t\tso be careful when mucking around with it.\n\t*/\n\ttry {\n\t\t// Acquire an initial lock for and initialize the loading screen.\n\t\tconst lockId = LoadScreen.lock();\n\t\tLoadScreen.init();\n\n\t\t// Normalize the document.\n\t\tif (document.normalize) {\n\t\t\tdocument.normalize();\n\t\t}\n\n\t\t// Load the story data (must be done before most anything else).\n\t\tStory.load();\n\n\t\t// Instantiate the storage and session objects.\n\t\t// NOTE: `SimpleStore.create(storageId, persistent)`\n\t\tstorage = SimpleStore.create(Story.domId, true);\n\t\tsession = SimpleStore.create(Story.domId, false);\n\n\t\t// Initialize the user interface (must be done before story initialization, specifically before scripts).\n\t\tDialog.init();\n\t\tUIBar.init();\n\t\tEngine.init();\n\n\t\t// Initialize the story (largely load the user styles, scripts, and widgets).\n\t\tStory.init();\n\n\t\t// Initialize the localization (must be done after story initialization).\n\t\tL10n.init();\n\n\t\t// Alert when the browser is degrading required capabilities (must be done after localization initialization).\n\t\tif (!session.has('rcWarn') && storage.name === 'cookie') {\n\t\t\t/* eslint-disable no-alert */\n\t\t\tsession.set('rcWarn', 1);\n\t\t\twindow.alert(L10n.get('warningNoWebStorage'));\n\t\t\t/* eslint-enable no-alert */\n\t\t}\n\n\t\t// Initialize the saves (must be done after story initialization, but before engine start).\n\t\tSave.init();\n\n\t\t// Initialize the settings.\n\t\tSetting.init();\n\n\t\t// Initialize the macros.\n\t\tMacro.init();\n\n\t\t// Start the engine (should be done as late as possible, but before interface startup).\n\t\tEngine.start();\n\n\t\t// Initialize the debug bar interface (should be done as late as possible, but before interface startup).\n\t\tif (Config.debug) {\n\t\t\tDebugBar.init();\n\t\t}\n\n\t\t// Set a recurring timer to start the interfaces (necessary due to DOM readiness issues in some browsers).\n\t\tconst $window    = $(window);\n\t\tconst vprCheckId = setInterval(() => {\n\t\t\t// If `$window.width()` returns a zero value, bail out and wait.\n\t\t\tif (!$window.width()) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Clear the recurring timer.\n\t\t\tclearInterval(vprCheckId);\n\n\t\t\t// Start the UI bar interface.\n\t\t\tUIBar.start();\n\n\t\t\t// Start the debug bar interface.\n\t\t\tif (Config.debug) {\n\t\t\t\tDebugBar.start();\n\t\t\t}\n\n\t\t\t// Trigger the `:storyready` global synthetic event.\n\t\t\tjQuery.event.trigger({ type : ':storyready' });\n\n\t\t\t// Release the loading screen lock after a short delay.\n\t\t\tsetTimeout(() => LoadScreen.unlock(lockId), Engine.minDomActionDelay * 2);\n\t\t}, Engine.minDomActionDelay);\n\n\t\t// Finally, export identifiers for debugging purposes.\n\t\tObject.defineProperty(window, 'SugarCube', {\n\t\t\t// WARNING: We need to assign new values at points, so seal it, do not freeze it.\n\t\t\tvalue : Object.seal(Object.assign(Object.create(null), {\n\t\t\t\tBrowser,\n\t\t\t\tConfig,\n\t\t\t\tDialog,\n\t\t\t\tEngine,\n\t\t\t\tFullscreen,\n\t\t\t\tHas,\n\t\t\t\tL10n,\n\t\t\t\tMacro,\n\t\t\t\tPassage,\n\t\t\t\tSave,\n\t\t\t\tScripting,\n\t\t\t\tSetting,\n\t\t\t\tSimpleAudio,\n\t\t\t\tState,\n\t\t\t\tStory,\n\t\t\t\tUI,\n\t\t\t\tUIBar,\n\t\t\t\tDebugBar,\n\t\t\t\tUtil,\n\t\t\t\tVisibility,\n\t\t\t\tWikifier,\n\t\t\t\tsession,\n\t\t\t\tsettings,\n\t\t\t\tsetup,\n\t\t\t\tstorage,\n\t\t\t\tversion\n\t\t\t}))\n\t\t});\n\n\t\tif (DEBUG) { console.log('[SugarCube/main()] Startup complete; story ready.'); }\n\t}\n\tcatch (ex) {\n\t\tconsole.error(ex);\n\t\tLoadScreen.clear();\n\t\treturn Alert.fatal(null, ex.message, ex);\n\t}\n});\n\n})(window, window.document, jQuery);\n}\n\t</script>\n</body>\n</html>\n"});
\ No newline at end of file
diff --git a/devNotes/sugarcube stuff/sugarcube-fc-changes.patch b/devNotes/sugarcube stuff/sugarcube-fc-changes.patch
index b318246254e..0be5847500d 100644
--- a/devNotes/sugarcube stuff/sugarcube-fc-changes.patch	
+++ b/devNotes/sugarcube stuff/sugarcube-fc-changes.patch	
@@ -344,7 +344,7 @@ index aa5c2f2..15d4221 100644
  			return frag;
  		}
 diff --git a/src/state.js b/src/state.js
-index 5ce7c55..3ae79be 100644
+index 5ce7c55..69a73a3 100644
 --- a/src/state.js
 +++ b/src/state.js
 @@ -104,7 +104,7 @@ var State = (() => { // eslint-disable-line no-unused-vars, no-var
@@ -356,6 +356,26 @@ index 5ce7c55..3ae79be 100644
  		}
  
  		if (_prng !== null) {
+@@ -224,8 +224,8 @@ var State = (() => { // eslint-disable-line no-unused-vars, no-var
+ 	*/
+ 	function momentCreate(title, variables) {
+ 		return {
+-			title     : title == null ? '' : String(title),       // lazy equality for null
+-			variables : variables == null ? {} : clone(variables) // lazy equality for null
++			title     : title == null ? '' : String(title), // lazy equality for null
++			variables : variables == null ? {} : variables   // lazy equality for null
+ 		};
+ 	}
+ 
+@@ -510,7 +510,7 @@ var State = (() => { // eslint-disable-line no-unused-vars, no-var
+ 			return [];
+ 		}
+ 
+-		const delta = [clone(historyArr[0])];
++		const delta = [historyArr[0]];
+ 
+ 		for (let i = 1, iend = historyArr.length; i < iend; ++i) {
+ 			delta.push(Diff.diff(historyArr[i - 1], historyArr[i]));
 diff --git a/src/ui.js b/src/ui.js
 index 44fb8fa..fecf8e8 100644
 --- a/src/ui.js
diff --git a/devTools/tweeGo/storyFormats/sugarcube-2/format.js b/devTools/tweeGo/storyFormats/sugarcube-2/format.js
index 416e757805b..0a6c2339ca2 100644
--- a/devTools/tweeGo/storyFormats/sugarcube-2/format.js
+++ b/devTools/tweeGo/storyFormats/sugarcube-2/format.js
@@ -1 +1 @@
-window.storyFormat({"name":"SugarCube","version":"2.31.1","description":"A full featured, highly customizable story format.  See its <a href=\"http://www.motoslave.net/sugarcube/2/#documentation\" target=\"_blank\">documentation</a>.","author":"Thomas Michael Edwards","image":"icon.svg","url":"http://www.motoslave.net/sugarcube/","license":"BSD-2-Clause","proofing":false,"source":"<!DOCTYPE html>\n<html data-init=\"no-js\">\n<head>\n<meta charset=\"UTF-8\" />\n<title>{{STORY_NAME}}</title>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n<!--\n\nSugarCube (v2.31.1): A free (gratis and libre) story format.\n\nCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n-->\n<script id=\"script-libraries\" type=\"text/javascript\">\nif(document.head&&document.addEventListener&&document.querySelector&&Object.create&&Object.freeze&&JSON){document.documentElement.setAttribute(\"data-init\", \"loading\");\n/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js */\nif(\"document\" in self){if(!(\"classList\" in document.createElement(\"_\"))){(function(j){\"use strict\";if(!(\"Element\" in j)){return}var a=\"classList\",f=\"prototype\",m=j.Element[f],b=Object,k=String[f].trim||function(){return this.replace(/^\\s+|\\s+$/g,\"\")},c=Array[f].indexOf||function(q){var p=0,o=this.length;for(;p<o;p++){if(p in this&&this[p]===q){return p}}return -1},n=function(o,p){this.name=o;this.code=DOMException[o];this.message=p},g=function(p,o){if(o===\"\"){throw new n(\"SYNTAX_ERR\",\"An invalid or illegal string was specified\")}if(/\\s/.test(o)){throw new n(\"INVALID_CHARACTER_ERR\",\"String contains an invalid character\")}return c.call(p,o)},d=function(s){var r=k.call(s.getAttribute(\"class\")||\"\"),q=r?r.split(/\\s+/):[],p=0,o=q.length;for(;p<o;p++){this.push(q[p])}this._updateClassName=function(){s.setAttribute(\"class\",this.toString())}},e=d[f]=[],i=function(){return new d(this)};n[f]=Error[f];e.item=function(o){return this[o]||null};e.contains=function(o){o+=\"\";return g(this,o)!==-1};e.add=function(){var s=arguments,r=0,p=s.length,q,o=false;do{q=s[r]+\"\";if(g(this,q)===-1){this.push(q);o=true}}while(++r<p);if(o){this._updateClassName()}};e.remove=function(){var t=arguments,s=0,p=t.length,r,o=false,q;do{r=t[s]+\"\";q=g(this,r);while(q!==-1){this.splice(q,1);o=true;q=g(this,r)}}while(++s<p);if(o){this._updateClassName()}};e.toggle=function(p,q){p+=\"\";var o=this.contains(p),r=o?q!==true&&\"remove\":q!==false&&\"add\";if(r){this[r](p)}if(q===true||q===false){return q}else{return !o}};e.toString=function(){return this.join(\" \")};if(b.defineProperty){var l={get:i,enumerable:true,configurable:true};try{b.defineProperty(m,a,l)}catch(h){if(h.number===-2146823252){l.enumerable=false;b.defineProperty(m,a,l)}}}else{if(b[f].__defineGetter__){m.__defineGetter__(a,i)}}}(self))}else{(function(){var b=document.createElement(\"_\");b.classList.add(\"c1\",\"c2\");if(!b.classList.contains(\"c2\")){var c=function(e){var d=DOMTokenList.prototype[e];DOMTokenList.prototype[e]=function(h){var g,f=arguments.length;for(g=0;g<f;g++){h=arguments[g];d.call(this,h)}}};c(\"add\");c(\"remove\")}b.classList.toggle(\"c3\",false);if(b.classList.contains(\"c3\")){var a=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(d,e){if(1 in arguments&&!this.contains(d)===!e){return e}else{return a.call(this,d)}}}b=null}())}};\n/*!\n * https://github.com/es-shims/es5-shim\n * @license es5-shim Copyright 2009-2015 by contributors, MIT License\n * see https://github.com/es-shims/es5-shim/blob/v4.5.13/LICENSE\n */\n(function(t,r){\"use strict\";if(typeof define===\"function\"&&define.amd){define(r)}else if(typeof exports===\"object\"){module.exports=r()}else{t.returnExports=r()}})(this,function(){var t=Array;var r=t.prototype;var e=Object;var n=e.prototype;var i=Function;var a=i.prototype;var o=String;var f=o.prototype;var u=Number;var l=u.prototype;var s=r.slice;var c=r.splice;var v=r.push;var h=r.unshift;var p=r.concat;var y=r.join;var d=a.call;var g=a.apply;var w=Math.max;var b=Math.min;var T=n.toString;var m=typeof Symbol===\"function\"&&typeof Symbol.toStringTag===\"symbol\";var D;var S=Function.prototype.toString,x=/^\\s*class /,O=function isES6ClassFn(t){try{var r=S.call(t);var e=r.replace(/\\/\\/.*\\n/g,\"\");var n=e.replace(/\\/\\*[.\\s\\S]*\\*\\//g,\"\");var i=n.replace(/\\n/gm,\" \").replace(/ {2}/g,\" \");return x.test(i)}catch(a){return false}},E=function tryFunctionObject(t){try{if(O(t)){return false}S.call(t);return true}catch(r){return false}},j=\"[object Function]\",I=\"[object GeneratorFunction]\",D=function isCallable(t){if(!t){return false}if(typeof t!==\"function\"&&typeof t!==\"object\"){return false}if(m){return E(t)}if(O(t)){return false}var r=T.call(t);return r===j||r===I};var M;var U=RegExp.prototype.exec,$=function tryRegexExec(t){try{U.call(t);return true}catch(r){return false}},F=\"[object RegExp]\";M=function isRegex(t){if(typeof t!==\"object\"){return false}return m?$(t):T.call(t)===F};var N;var C=String.prototype.valueOf,k=function tryStringObject(t){try{C.call(t);return true}catch(r){return false}},A=\"[object String]\";N=function isString(t){if(typeof t===\"string\"){return true}if(typeof t!==\"object\"){return false}return m?k(t):T.call(t)===A};var R=e.defineProperty&&function(){try{var t={};e.defineProperty(t,\"x\",{enumerable:false,value:t});for(var r in t){return false}return t.x===t}catch(n){return false}}();var P=function(t){var r;if(R){r=function(t,r,n,i){if(!i&&r in t){return}e.defineProperty(t,r,{configurable:true,enumerable:false,writable:true,value:n})}}else{r=function(t,r,e,n){if(!n&&r in t){return}t[r]=e}}return function defineProperties(e,n,i){for(var a in n){if(t.call(n,a)){r(e,a,n[a],i)}}}}(n.hasOwnProperty);var J=function isPrimitive(t){var r=typeof t;return t===null||r!==\"object\"&&r!==\"function\"};var Y=u.isNaN||function isActualNaN(t){return t!==t};var z={ToInteger:function ToInteger(t){var r=+t;if(Y(r)){r=0}else if(r!==0&&r!==1/0&&r!==-(1/0)){r=(r>0||-1)*Math.floor(Math.abs(r))}return r},ToPrimitive:function ToPrimitive(t){var r,e,n;if(J(t)){return t}e=t.valueOf;if(D(e)){r=e.call(t);if(J(r)){return r}}n=t.toString;if(D(n)){r=n.call(t);if(J(r)){return r}}throw new TypeError},ToObject:function(t){if(t==null){throw new TypeError(\"can't convert \"+t+\" to object\")}return e(t)},ToUint32:function ToUint32(t){return t>>>0}};var Z=function Empty(){};P(a,{bind:function bind(t){var r=this;if(!D(r)){throw new TypeError(\"Function.prototype.bind called on incompatible \"+r)}var n=s.call(arguments,1);var a;var o=function(){if(this instanceof a){var i=g.call(r,this,p.call(n,s.call(arguments)));if(e(i)===i){return i}return this}else{return g.call(r,t,p.call(n,s.call(arguments)))}};var f=w(0,r.length-n.length);var u=[];for(var l=0;l<f;l++){v.call(u,\"$\"+l)}a=i(\"binder\",\"return function (\"+y.call(u,\",\")+\"){ return binder.apply(this, arguments); }\")(o);if(r.prototype){Z.prototype=r.prototype;a.prototype=new Z;Z.prototype=null}return a}});var G=d.bind(n.hasOwnProperty);var H=d.bind(n.toString);var W=d.bind(s);var B=g.bind(s);if(typeof document===\"object\"&&document&&document.documentElement){try{W(document.documentElement.childNodes)}catch(X){var L=W;var q=B;W=function arraySliceIE(t){var r=[];var e=t.length;while(e-- >0){r[e]=t[e]}return q(r,L(arguments,1))};B=function arraySliceApplyIE(t,r){return q(W(t),r)}}}var K=d.bind(f.slice);var Q=d.bind(f.split);var V=d.bind(f.indexOf);var _=d.bind(v);var tt=d.bind(n.propertyIsEnumerable);var rt=d.bind(r.sort);var et=t.isArray||function isArray(t){return H(t)===\"[object Array]\"};var nt=[].unshift(0)!==1;P(r,{unshift:function(){h.apply(this,arguments);return this.length}},nt);P(t,{isArray:et});var it=e(\"a\");var at=it[0]!==\"a\"||!(0 in it);var ot=function properlyBoxed(t){var r=true;var e=true;var n=false;if(t){try{t.call(\"foo\",function(t,e,n){if(typeof n!==\"object\"){r=false}});t.call([1],function(){\"use strict\";e=typeof this===\"string\"},\"x\")}catch(i){n=true}}return!!t&&!n&&r&&e};P(r,{forEach:function forEach(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=-1;var i=z.ToUint32(e.length);var a;if(arguments.length>1){a=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.forEach callback must be a function\")}while(++n<i){if(n in e){if(typeof a===\"undefined\"){t(e[n],n,r)}else{t.call(a,e[n],n,r)}}}}},!ot(r.forEach));P(r,{map:function map(r){var e=z.ToObject(this);var n=at&&N(this)?Q(this,\"\"):e;var i=z.ToUint32(n.length);var a=t(i);var o;if(arguments.length>1){o=arguments[1]}if(!D(r)){throw new TypeError(\"Array.prototype.map callback must be a function\")}for(var f=0;f<i;f++){if(f in n){if(typeof o===\"undefined\"){a[f]=r(n[f],f,e)}else{a[f]=r.call(o,n[f],f,e)}}}return a}},!ot(r.map));P(r,{filter:function filter(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i=[];var a;var o;if(arguments.length>1){o=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.filter callback must be a function\")}for(var f=0;f<n;f++){if(f in e){a=e[f];if(typeof o===\"undefined\"?t(a,f,r):t.call(o,a,f,r)){_(i,a)}}}return i}},!ot(r.filter));P(r,{every:function every(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i;if(arguments.length>1){i=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.every callback must be a function\")}for(var a=0;a<n;a++){if(a in e&&!(typeof i===\"undefined\"?t(e[a],a,r):t.call(i,e[a],a,r))){return false}}return true}},!ot(r.every));P(r,{some:function some(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i;if(arguments.length>1){i=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.some callback must be a function\")}for(var a=0;a<n;a++){if(a in e&&(typeof i===\"undefined\"?t(e[a],a,r):t.call(i,e[a],a,r))){return true}}return false}},!ot(r.some));var ft=false;if(r.reduce){ft=typeof r.reduce.call(\"es5\",function(t,r,e,n){return n})===\"object\"}P(r,{reduce:function reduce(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);if(!D(t)){throw new TypeError(\"Array.prototype.reduce callback must be a function\")}if(n===0&&arguments.length===1){throw new TypeError(\"reduce of empty array with no initial value\")}var i=0;var a;if(arguments.length>=2){a=arguments[1]}else{do{if(i in e){a=e[i++];break}if(++i>=n){throw new TypeError(\"reduce of empty array with no initial value\")}}while(true)}for(;i<n;i++){if(i in e){a=t(a,e[i],i,r)}}return a}},!ft);var ut=false;if(r.reduceRight){ut=typeof r.reduceRight.call(\"es5\",function(t,r,e,n){return n})===\"object\"}P(r,{reduceRight:function reduceRight(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);if(!D(t)){throw new TypeError(\"Array.prototype.reduceRight callback must be a function\")}if(n===0&&arguments.length===1){throw new TypeError(\"reduceRight of empty array with no initial value\")}var i;var a=n-1;if(arguments.length>=2){i=arguments[1]}else{do{if(a in e){i=e[a--];break}if(--a<0){throw new TypeError(\"reduceRight of empty array with no initial value\")}}while(true)}if(a<0){return i}do{if(a in e){i=t(i,e[a],a,r)}}while(a--);return i}},!ut);var lt=r.indexOf&&[0,1].indexOf(1,2)!==-1;P(r,{indexOf:function indexOf(t){var r=at&&N(this)?Q(this,\"\"):z.ToObject(this);var e=z.ToUint32(r.length);if(e===0){return-1}var n=0;if(arguments.length>1){n=z.ToInteger(arguments[1])}n=n>=0?n:w(0,e+n);for(;n<e;n++){if(n in r&&r[n]===t){return n}}return-1}},lt);var st=r.lastIndexOf&&[0,1].lastIndexOf(0,-3)!==-1;P(r,{lastIndexOf:function lastIndexOf(t){var r=at&&N(this)?Q(this,\"\"):z.ToObject(this);var e=z.ToUint32(r.length);if(e===0){return-1}var n=e-1;if(arguments.length>1){n=b(n,z.ToInteger(arguments[1]))}n=n>=0?n:e-Math.abs(n);for(;n>=0;n--){if(n in r&&t===r[n]){return n}}return-1}},st);var ct=function(){var t=[1,2];var r=t.splice();return t.length===2&&et(r)&&r.length===0}();P(r,{splice:function splice(t,r){if(arguments.length===0){return[]}else{return c.apply(this,arguments)}}},!ct);var vt=function(){var t={};r.splice.call(t,0,0,1);return t.length===1}();P(r,{splice:function splice(t,r){if(arguments.length===0){return[]}var e=arguments;this.length=w(z.ToInteger(this.length),0);if(arguments.length>0&&typeof r!==\"number\"){e=W(arguments);if(e.length<2){_(e,this.length-t)}else{e[1]=z.ToInteger(r)}}return c.apply(this,e)}},!vt);var ht=function(){var r=new t(1e5);r[8]=\"x\";r.splice(1,1);return r.indexOf(\"x\")===7}();var pt=function(){var t=256;var r=[];r[t]=\"a\";r.splice(t+1,0,\"b\");return r[t]===\"a\"}();P(r,{splice:function splice(t,r){var e=z.ToObject(this);var n=[];var i=z.ToUint32(e.length);var a=z.ToInteger(t);var f=a<0?w(i+a,0):b(a,i);var u=b(w(z.ToInteger(r),0),i-f);var l=0;var s;while(l<u){s=o(f+l);if(G(e,s)){n[l]=e[s]}l+=1}var c=W(arguments,2);var v=c.length;var h;if(v<u){l=f;var p=i-u;while(l<p){s=o(l+u);h=o(l+v);if(G(e,s)){e[h]=e[s]}else{delete e[h]}l+=1}l=i;var y=i-u+v;while(l>y){delete e[l-1];l-=1}}else if(v>u){l=i-u;while(l>f){s=o(l+u-1);h=o(l+v-1);if(G(e,s)){e[h]=e[s]}else{delete e[h]}l-=1}}l=f;for(var d=0;d<c.length;++d){e[l]=c[d];l+=1}e.length=i-u+v;return n}},!ht||!pt);var yt=r.join;var dt;try{dt=Array.prototype.join.call(\"123\",\",\")!==\"1,2,3\"}catch(X){dt=true}if(dt){P(r,{join:function join(t){var r=typeof t===\"undefined\"?\",\":t;return yt.call(N(this)?Q(this,\"\"):this,r)}},dt)}var gt=[1,2].join(undefined)!==\"1,2\";if(gt){P(r,{join:function join(t){var r=typeof t===\"undefined\"?\",\":t;return yt.call(this,r)}},gt)}var wt=function push(t){var r=z.ToObject(this);var e=z.ToUint32(r.length);var n=0;while(n<arguments.length){r[e+n]=arguments[n];n+=1}r.length=e+n;return e+n};var bt=function(){var t={};var r=Array.prototype.push.call(t,undefined);return r!==1||t.length!==1||typeof t[0]!==\"undefined\"||!G(t,0)}();P(r,{push:function push(t){if(et(this)){return v.apply(this,arguments)}return wt.apply(this,arguments)}},bt);var Tt=function(){var t=[];var r=t.push(undefined);return r!==1||t.length!==1||typeof t[0]!==\"undefined\"||!G(t,0)}();P(r,{push:wt},Tt);P(r,{slice:function(t,r){var e=N(this)?Q(this,\"\"):this;return B(e,arguments)}},at);var mt=function(){try{[1,2].sort(null)}catch(t){try{[1,2].sort({})}catch(r){return false}}return true}();var Dt=function(){try{[1,2].sort(/a/);return false}catch(t){}return true}();var St=function(){try{[1,2].sort(undefined);return true}catch(t){}return false}();P(r,{sort:function sort(t){if(typeof t===\"undefined\"){return rt(this)}if(!D(t)){throw new TypeError(\"Array.prototype.sort callback must be a function\")}return rt(this,t)}},mt||!St||!Dt);var xt=!tt({toString:null},\"toString\");var Ot=tt(function(){},\"prototype\");var Et=!G(\"x\",\"0\");var jt=function(t){var r=t.constructor;return r&&r.prototype===t};var It={$applicationCache:true,$console:true,$external:true,$frame:true,$frameElement:true,$frames:true,$innerHeight:true,$innerWidth:true,$onmozfullscreenchange:true,$onmozfullscreenerror:true,$outerHeight:true,$outerWidth:true,$pageXOffset:true,$pageYOffset:true,$parent:true,$scrollLeft:true,$scrollTop:true,$scrollX:true,$scrollY:true,$self:true,$webkitIndexedDB:true,$webkitStorageInfo:true,$window:true,$width:true,$height:true,$top:true,$localStorage:true};var Mt=function(){if(typeof window===\"undefined\"){return false}for(var t in window){try{if(!It[\"$\"+t]&&G(window,t)&&window[t]!==null&&typeof window[t]===\"object\"){jt(window[t])}}catch(r){return true}}return false}();var Ut=function(t){if(typeof window===\"undefined\"||!Mt){return jt(t)}try{return jt(t)}catch(r){return false}};var $t=[\"toString\",\"toLocaleString\",\"valueOf\",\"hasOwnProperty\",\"isPrototypeOf\",\"propertyIsEnumerable\",\"constructor\"];var Ft=$t.length;var Nt=function isArguments(t){return H(t)===\"[object Arguments]\"};var Ct=function isArguments(t){return t!==null&&typeof t===\"object\"&&typeof t.length===\"number\"&&t.length>=0&&!et(t)&&D(t.callee)};var kt=Nt(arguments)?Nt:Ct;P(e,{keys:function keys(t){var r=D(t);var e=kt(t);var n=t!==null&&typeof t===\"object\";var i=n&&N(t);if(!n&&!r&&!e){throw new TypeError(\"Object.keys called on a non-object\")}var a=[];var f=Ot&&r;if(i&&Et||e){for(var u=0;u<t.length;++u){_(a,o(u))}}if(!e){for(var l in t){if(!(f&&l===\"prototype\")&&G(t,l)){_(a,o(l))}}}if(xt){var s=Ut(t);for(var c=0;c<Ft;c++){var v=$t[c];if(!(s&&v===\"constructor\")&&G(t,v)){_(a,v)}}}return a}});var At=e.keys&&function(){return e.keys(arguments).length===2}(1,2);var Rt=e.keys&&function(){var t=e.keys(arguments);return arguments.length!==1||t.length!==1||t[0]!==1}(1);var Pt=e.keys;P(e,{keys:function keys(t){if(kt(t)){return Pt(W(t))}else{return Pt(t)}}},!At||Rt);var Jt=new Date(-0xc782b5b342b24).getUTCMonth()!==0;var Yt=new Date(-0x55d318d56a724);var zt=new Date(14496624e5);var Zt=Yt.toUTCString()!==\"Mon, 01 Jan -45875 11:59:59 GMT\";var Gt;var Ht;var Wt=Yt.getTimezoneOffset();if(Wt<-720){Gt=Yt.toDateString()!==\"Tue Jan 02 -45875\";Ht=!/^Thu Dec 10 2015 \\d\\d:\\d\\d:\\d\\d GMT[-+]\\d\\d\\d\\d(?: |$)/.test(String(zt))}else{Gt=Yt.toDateString()!==\"Mon Jan 01 -45875\";Ht=!/^Wed Dec 09 2015 \\d\\d:\\d\\d:\\d\\d GMT[-+]\\d\\d\\d\\d(?: |$)/.test(String(zt))}var Bt=d.bind(Date.prototype.getFullYear);var Xt=d.bind(Date.prototype.getMonth);var Lt=d.bind(Date.prototype.getDate);var qt=d.bind(Date.prototype.getUTCFullYear);var Kt=d.bind(Date.prototype.getUTCMonth);var Qt=d.bind(Date.prototype.getUTCDate);var Vt=d.bind(Date.prototype.getUTCDay);var _t=d.bind(Date.prototype.getUTCHours);var tr=d.bind(Date.prototype.getUTCMinutes);var rr=d.bind(Date.prototype.getUTCSeconds);var er=d.bind(Date.prototype.getUTCMilliseconds);var nr=[\"Sun\",\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\"];var ir=[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"];var ar=function daysInMonth(t,r){return Lt(new Date(r,t,0))};P(Date.prototype,{getFullYear:function getFullYear(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);if(t<0&&Xt(this)>11){return t+1}return t},getMonth:function getMonth(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);var r=Xt(this);if(t<0&&r>11){return 0}return r},getDate:function getDate(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);var r=Xt(this);var e=Lt(this);if(t<0&&r>11){if(r===12){return e}var n=ar(0,t+1);return n-e+1}return e},getUTCFullYear:function getUTCFullYear(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);if(t<0&&Kt(this)>11){return t+1}return t},getUTCMonth:function getUTCMonth(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);var r=Kt(this);if(t<0&&r>11){return 0}return r},getUTCDate:function getUTCDate(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);var r=Kt(this);var e=Qt(this);if(t<0&&r>11){if(r===12){return e}var n=ar(0,t+1);return n-e+1}return e}},Jt);P(Date.prototype,{toUTCString:function toUTCString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Vt(this);var r=Qt(this);var e=Kt(this);var n=qt(this);var i=_t(this);var a=tr(this);var o=rr(this);return nr[t]+\", \"+(r<10?\"0\"+r:r)+\" \"+ir[e]+\" \"+n+\" \"+(i<10?\"0\"+i:i)+\":\"+(a<10?\"0\"+a:a)+\":\"+(o<10?\"0\"+o:o)+\" GMT\"}},Jt||Zt);P(Date.prototype,{toDateString:function toDateString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=this.getDay();var r=this.getDate();var e=this.getMonth();var n=this.getFullYear();return nr[t]+\" \"+ir[e]+\" \"+(r<10?\"0\"+r:r)+\" \"+n}},Jt||Gt);if(Jt||Ht){Date.prototype.toString=function toString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=this.getDay();var r=this.getDate();var e=this.getMonth();var n=this.getFullYear();var i=this.getHours();var a=this.getMinutes();var o=this.getSeconds();var f=this.getTimezoneOffset();var u=Math.floor(Math.abs(f)/60);var l=Math.floor(Math.abs(f)%60);return nr[t]+\" \"+ir[e]+\" \"+(r<10?\"0\"+r:r)+\" \"+n+\" \"+(i<10?\"0\"+i:i)+\":\"+(a<10?\"0\"+a:a)+\":\"+(o<10?\"0\"+o:o)+\" GMT\"+(f>0?\"-\":\"+\")+(u<10?\"0\"+u:u)+(l<10?\"0\"+l:l)};if(R){e.defineProperty(Date.prototype,\"toString\",{configurable:true,enumerable:false,writable:true})}}var or=-621987552e5;var fr=\"-000001\";var ur=Date.prototype.toISOString&&new Date(or).toISOString().indexOf(fr)===-1;var lr=Date.prototype.toISOString&&new Date(-1).toISOString()!==\"1969-12-31T23:59:59.999Z\";var sr=d.bind(Date.prototype.getTime);P(Date.prototype,{toISOString:function toISOString(){if(!isFinite(this)||!isFinite(sr(this))){throw new RangeError(\"Date.prototype.toISOString called on non-finite value.\")}var t=qt(this);var r=Kt(this);t+=Math.floor(r/12);r=(r%12+12)%12;var e=[r+1,Qt(this),_t(this),tr(this),rr(this)];t=(t<0?\"-\":t>9999?\"+\":\"\")+K(\"00000\"+Math.abs(t),0<=t&&t<=9999?-4:-6);for(var n=0;n<e.length;++n){e[n]=K(\"00\"+e[n],-2)}return t+\"-\"+W(e,0,2).join(\"-\")+\"T\"+W(e,2).join(\":\")+\".\"+K(\"000\"+er(this),-3)+\"Z\"}},ur||lr);var cr=function(){try{return Date.prototype.toJSON&&new Date(NaN).toJSON()===null&&new Date(or).toJSON().indexOf(fr)!==-1&&Date.prototype.toJSON.call({toISOString:function(){return true}})}catch(t){return false}}();if(!cr){Date.prototype.toJSON=function toJSON(t){var r=e(this);var n=z.ToPrimitive(r);if(typeof n===\"number\"&&!isFinite(n)){return null}var i=r.toISOString;if(!D(i)){throw new TypeError(\"toISOString property is not callable\")}return i.call(r)}}var vr=Date.parse(\"+033658-09-27T01:46:40.000Z\")===1e15;var hr=!isNaN(Date.parse(\"2012-04-04T24:00:00.500Z\"))||!isNaN(Date.parse(\"2012-11-31T23:59:59.000Z\"))||!isNaN(Date.parse(\"2012-12-31T23:59:60.000Z\"));var pr=isNaN(Date.parse(\"2000-01-01T00:00:00.000Z\"));if(pr||hr||!vr){var yr=Math.pow(2,31)-1;var dr=Y(new Date(1970,0,1,0,0,0,yr+1).getTime());Date=function(t){var r=function Date(e,n,i,a,f,u,l){var s=arguments.length;var c;if(this instanceof t){var v=u;var h=l;if(dr&&s>=7&&l>yr){var p=Math.floor(l/yr)*yr;var y=Math.floor(p/1e3);v+=y;h-=y*1e3}c=s===1&&o(e)===e?new t(r.parse(e)):s>=7?new t(e,n,i,a,f,v,h):s>=6?new t(e,n,i,a,f,v):s>=5?new t(e,n,i,a,f):s>=4?new t(e,n,i,a):s>=3?new t(e,n,i):s>=2?new t(e,n):s>=1?new t(e instanceof t?+e:e):new t}else{c=t.apply(this,arguments)}if(!J(c)){P(c,{constructor:r},true)}return c};var e=new RegExp(\"^\"+\"(\\\\d{4}|[+-]\\\\d{6})\"+\"(?:-(\\\\d{2})\"+\"(?:-(\\\\d{2})\"+\"(?:\"+\"T(\\\\d{2})\"+\":(\\\\d{2})\"+\"(?:\"+\":(\\\\d{2})\"+\"(?:(\\\\.\\\\d{1,}))?\"+\")?\"+\"(\"+\"Z|\"+\"(?:\"+\"([-+])\"+\"(\\\\d{2})\"+\":(\\\\d{2})\"+\")\"+\")?)?)?)?\"+\"$\");var n=[0,31,59,90,120,151,181,212,243,273,304,334,365];var i=function dayFromMonth(t,r){var e=r>1?1:0;return n[r]+Math.floor((t-1969+e)/4)-Math.floor((t-1901+e)/100)+Math.floor((t-1601+e)/400)+365*(t-1970)};var a=function toUTC(r){var e=0;var n=r;if(dr&&n>yr){var i=Math.floor(n/yr)*yr;var a=Math.floor(i/1e3);e+=a;n-=a*1e3}return u(new t(1970,0,1,0,0,e,n))};for(var f in t){if(G(t,f)){r[f]=t[f]}}P(r,{now:t.now,UTC:t.UTC},true);r.prototype=t.prototype;P(r.prototype,{constructor:r},true);var l=function parse(r){var n=e.exec(r);if(n){var o=u(n[1]),f=u(n[2]||1)-1,l=u(n[3]||1)-1,s=u(n[4]||0),c=u(n[5]||0),v=u(n[6]||0),h=Math.floor(u(n[7]||0)*1e3),p=Boolean(n[4]&&!n[8]),y=n[9]===\"-\"?1:-1,d=u(n[10]||0),g=u(n[11]||0),w;var b=c>0||v>0||h>0;if(s<(b?24:25)&&c<60&&v<60&&h<1e3&&f>-1&&f<12&&d<24&&g<60&&l>-1&&l<i(o,f+1)-i(o,f)){w=((i(o,f)+l)*24+s+d*y)*60;w=((w+c+g*y)*60+v)*1e3+h;if(p){w=a(w)}if(-864e13<=w&&w<=864e13){return w}}return NaN}return t.parse.apply(this,arguments)};P(r,{parse:l});return r}(Date)}if(!Date.now){Date.now=function now(){return(new Date).getTime()}}var gr=l.toFixed&&(8e-5.toFixed(3)!==\"0.000\"||.9.toFixed(0)!==\"1\"||1.255.toFixed(2)!==\"1.25\"||(1000000000000000128).toFixed(0)!==\"1000000000000000128\");var wr={base:1e7,size:6,data:[0,0,0,0,0,0],multiply:function multiply(t,r){var e=-1;var n=r;while(++e<wr.size){n+=t*wr.data[e];wr.data[e]=n%wr.base;n=Math.floor(n/wr.base)}},divide:function divide(t){var r=wr.size;var e=0;while(--r>=0){e+=wr.data[r];wr.data[r]=Math.floor(e/t);e=e%t*wr.base}},numToString:function numToString(){var t=wr.size;var r=\"\";while(--t>=0){if(r!==\"\"||t===0||wr.data[t]!==0){var e=o(wr.data[t]);if(r===\"\"){r=e}else{r+=K(\"0000000\",0,7-e.length)+e}}}return r},pow:function pow(t,r,e){return r===0?e:r%2===1?pow(t,r-1,e*t):pow(t*t,r/2,e)},log:function log(t){var r=0;var e=t;while(e>=4096){r+=12;e/=4096}while(e>=2){r+=1;e/=2}return r}};var br=function toFixed(t){var r,e,n,i,a,f,l,s;r=u(t);r=Y(r)?0:Math.floor(r);if(r<0||r>20){throw new RangeError(\"Number.toFixed called with invalid number of decimals\")}e=u(this);if(Y(e)){return\"NaN\"}if(e<=-1e21||e>=1e21){return o(e)}n=\"\";if(e<0){n=\"-\";e=-e}i=\"0\";if(e>1e-21){a=wr.log(e*wr.pow(2,69,1))-69;f=a<0?e*wr.pow(2,-a,1):e/wr.pow(2,a,1);f*=4503599627370496;a=52-a;if(a>0){wr.multiply(0,f);l=r;while(l>=7){wr.multiply(1e7,0);l-=7}wr.multiply(wr.pow(10,l,1),0);l=a-1;while(l>=23){wr.divide(1<<23);l-=23}wr.divide(1<<l);wr.multiply(1,1);wr.divide(2);i=wr.numToString()}else{wr.multiply(0,f);wr.multiply(1<<-a,0);i=wr.numToString()+K(\"0.00000000000000000000\",2,2+r)}}if(r>0){s=i.length;if(s<=r){i=n+K(\"0.0000000000000000000\",0,r-s+2)+i}else{i=n+K(i,0,s-r)+\".\"+K(i,s-r)}}else{i=n+i}return i};P(l,{toFixed:br},gr);var Tr=function(){try{return 1..toPrecision(undefined)===\"1\"}catch(t){return true}}();var mr=l.toPrecision;P(l,{toPrecision:function toPrecision(t){return typeof t===\"undefined\"?mr.call(this):mr.call(this,t)}},Tr);if(\"ab\".split(/(?:ab)*/).length!==2||\".\".split(/(.?)(.?)/).length!==4||\"tesst\".split(/(s)*/)[1]===\"t\"||\"test\".split(/(?:)/,-1).length!==4||\"\".split(/.?/).length||\".\".split(/()()/).length>1){(function(){var t=typeof/()??/.exec(\"\")[1]===\"undefined\";var r=Math.pow(2,32)-1;f.split=function(e,n){var i=String(this);if(typeof e===\"undefined\"&&n===0){return[]}if(!M(e)){return Q(this,e,n)}var a=[];var o=(e.ignoreCase?\"i\":\"\")+(e.multiline?\"m\":\"\")+(e.unicode?\"u\":\"\")+(e.sticky?\"y\":\"\"),f=0,u,l,s,c;var h=new RegExp(e.source,o+\"g\");if(!t){u=new RegExp(\"^\"+h.source+\"$(?!\\\\s)\",o)}var p=typeof n===\"undefined\"?r:z.ToUint32(n);l=h.exec(i);while(l){s=l.index+l[0].length;if(s>f){_(a,K(i,f,l.index));if(!t&&l.length>1){l[0].replace(u,function(){for(var t=1;t<arguments.length-2;t++){if(typeof arguments[t]===\"undefined\"){l[t]=void 0}}})}if(l.length>1&&l.index<i.length){v.apply(a,W(l,1))}c=l[0].length;f=s;if(a.length>=p){break}}if(h.lastIndex===l.index){h.lastIndex++}l=h.exec(i)}if(f===i.length){if(c||!h.test(\"\")){_(a,\"\")}}else{_(a,K(i,f))}return a.length>p?W(a,0,p):a}})()}else if(\"0\".split(void 0,0).length){f.split=function split(t,r){if(typeof t===\"undefined\"&&r===0){return[]}return Q(this,t,r)}}var Dr=f.replace;var Sr=function(){var t=[];\"x\".replace(/x(.)?/g,function(r,e){_(t,e)});return t.length===1&&typeof t[0]===\"undefined\"}();if(!Sr){f.replace=function replace(t,r){var e=D(r);var n=M(t)&&/\\)[*?]/.test(t.source);if(!e||!n){return Dr.call(this,t,r)}else{var i=function(e){var n=arguments.length;var i=t.lastIndex;t.lastIndex=0;var a=t.exec(e)||[];t.lastIndex=i;_(a,arguments[n-2],arguments[n-1]);return r.apply(this,a)};return Dr.call(this,t,i)}}}var xr=f.substr;var Or=\"\".substr&&\"0b\".substr(-1)!==\"b\";P(f,{substr:function substr(t,r){var e=t;if(t<0){e=w(this.length+t,0)}return xr.call(this,e,r)}},Or);var Er=\"\\t\\n\\x0B\\f\\r \\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\"+\"\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\"+\"\\u2029\\ufeff\";var jr=\"\\u200b\";var Ir=\"[\"+Er+\"]\";var Mr=new RegExp(\"^\"+Ir+Ir+\"*\");var Ur=new RegExp(Ir+Ir+\"*$\");var $r=f.trim&&(Er.trim()||!jr.trim());P(f,{trim:function trim(){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}return o(this).replace(Mr,\"\").replace(Ur,\"\")}},$r);var Fr=d.bind(String.prototype.trim);var Nr=f.lastIndexOf&&\"abc\\u3042\\u3044\".lastIndexOf(\"\\u3042\\u3044\",2)!==-1;P(f,{lastIndexOf:function lastIndexOf(t){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}var r=o(this);var e=o(t);var n=arguments.length>1?u(arguments[1]):NaN;var i=Y(n)?Infinity:z.ToInteger(n);var a=b(w(i,0),r.length);var f=e.length;var l=a+f;while(l>0){l=w(0,l-f);var s=V(K(r,l,a+f),e);if(s!==-1){return l+s}}return-1}},Nr);var Cr=f.lastIndexOf;P(f,{lastIndexOf:function lastIndexOf(t){return Cr.apply(this,arguments)}},f.lastIndexOf.length!==1);if(parseInt(Er+\"08\")!==8||parseInt(Er+\"0x16\")!==22){parseInt=function(t){var r=/^[-+]?0[xX]/;return function parseInt(e,n){if(typeof e===\"symbol\"){\"\"+e}var i=Fr(String(e));var a=u(n)||(r.test(i)?16:10);return t(i,a)}}(parseInt)}if(1/parseFloat(\"-0\")!==-Infinity){parseFloat=function(t){return function parseFloat(r){var e=Fr(String(r));var n=t(e);return n===0&&K(e,0,1)===\"-\"?-0:n}}(parseFloat)}if(String(new RangeError(\"test\"))!==\"RangeError: test\"){var kr=function toString(){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}var t=this.name;if(typeof t===\"undefined\"){t=\"Error\"}else if(typeof t!==\"string\"){t=o(t)}var r=this.message;if(typeof r===\"undefined\"){r=\"\"}else if(typeof r!==\"string\"){r=o(r)}if(!t){return r}if(!r){return t}return t+\": \"+r};Error.prototype.toString=kr}if(R){var Ar=function(t,r){if(tt(t,r)){var e=Object.getOwnPropertyDescriptor(t,r);if(e.configurable){e.enumerable=false;Object.defineProperty(t,r,e)}}};Ar(Error.prototype,\"message\");if(Error.prototype.message!==\"\"){Error.prototype.message=\"\"}Ar(Error.prototype,\"name\")}if(String(/a/gim)!==\"/a/gim\"){var Rr=function toString(){var t=\"/\"+this.source+\"/\";if(this.global){t+=\"g\"}if(this.ignoreCase){t+=\"i\"}if(this.multiline){t+=\"m\"}return t};RegExp.prototype.toString=Rr}});\n//# sourceMappingURL=es5-shim.map\n/*!\n * https://github.com/paulmillr/es6-shim\n * @license es6-shim Copyright 2013-2016 by Paul Miller (http://paulmillr.com)\n *   and contributors,  MIT License\n * es6-shim: v0.35.4\n * see https://github.com/paulmillr/es6-shim/blob/0.35.4/LICENSE\n * Details and documentation:\n * https://github.com/paulmillr/es6-shim/\n */\n(function(e,t){if(typeof define===\"function\"&&define.amd){define(t)}else if(typeof exports===\"object\"){module.exports=t()}else{e.returnExports=t()}})(this,function(){\"use strict\";var e=Function.call.bind(Function.apply);var t=Function.call.bind(Function.call);var r=Array.isArray;var n=Object.keys;var o=function notThunker(t){return function notThunk(){return!e(t,this,arguments)}};var i=function(e){try{e();return false}catch(t){return true}};var a=function valueOrFalseIfThrows(e){try{return e()}catch(t){return false}};var u=o(i);var f=function(){return!i(function(){return Object.defineProperty({},\"x\",{get:function(){}})})};var s=!!Object.defineProperty&&f();var c=function foo(){}.name===\"foo\";var l=Function.call.bind(Array.prototype.forEach);var p=Function.call.bind(Array.prototype.reduce);var v=Function.call.bind(Array.prototype.filter);var y=Function.call.bind(Array.prototype.some);var h=function(e,t,r,n){if(!n&&t in e){return}if(s){Object.defineProperty(e,t,{configurable:true,enumerable:false,writable:true,value:r})}else{e[t]=r}};var b=function(e,t,r){l(n(t),function(n){var o=t[n];h(e,n,o,!!r)})};var g=Function.call.bind(Object.prototype.toString);var d=typeof/abc/===\"function\"?function IsCallableSlow(e){return typeof e===\"function\"&&g(e)===\"[object Function]\"}:function IsCallableFast(e){return typeof e===\"function\"};var m={getter:function(e,t,r){if(!s){throw new TypeError(\"getters require true ES5 support\")}Object.defineProperty(e,t,{configurable:true,enumerable:false,get:r})},proxy:function(e,t,r){if(!s){throw new TypeError(\"getters require true ES5 support\")}var n=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,{configurable:n.configurable,enumerable:n.enumerable,get:function getKey(){return e[t]},set:function setKey(r){e[t]=r}})},redefine:function(e,t,r){if(s){var n=Object.getOwnPropertyDescriptor(e,t);n.value=r;Object.defineProperty(e,t,n)}else{e[t]=r}},defineByDescriptor:function(e,t,r){if(s){Object.defineProperty(e,t,r)}else if(\"value\"in r){e[t]=r.value}},preserveToString:function(e,t){if(t&&d(t.toString)){h(e,\"toString\",t.toString.bind(t),true)}}};var O=Object.create||function(e,t){var r=function Prototype(){};r.prototype=e;var o=new r;if(typeof t!==\"undefined\"){n(t).forEach(function(e){m.defineByDescriptor(o,e,t[e])})}return o};var w=function(e,t){if(!Object.setPrototypeOf){return false}return a(function(){var r=function Subclass(t){var r=new e(t);Object.setPrototypeOf(r,Subclass.prototype);return r};Object.setPrototypeOf(r,e);r.prototype=O(e.prototype,{constructor:{value:r}});return t(r)})};var j=function(){if(typeof self!==\"undefined\"){return self}if(typeof window!==\"undefined\"){return window}if(typeof global!==\"undefined\"){return global}throw new Error(\"unable to locate global object\")};var S=j();var T=S.isFinite;var I=Function.call.bind(String.prototype.indexOf);var E=Function.apply.bind(Array.prototype.indexOf);var P=Function.call.bind(Array.prototype.concat);var C=Function.call.bind(String.prototype.slice);var M=Function.call.bind(Array.prototype.push);var x=Function.apply.bind(Array.prototype.push);var N=Function.call.bind(Array.prototype.shift);var A=Math.max;var R=Math.min;var _=Math.floor;var k=Math.abs;var L=Math.exp;var F=Math.log;var D=Math.sqrt;var z=Function.call.bind(Object.prototype.hasOwnProperty);var q;var W=function(){};var G=S.Map;var H=G&&G.prototype[\"delete\"];var V=G&&G.prototype.get;var B=G&&G.prototype.has;var U=G&&G.prototype.set;var $=S.Symbol||{};var J=$.species||\"@@species\";var X=Number.isNaN||function isNaN(e){return e!==e};var K=Number.isFinite||function isFinite(e){return typeof e===\"number\"&&T(e)};var Z=d(Math.sign)?Math.sign:function sign(e){var t=Number(e);if(t===0){return t}if(X(t)){return t}return t<0?-1:1};var Y=function log1p(e){var t=Number(e);if(t<-1||X(t)){return NaN}if(t===0||t===Infinity){return t}if(t===-1){return-Infinity}return 1+t-1===0?t:t*(F(1+t)/(1+t-1))};var Q=function isArguments(e){return g(e)===\"[object Arguments]\"};var ee=function isArguments(e){return e!==null&&typeof e===\"object\"&&typeof e.length===\"number\"&&e.length>=0&&g(e)!==\"[object Array]\"&&g(e.callee)===\"[object Function]\"};var te=Q(arguments)?Q:ee;var re={primitive:function(e){return e===null||typeof e!==\"function\"&&typeof e!==\"object\"},string:function(e){return g(e)===\"[object String]\"},regex:function(e){return g(e)===\"[object RegExp]\"},symbol:function(e){return typeof S.Symbol===\"function\"&&typeof e===\"symbol\"}};var ne=function overrideNative(e,t,r){var n=e[t];h(e,t,r,true);m.preserveToString(e[t],n)};var oe=typeof $===\"function\"&&typeof $[\"for\"]===\"function\"&&re.symbol($());var ie=re.symbol($.iterator)?$.iterator:\"_es6-shim iterator_\";if(S.Set&&typeof(new S.Set)[\"@@iterator\"]===\"function\"){ie=\"@@iterator\"}if(!S.Reflect){h(S,\"Reflect\",{},true)}var ae=S.Reflect;var ue=String;var fe=typeof document===\"undefined\"||!document?null:document.all;var se=fe==null?function isNullOrUndefined(e){return e==null}:function isNullOrUndefinedAndNotDocumentAll(e){return e==null&&e!==fe};var ce={Call:function Call(t,r){var n=arguments.length>2?arguments[2]:[];if(!ce.IsCallable(t)){throw new TypeError(t+\" is not a function\")}return e(t,r,n)},RequireObjectCoercible:function(e,t){if(se(e)){throw new TypeError(t||\"Cannot call method on \"+e)}return e},TypeIsObject:function(e){if(e===void 0||e===null||e===true||e===false){return false}return typeof e===\"function\"||typeof e===\"object\"||e===fe},ToObject:function(e,t){return Object(ce.RequireObjectCoercible(e,t))},IsCallable:d,IsConstructor:function(e){return ce.IsCallable(e)},ToInt32:function(e){return ce.ToNumber(e)>>0},ToUint32:function(e){return ce.ToNumber(e)>>>0},ToNumber:function(e){if(g(e)===\"[object Symbol]\"){throw new TypeError(\"Cannot convert a Symbol value to a number\")}return+e},ToInteger:function(e){var t=ce.ToNumber(e);if(X(t)){return 0}if(t===0||!K(t)){return t}return(t>0?1:-1)*_(k(t))},ToLength:function(e){var t=ce.ToInteger(e);if(t<=0){return 0}if(t>Number.MAX_SAFE_INTEGER){return Number.MAX_SAFE_INTEGER}return t},SameValue:function(e,t){if(e===t){if(e===0){return 1/e===1/t}return true}return X(e)&&X(t)},SameValueZero:function(e,t){return e===t||X(e)&&X(t)},IsIterable:function(e){return ce.TypeIsObject(e)&&(typeof e[ie]!==\"undefined\"||te(e))},GetIterator:function(e){if(te(e)){return new q(e,\"value\")}var t=ce.GetMethod(e,ie);if(!ce.IsCallable(t)){throw new TypeError(\"value is not an iterable\")}var r=ce.Call(t,e);if(!ce.TypeIsObject(r)){throw new TypeError(\"bad iterator\")}return r},GetMethod:function(e,t){var r=ce.ToObject(e)[t];if(se(r)){return void 0}if(!ce.IsCallable(r)){throw new TypeError(\"Method not callable: \"+t)}return r},IteratorComplete:function(e){return!!e.done},IteratorClose:function(e,t){var r=ce.GetMethod(e,\"return\");if(r===void 0){return}var n,o;try{n=ce.Call(r,e)}catch(i){o=i}if(t){return}if(o){throw o}if(!ce.TypeIsObject(n)){throw new TypeError(\"Iterator's return method returned a non-object.\")}},IteratorNext:function(e){var t=arguments.length>1?e.next(arguments[1]):e.next();if(!ce.TypeIsObject(t)){throw new TypeError(\"bad iterator\")}return t},IteratorStep:function(e){var t=ce.IteratorNext(e);var r=ce.IteratorComplete(t);return r?false:t},Construct:function(e,t,r,n){var o=typeof r===\"undefined\"?e:r;if(!n&&ae.construct){return ae.construct(e,t,o)}var i=o.prototype;if(!ce.TypeIsObject(i)){i=Object.prototype}var a=O(i);var u=ce.Call(e,a,t);return ce.TypeIsObject(u)?u:a},SpeciesConstructor:function(e,t){var r=e.constructor;if(r===void 0){return t}if(!ce.TypeIsObject(r)){throw new TypeError(\"Bad constructor\")}var n=r[J];if(se(n)){return t}if(!ce.IsConstructor(n)){throw new TypeError(\"Bad @@species\")}return n},CreateHTML:function(e,t,r,n){var o=ce.ToString(e);var i=\"<\"+t;if(r!==\"\"){var a=ce.ToString(n);var u=a.replace(/\"/g,\"&quot;\");i+=\" \"+r+'=\"'+u+'\"'}var f=i+\">\";var s=f+o;return s+\"</\"+t+\">\"},IsRegExp:function IsRegExp(e){if(!ce.TypeIsObject(e)){return false}var t=e[$.match];if(typeof t!==\"undefined\"){return!!t}return re.regex(e)},ToString:function ToString(e){return ue(e)}};if(s&&oe){var le=function defineWellKnownSymbol(e){if(re.symbol($[e])){return $[e]}var t=$[\"for\"](\"Symbol.\"+e);Object.defineProperty($,e,{configurable:false,enumerable:false,writable:false,value:t});return t};if(!re.symbol($.search)){var pe=le(\"search\");var ve=String.prototype.search;h(RegExp.prototype,pe,function search(e){return ce.Call(ve,e,[this])});var ye=function search(e){var t=ce.RequireObjectCoercible(this);if(!se(e)){var r=ce.GetMethod(e,pe);if(typeof r!==\"undefined\"){return ce.Call(r,e,[t])}}return ce.Call(ve,t,[ce.ToString(e)])};ne(String.prototype,\"search\",ye)}if(!re.symbol($.replace)){var he=le(\"replace\");var be=String.prototype.replace;h(RegExp.prototype,he,function replace(e,t){return ce.Call(be,e,[this,t])});var ge=function replace(e,t){var r=ce.RequireObjectCoercible(this);if(!se(e)){var n=ce.GetMethod(e,he);if(typeof n!==\"undefined\"){return ce.Call(n,e,[r,t])}}return ce.Call(be,r,[ce.ToString(e),t])};ne(String.prototype,\"replace\",ge)}if(!re.symbol($.split)){var de=le(\"split\");var me=String.prototype.split;h(RegExp.prototype,de,function split(e,t){return ce.Call(me,e,[this,t])});var Oe=function split(e,t){var r=ce.RequireObjectCoercible(this);if(!se(e)){var n=ce.GetMethod(e,de);if(typeof n!==\"undefined\"){return ce.Call(n,e,[r,t])}}return ce.Call(me,r,[ce.ToString(e),t])};ne(String.prototype,\"split\",Oe)}var we=re.symbol($.match);var je=we&&function(){var e={};e[$.match]=function(){return 42};return\"a\".match(e)!==42}();if(!we||je){var Se=le(\"match\");var Te=String.prototype.match;h(RegExp.prototype,Se,function match(e){return ce.Call(Te,e,[this])});var Ie=function match(e){var t=ce.RequireObjectCoercible(this);if(!se(e)){var r=ce.GetMethod(e,Se);if(typeof r!==\"undefined\"){return ce.Call(r,e,[t])}}return ce.Call(Te,t,[ce.ToString(e)])};ne(String.prototype,\"match\",Ie)}}var Ee=function wrapConstructor(e,t,r){m.preserveToString(t,e);if(Object.setPrototypeOf){Object.setPrototypeOf(e,t)}if(s){l(Object.getOwnPropertyNames(e),function(n){if(n in W||r[n]){return}m.proxy(e,n,t)})}else{l(Object.keys(e),function(n){if(n in W||r[n]){return}t[n]=e[n]})}t.prototype=e.prototype;m.redefine(e.prototype,\"constructor\",t)};var Pe=function(){return this};var Ce=function(e){if(s&&!z(e,J)){m.getter(e,J,Pe)}};var Me=function(e,t){var r=t||function iterator(){return this};h(e,ie,r);if(!e[ie]&&re.symbol(ie)){e[ie]=r}};var xe=function createDataProperty(e,t,r){if(s){Object.defineProperty(e,t,{configurable:true,enumerable:true,writable:true,value:r})}else{e[t]=r}};var Ne=function createDataPropertyOrThrow(e,t,r){xe(e,t,r);if(!ce.SameValue(e[t],r)){throw new TypeError(\"property is nonconfigurable\")}};var Ae=function(e,t,r,n){if(!ce.TypeIsObject(e)){throw new TypeError(\"Constructor requires `new`: \"+t.name)}var o=t.prototype;if(!ce.TypeIsObject(o)){o=r}var i=O(o);for(var a in n){if(z(n,a)){var u=n[a];h(i,a,u,true)}}return i};if(String.fromCodePoint&&String.fromCodePoint.length!==1){var Re=String.fromCodePoint;ne(String,\"fromCodePoint\",function fromCodePoint(e){return ce.Call(Re,this,arguments)})}var _e={fromCodePoint:function fromCodePoint(e){var t=[];var r;for(var n=0,o=arguments.length;n<o;n++){r=Number(arguments[n]);if(!ce.SameValue(r,ce.ToInteger(r))||r<0||r>1114111){throw new RangeError(\"Invalid code point \"+r)}if(r<65536){M(t,String.fromCharCode(r))}else{r-=65536;M(t,String.fromCharCode((r>>10)+55296));M(t,String.fromCharCode(r%1024+56320))}}return t.join(\"\")},raw:function raw(e){var t=ce.ToObject(e,\"bad callSite\");var r=ce.ToObject(t.raw,\"bad raw value\");var n=r.length;var o=ce.ToLength(n);if(o<=0){return\"\"}var i=[];var a=0;var u,f,s,c;while(a<o){u=ce.ToString(a);s=ce.ToString(r[u]);M(i,s);if(a+1>=o){break}f=a+1<arguments.length?arguments[a+1]:\"\";c=ce.ToString(f);M(i,c);a+=1}return i.join(\"\")}};if(String.raw&&String.raw({raw:{0:\"x\",1:\"y\",length:2}})!==\"xy\"){ne(String,\"raw\",_e.raw)}b(String,_e);var ke=function repeat(e,t){if(t<1){return\"\"}if(t%2){return repeat(e,t-1)+e}var r=repeat(e,t/2);return r+r};var Le=Infinity;var Fe={repeat:function repeat(e){var t=ce.ToString(ce.RequireObjectCoercible(this));var r=ce.ToInteger(e);if(r<0||r>=Le){throw new RangeError(\"repeat count must be less than infinity and not overflow maximum string size\")}return ke(t,r)},startsWith:function startsWith(e){var t=ce.ToString(ce.RequireObjectCoercible(this));if(ce.IsRegExp(e)){throw new TypeError('Cannot call method \"startsWith\" with a regex')}var r=ce.ToString(e);var n;if(arguments.length>1){n=arguments[1]}var o=A(ce.ToInteger(n),0);return C(t,o,o+r.length)===r},endsWith:function endsWith(e){var t=ce.ToString(ce.RequireObjectCoercible(this));if(ce.IsRegExp(e)){throw new TypeError('Cannot call method \"endsWith\" with a regex')}var r=ce.ToString(e);var n=t.length;var o;if(arguments.length>1){o=arguments[1]}var i=typeof o===\"undefined\"?n:ce.ToInteger(o);var a=R(A(i,0),n);return C(t,a-r.length,a)===r},includes:function includes(e){if(ce.IsRegExp(e)){throw new TypeError('\"includes\" does not accept a RegExp')}var t=ce.ToString(e);var r;if(arguments.length>1){r=arguments[1]}return I(this,t,r)!==-1},codePointAt:function codePointAt(e){var t=ce.ToString(ce.RequireObjectCoercible(this));var r=ce.ToInteger(e);var n=t.length;if(r>=0&&r<n){var o=t.charCodeAt(r);var i=r+1===n;if(o<55296||o>56319||i){return o}var a=t.charCodeAt(r+1);if(a<56320||a>57343){return o}return(o-55296)*1024+(a-56320)+65536}}};if(String.prototype.includes&&\"a\".includes(\"a\",Infinity)!==false){ne(String.prototype,\"includes\",Fe.includes)}if(String.prototype.startsWith&&String.prototype.endsWith){var De=i(function(){return\"/a/\".startsWith(/a/)});var ze=a(function(){return\"abc\".startsWith(\"a\",Infinity)===false});if(!De||!ze){ne(String.prototype,\"startsWith\",Fe.startsWith);ne(String.prototype,\"endsWith\",Fe.endsWith)}}if(oe){var qe=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".startsWith(e)});if(!qe){ne(String.prototype,\"startsWith\",Fe.startsWith)}var We=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".endsWith(e)});if(!We){ne(String.prototype,\"endsWith\",Fe.endsWith)}var Ge=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".includes(e)});if(!Ge){ne(String.prototype,\"includes\",Fe.includes)}}b(String.prototype,Fe);var He=[\"\\t\\n\\x0B\\f\\r \\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\",\"\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\",\"\\u2029\\ufeff\"].join(\"\");var Ve=new RegExp(\"(^[\"+He+\"]+)|([\"+He+\"]+$)\",\"g\");var Be=function trim(){return ce.ToString(ce.RequireObjectCoercible(this)).replace(Ve,\"\")};var Ue=[\"\\x85\",\"\\u200b\",\"\\ufffe\"].join(\"\");var $e=new RegExp(\"[\"+Ue+\"]\",\"g\");var Je=/^[-+]0x[0-9a-f]+$/i;var Xe=Ue.trim().length!==Ue.length;h(String.prototype,\"trim\",Be,Xe);var Ke=function(e){return{value:e,done:arguments.length===0}};var Ze=function(e){ce.RequireObjectCoercible(e);this._s=ce.ToString(e);this._i=0};Ze.prototype.next=function(){var e=this._s;var t=this._i;if(typeof e===\"undefined\"||t>=e.length){this._s=void 0;return Ke()}var r=e.charCodeAt(t);var n,o;if(r<55296||r>56319||t+1===e.length){o=1}else{n=e.charCodeAt(t+1);o=n<56320||n>57343?1:2}this._i=t+o;return Ke(e.substr(t,o))};Me(Ze.prototype);Me(String.prototype,function(){return new Ze(this)});var Ye={from:function from(e){var r=this;var n;if(arguments.length>1){n=arguments[1]}var o,i;if(typeof n===\"undefined\"){o=false}else{if(!ce.IsCallable(n)){throw new TypeError(\"Array.from: when provided, the second argument must be a function\")}if(arguments.length>2){i=arguments[2]}o=true}var a=typeof(te(e)||ce.GetMethod(e,ie))!==\"undefined\";var u,f,s;if(a){f=ce.IsConstructor(r)?Object(new r):[];var c=ce.GetIterator(e);var l,p;s=0;while(true){l=ce.IteratorStep(c);if(l===false){break}p=l.value;try{if(o){p=typeof i===\"undefined\"?n(p,s):t(n,i,p,s)}f[s]=p}catch(v){ce.IteratorClose(c,true);throw v}s+=1}u=s}else{var y=ce.ToObject(e);u=ce.ToLength(y.length);f=ce.IsConstructor(r)?Object(new r(u)):new Array(u);var h;for(s=0;s<u;++s){h=y[s];if(o){h=typeof i===\"undefined\"?n(h,s):t(n,i,h,s)}Ne(f,s,h)}}f.length=u;return f},of:function of(){var e=arguments.length;var t=this;var n=r(t)||!ce.IsCallable(t)?new Array(e):ce.Construct(t,[e]);for(var o=0;o<e;++o){Ne(n,o,arguments[o])}n.length=e;return n}};b(Array,Ye);Ce(Array);q=function(e,t){this.i=0;this.array=e;this.kind=t};b(q.prototype,{next:function(){var e=this.i;var t=this.array;if(!(this instanceof q)){throw new TypeError(\"Not an ArrayIterator\")}if(typeof t!==\"undefined\"){var r=ce.ToLength(t.length);for(;e<r;e++){var n=this.kind;var o;if(n===\"key\"){o=e}else if(n===\"value\"){o=t[e]}else if(n===\"entry\"){o=[e,t[e]]}this.i=e+1;return Ke(o)}}this.array=void 0;return Ke()}});Me(q.prototype);var Qe=Array.of===Ye.of||function(){var e=function Foo(e){this.length=e};e.prototype=[];var t=Array.of.apply(e,[1,2]);return t instanceof e&&t.length===2}();if(!Qe){ne(Array,\"of\",Ye.of)}var et={copyWithin:function copyWithin(e,t){var r=ce.ToObject(this);var n=ce.ToLength(r.length);var o=ce.ToInteger(e);var i=ce.ToInteger(t);var a=o<0?A(n+o,0):R(o,n);var u=i<0?A(n+i,0):R(i,n);var f;if(arguments.length>2){f=arguments[2]}var s=typeof f===\"undefined\"?n:ce.ToInteger(f);var c=s<0?A(n+s,0):R(s,n);var l=R(c-u,n-a);var p=1;if(u<a&&a<u+l){p=-1;u+=l-1;a+=l-1}while(l>0){if(u in r){r[a]=r[u]}else{delete r[a]}u+=p;a+=p;l-=1}return r},fill:function fill(e){var t;if(arguments.length>1){t=arguments[1]}var r;if(arguments.length>2){r=arguments[2]}var n=ce.ToObject(this);var o=ce.ToLength(n.length);t=ce.ToInteger(typeof t===\"undefined\"?0:t);r=ce.ToInteger(typeof r===\"undefined\"?o:r);var i=t<0?A(o+t,0):R(t,o);var a=r<0?o+r:r;for(var u=i;u<o&&u<a;++u){n[u]=e}return n},find:function find(e){var r=ce.ToObject(this);var n=ce.ToLength(r.length);if(!ce.IsCallable(e)){throw new TypeError(\"Array#find: predicate must be a function\")}var o=arguments.length>1?arguments[1]:null;for(var i=0,a;i<n;i++){a=r[i];if(o){if(t(e,o,a,i,r)){return a}}else if(e(a,i,r)){return a}}},findIndex:function findIndex(e){var r=ce.ToObject(this);var n=ce.ToLength(r.length);if(!ce.IsCallable(e)){throw new TypeError(\"Array#findIndex: predicate must be a function\")}var o=arguments.length>1?arguments[1]:null;for(var i=0;i<n;i++){if(o){if(t(e,o,r[i],i,r)){return i}}else if(e(r[i],i,r)){return i}}return-1},keys:function keys(){return new q(this,\"key\")},values:function values(){return new q(this,\"value\")},entries:function entries(){return new q(this,\"entry\")}};if(Array.prototype.keys&&!ce.IsCallable([1].keys().next)){delete Array.prototype.keys}if(Array.prototype.entries&&!ce.IsCallable([1].entries().next)){delete Array.prototype.entries}if(Array.prototype.keys&&Array.prototype.entries&&!Array.prototype.values&&Array.prototype[ie]){b(Array.prototype,{values:Array.prototype[ie]});if(re.symbol($.unscopables)){Array.prototype[$.unscopables].values=true}}if(c&&Array.prototype.values&&Array.prototype.values.name!==\"values\"){var tt=Array.prototype.values;ne(Array.prototype,\"values\",function values(){return ce.Call(tt,this,arguments)});h(Array.prototype,ie,Array.prototype.values,true)}b(Array.prototype,et);if(1/[true].indexOf(true,-0)<0){h(Array.prototype,\"indexOf\",function indexOf(e){var t=E(this,arguments);if(t===0&&1/t<0){return 0}return t},true)}Me(Array.prototype,function(){return this.values()});if(Object.getPrototypeOf){Me(Object.getPrototypeOf([].values()))}var rt=function(){return a(function(){return Array.from({length:-1}).length===0})}();var nt=function(){var e=Array.from([0].entries());return e.length===1&&r(e[0])&&e[0][0]===0&&e[0][1]===0}();if(!rt||!nt){ne(Array,\"from\",Ye.from)}var ot=function(){return a(function(){return Array.from([0],void 0)})}();if(!ot){var it=Array.from;ne(Array,\"from\",function from(e){if(arguments.length>1&&typeof arguments[1]!==\"undefined\"){return ce.Call(it,this,arguments)}else{return t(it,this,e)}})}var at=-(Math.pow(2,32)-1);var ut=function(e,r){var n={length:at};n[r?(n.length>>>0)-1:0]=true;return a(function(){t(e,n,function(){throw new RangeError(\"should not reach here\")},[]);return true})};if(!ut(Array.prototype.forEach)){var ft=Array.prototype.forEach;ne(Array.prototype,\"forEach\",function forEach(e){return ce.Call(ft,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.map)){var st=Array.prototype.map;ne(Array.prototype,\"map\",function map(e){return ce.Call(st,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.filter)){var ct=Array.prototype.filter;ne(Array.prototype,\"filter\",function filter(e){return ce.Call(ct,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.some)){var lt=Array.prototype.some;ne(Array.prototype,\"some\",function some(e){return ce.Call(lt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.every)){var pt=Array.prototype.every;ne(Array.prototype,\"every\",function every(e){return ce.Call(pt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.reduce)){var vt=Array.prototype.reduce;ne(Array.prototype,\"reduce\",function reduce(e){return ce.Call(vt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.reduceRight,true)){var yt=Array.prototype.reduceRight;ne(Array.prototype,\"reduceRight\",function reduceRight(e){return ce.Call(yt,this.length>=0?this:[],arguments)},true)}var ht=Number(\"0o10\")!==8;var bt=Number(\"0b10\")!==2;var gt=y(Ue,function(e){return Number(e+0+e)===0});if(ht||bt||gt){var dt=Number;var mt=/^0b[01]+$/i;var Ot=/^0o[0-7]+$/i;var wt=mt.test.bind(mt);var jt=Ot.test.bind(Ot);var St=function(e){var t;if(typeof e.valueOf===\"function\"){t=e.valueOf();if(re.primitive(t)){return t}}if(typeof e.toString===\"function\"){t=e.toString();if(re.primitive(t)){return t}}throw new TypeError(\"No default value\")};var Tt=$e.test.bind($e);var It=Je.test.bind(Je);var Et=function(){var e=function Number(t){var r;if(arguments.length>0){r=re.primitive(t)?t:St(t,\"number\")}else{r=0}if(typeof r===\"string\"){r=ce.Call(Be,r);if(wt(r)){r=parseInt(C(r,2),2)}else if(jt(r)){r=parseInt(C(r,2),8)}else if(Tt(r)||It(r)){r=NaN}}var n=this;var o=a(function(){dt.prototype.valueOf.call(n);return true});if(n instanceof e&&!o){return new dt(r)}return dt(r)};return e}();Ee(dt,Et,{});b(Et,{NaN:dt.NaN,MAX_VALUE:dt.MAX_VALUE,MIN_VALUE:dt.MIN_VALUE,NEGATIVE_INFINITY:dt.NEGATIVE_INFINITY,POSITIVE_INFINITY:dt.POSITIVE_INFINITY});Number=Et;m.redefine(S,\"Number\",Et)}var Pt=Math.pow(2,53)-1;b(Number,{MAX_SAFE_INTEGER:Pt,MIN_SAFE_INTEGER:-Pt,EPSILON:2.220446049250313e-16,parseInt:S.parseInt,parseFloat:S.parseFloat,isFinite:K,isInteger:function isInteger(e){return K(e)&&ce.ToInteger(e)===e},isSafeInteger:function isSafeInteger(e){return Number.isInteger(e)&&k(e)<=Number.MAX_SAFE_INTEGER},isNaN:X});h(Number,\"parseInt\",S.parseInt,Number.parseInt!==S.parseInt);if([,1].find(function(){return true})===1){ne(Array.prototype,\"find\",et.find)}if([,1].findIndex(function(){return true})!==0){ne(Array.prototype,\"findIndex\",et.findIndex)}var Ct=Function.bind.call(Function.bind,Object.prototype.propertyIsEnumerable);var Mt=function ensureEnumerable(e,t){if(s&&Ct(e,t)){Object.defineProperty(e,t,{enumerable:false})}};var xt=function sliceArgs(){var e=Number(this);var t=arguments.length;var r=t-e;var n=new Array(r<0?0:r);for(var o=e;o<t;++o){n[o-e]=arguments[o]}return n};var Nt=function assignTo(e){return function assignToSource(t,r){t[r]=e[r];return t}};var At=function(e,t){var r=n(Object(t));var o;if(ce.IsCallable(Object.getOwnPropertySymbols)){o=v(Object.getOwnPropertySymbols(Object(t)),Ct(t))}return p(P(r,o||[]),Nt(t),e)};var Rt={assign:function(e,t){var r=ce.ToObject(e,\"Cannot convert undefined or null to object\");return p(ce.Call(xt,1,arguments),At,r)},is:function is(e,t){return ce.SameValue(e,t)}};var _t=Object.assign&&Object.preventExtensions&&function(){var e=Object.preventExtensions({1:2});try{Object.assign(e,\"xy\")}catch(t){return e[1]===\"y\"}}();if(_t){ne(Object,\"assign\",Rt.assign)}b(Object,Rt);if(s){var kt={setPrototypeOf:function(e,r){var n;var o=function(e,t){if(!ce.TypeIsObject(e)){throw new TypeError(\"cannot set prototype on a non-object\")}if(!(t===null||ce.TypeIsObject(t))){throw new TypeError(\"can only set prototype to an object or null\"+t)}};var i=function(e,r){o(e,r);t(n,e,r);return e};try{n=e.getOwnPropertyDescriptor(e.prototype,r).set;t(n,{},null)}catch(a){if(e.prototype!=={}[r]){return}n=function(e){this[r]=e};i.polyfill=i(i({},null),e.prototype)instanceof e}return i}(Object,\"__proto__\")};b(Object,kt)}if(Object.setPrototypeOf&&Object.getPrototypeOf&&Object.getPrototypeOf(Object.setPrototypeOf({},null))!==null&&Object.getPrototypeOf(Object.create(null))===null){(function(){var e=Object.create(null);var t=Object.getPrototypeOf;var r=Object.setPrototypeOf;Object.getPrototypeOf=function(r){var n=t(r);return n===e?null:n};Object.setPrototypeOf=function(t,n){var o=n===null?e:n;return r(t,o)};Object.setPrototypeOf.polyfill=false})()}var Lt=!i(function(){return Object.keys(\"foo\")});if(!Lt){var Ft=Object.keys;ne(Object,\"keys\",function keys(e){return Ft(ce.ToObject(e))});n=Object.keys}var Dt=i(function(){return Object.keys(/a/g)});if(Dt){var zt=Object.keys;ne(Object,\"keys\",function keys(e){if(re.regex(e)){var t=[];for(var r in e){if(z(e,r)){M(t,r)}}return t}return zt(e)});n=Object.keys}if(Object.getOwnPropertyNames){var qt=!i(function(){return Object.getOwnPropertyNames(\"foo\")});if(!qt){var Wt=typeof window===\"object\"?Object.getOwnPropertyNames(window):[];var Gt=Object.getOwnPropertyNames;ne(Object,\"getOwnPropertyNames\",function getOwnPropertyNames(e){var t=ce.ToObject(e);if(g(t)===\"[object Window]\"){try{return Gt(t)}catch(r){return P([],Wt)}}return Gt(t)})}}if(Object.getOwnPropertyDescriptor){var Ht=!i(function(){return Object.getOwnPropertyDescriptor(\"foo\",\"bar\")});if(!Ht){var Vt=Object.getOwnPropertyDescriptor;ne(Object,\"getOwnPropertyDescriptor\",function getOwnPropertyDescriptor(e,t){return Vt(ce.ToObject(e),t)})}}if(Object.seal){var Bt=!i(function(){return Object.seal(\"foo\")});if(!Bt){var Ut=Object.seal;ne(Object,\"seal\",function seal(e){if(!ce.TypeIsObject(e)){return e}return Ut(e)})}}if(Object.isSealed){var $t=!i(function(){return Object.isSealed(\"foo\")});if(!$t){var Jt=Object.isSealed;ne(Object,\"isSealed\",function isSealed(e){if(!ce.TypeIsObject(e)){return true}return Jt(e)})}}if(Object.freeze){var Xt=!i(function(){return Object.freeze(\"foo\")});if(!Xt){var Kt=Object.freeze;ne(Object,\"freeze\",function freeze(e){if(!ce.TypeIsObject(e)){return e}return Kt(e)})}}if(Object.isFrozen){var Zt=!i(function(){return Object.isFrozen(\"foo\")});if(!Zt){var Yt=Object.isFrozen;ne(Object,\"isFrozen\",function isFrozen(e){if(!ce.TypeIsObject(e)){return true}return Yt(e)})}}if(Object.preventExtensions){var Qt=!i(function(){return Object.preventExtensions(\"foo\")});if(!Qt){var er=Object.preventExtensions;ne(Object,\"preventExtensions\",function preventExtensions(e){if(!ce.TypeIsObject(e)){return e}return er(e)})}}if(Object.isExtensible){var tr=!i(function(){return Object.isExtensible(\"foo\")});if(!tr){var rr=Object.isExtensible;ne(Object,\"isExtensible\",function isExtensible(e){if(!ce.TypeIsObject(e)){return false}return rr(e)})}}if(Object.getPrototypeOf){var nr=!i(function(){return Object.getPrototypeOf(\"foo\")});if(!nr){var or=Object.getPrototypeOf;ne(Object,\"getPrototypeOf\",function getPrototypeOf(e){return or(ce.ToObject(e))})}}var ir=s&&function(){var e=Object.getOwnPropertyDescriptor(RegExp.prototype,\"flags\");return e&&ce.IsCallable(e.get)}();if(s&&!ir){var ar=function flags(){if(!ce.TypeIsObject(this)){throw new TypeError(\"Method called on incompatible type: must be an object.\")}var e=\"\";if(this.global){e+=\"g\"}if(this.ignoreCase){e+=\"i\"}if(this.multiline){e+=\"m\"}if(this.unicode){e+=\"u\"}if(this.sticky){e+=\"y\"}return e};m.getter(RegExp.prototype,\"flags\",ar)}var ur=s&&a(function(){return String(new RegExp(/a/g,\"i\"))===\"/a/i\"});var fr=oe&&s&&function(){var e=/./;e[$.match]=false;return RegExp(e)===e}();var sr=a(function(){return RegExp.prototype.toString.call({source:\"abc\"})===\"/abc/\"});var cr=sr&&a(function(){return RegExp.prototype.toString.call({source:\"a\",flags:\"b\"})===\"/a/b\"});if(!sr||!cr){var lr=RegExp.prototype.toString;h(RegExp.prototype,\"toString\",function toString(){var e=ce.RequireObjectCoercible(this);if(re.regex(e)){return t(lr,e)}var r=ue(e.source);var n=ue(e.flags);return\"/\"+r+\"/\"+n},true);m.preserveToString(RegExp.prototype.toString,lr)}if(s&&(!ur||fr)){var pr=Object.getOwnPropertyDescriptor(RegExp.prototype,\"flags\").get;var vr=Object.getOwnPropertyDescriptor(RegExp.prototype,\"source\")||{};var yr=function(){return this.source};var hr=ce.IsCallable(vr.get)?vr.get:yr;var br=RegExp;var gr=function(){return function RegExp(e,t){var r=ce.IsRegExp(e);var n=this instanceof RegExp;if(!n&&r&&typeof t===\"undefined\"&&e.constructor===RegExp){return e}var o=e;var i=t;if(re.regex(e)){o=ce.Call(hr,e);i=typeof t===\"undefined\"?ce.Call(pr,e):t;return new RegExp(o,i)}else if(r){o=e.source;i=typeof t===\"undefined\"?e.flags:t}return new br(e,t)}}();Ee(br,gr,{$input:true});RegExp=gr;m.redefine(S,\"RegExp\",gr)}if(s){var dr={input:\"$_\",lastMatch:\"$&\",lastParen:\"$+\",leftContext:\"$`\",rightContext:\"$'\"};l(n(dr),function(e){if(e in RegExp&&!(dr[e]in RegExp)){m.getter(RegExp,dr[e],function get(){return RegExp[e]})}})}Ce(RegExp);var mr=1/Number.EPSILON;var Or=function roundTiesToEven(e){return e+mr-mr};var wr=Math.pow(2,-23);var jr=Math.pow(2,127)*(2-wr);var Sr=Math.pow(2,-126);var Tr=Math.E;var Ir=Math.LOG2E;var Er=Math.LOG10E;var Pr=Number.prototype.clz;delete Number.prototype.clz;var Cr={acosh:function acosh(e){var t=Number(e);if(X(t)||e<1){return NaN}if(t===1){return 0}if(t===Infinity){return t}var r=1/(t*t);if(t<2){return Y(t-1+D(1-r)*t)}var n=t/2;return Y(n+D(1-r)*n-1)+1/Ir},asinh:function asinh(e){var t=Number(e);if(t===0||!T(t)){return t}var r=k(t);var n=r*r;var o=Z(t);if(r<1){return o*Y(r+n/(D(n+1)+1))}return o*(Y(r/2+D(1+1/n)*r/2-1)+1/Ir)},atanh:function atanh(e){var t=Number(e);if(t===0){return t}if(t===-1){return-Infinity}if(t===1){return Infinity}if(X(t)||t<-1||t>1){return NaN}var r=k(t);return Z(t)*Y(2*r/(1-r))/2},cbrt:function cbrt(e){var t=Number(e);if(t===0){return t}var r=t<0;var n;if(r){t=-t}if(t===Infinity){n=Infinity}else{n=L(F(t)/3);n=(t/(n*n)+2*n)/3}return r?-n:n},clz32:function clz32(e){var t=Number(e);var r=ce.ToUint32(t);if(r===0){return 32}return Pr?ce.Call(Pr,r):31-_(F(r+.5)*Ir)},cosh:function cosh(e){var t=Number(e);if(t===0){return 1}if(X(t)){return NaN}if(!T(t)){return Infinity}var r=L(k(t)-1);return(r+1/(r*Tr*Tr))*(Tr/2)},expm1:function expm1(e){var t=Number(e);if(t===-Infinity){return-1}if(!T(t)||t===0){return t}if(k(t)>.5){return L(t)-1}var r=t;var n=0;var o=1;while(n+r!==n){n+=r;o+=1;r*=t/o}return n},hypot:function hypot(e,t){var r=0;var n=0;for(var o=0;o<arguments.length;++o){var i=k(Number(arguments[o]));if(n<i){r*=n/i*(n/i);r+=1;n=i}else{r+=i>0?i/n*(i/n):i}}return n===Infinity?Infinity:n*D(r)},log2:function log2(e){return F(e)*Ir},log10:function log10(e){return F(e)*Er},log1p:Y,sign:Z,sinh:function sinh(e){var t=Number(e);if(!T(t)||t===0){return t}var r=k(t);if(r<1){var n=Math.expm1(r);return Z(t)*n*(1+1/(n+1))/2}var o=L(r-1);return Z(t)*(o-1/(o*Tr*Tr))*(Tr/2)},tanh:function tanh(e){var t=Number(e);if(X(t)||t===0){return t}if(t>=20){return 1}if(t<=-20){return-1}return(Math.expm1(t)-Math.expm1(-t))/(L(t)+L(-t))},trunc:function trunc(e){var t=Number(e);return t<0?-_(-t):_(t)},imul:function imul(e,t){var r=ce.ToUint32(e);var n=ce.ToUint32(t);var o=r>>>16&65535;var i=r&65535;var a=n>>>16&65535;var u=n&65535;return i*u+(o*u+i*a<<16>>>0)|0},fround:function fround(e){var t=Number(e);if(t===0||t===Infinity||t===-Infinity||X(t)){return t}var r=Z(t);var n=k(t);if(n<Sr){return r*Or(n/Sr/wr)*Sr*wr}var o=(1+wr/Number.EPSILON)*n;var i=o-(o-n);if(i>jr||X(i)){return r*Infinity}return r*i}};var Mr=function withinULPDistance(e,t,r){return k(1-e/t)/Number.EPSILON<(r||8)};b(Math,Cr);h(Math,\"sinh\",Cr.sinh,Math.sinh(710)===Infinity);h(Math,\"cosh\",Cr.cosh,Math.cosh(710)===Infinity);h(Math,\"log1p\",Cr.log1p,Math.log1p(-1e-17)!==-1e-17);h(Math,\"asinh\",Cr.asinh,Math.asinh(-1e7)!==-Math.asinh(1e7));h(Math,\"asinh\",Cr.asinh,Math.asinh(1e300)===Infinity);h(Math,\"atanh\",Cr.atanh,Math.atanh(1e-300)===0);h(Math,\"tanh\",Cr.tanh,Math.tanh(-2e-17)!==-2e-17);\nh(Math,\"acosh\",Cr.acosh,Math.acosh(Number.MAX_VALUE)===Infinity);h(Math,\"acosh\",Cr.acosh,!Mr(Math.acosh(1+Number.EPSILON),Math.sqrt(2*Number.EPSILON)));h(Math,\"cbrt\",Cr.cbrt,!Mr(Math.cbrt(1e-300),1e-100));h(Math,\"sinh\",Cr.sinh,Math.sinh(-2e-17)!==-2e-17);var xr=Math.expm1(10);h(Math,\"expm1\",Cr.expm1,xr>22025.465794806718||xr<22025.465794806718);var Nr=Math.round;var Ar=Math.round(.5-Number.EPSILON/4)===0&&Math.round(-.5+Number.EPSILON/3.99)===1;var Rr=mr+1;var _r=2*mr-1;var kr=[Rr,_r].every(function(e){return Math.round(e)===e});h(Math,\"round\",function round(e){var t=_(e);var r=t===-1?-0:t+1;return e-t<.5?t:r},!Ar||!kr);m.preserveToString(Math.round,Nr);var Lr=Math.imul;if(Math.imul(4294967295,5)!==-5){Math.imul=Cr.imul;m.preserveToString(Math.imul,Lr)}if(Math.imul.length!==2){ne(Math,\"imul\",function imul(e,t){return ce.Call(Lr,Math,arguments)})}var Fr=function(){var e=S.setTimeout;if(typeof e!==\"function\"&&typeof e!==\"object\"){return}ce.IsPromise=function(e){if(!ce.TypeIsObject(e)){return false}if(typeof e._promise===\"undefined\"){return false}return true};var r=function(e){if(!ce.IsConstructor(e)){throw new TypeError(\"Bad promise constructor\")}var t=this;var r=function(e,r){if(t.resolve!==void 0||t.reject!==void 0){throw new TypeError(\"Bad Promise implementation!\")}t.resolve=e;t.reject=r};t.resolve=void 0;t.reject=void 0;t.promise=new e(r);if(!(ce.IsCallable(t.resolve)&&ce.IsCallable(t.reject))){throw new TypeError(\"Bad promise constructor\")}};var n;if(typeof window!==\"undefined\"&&ce.IsCallable(window.postMessage)){n=function(){var e=[];var t=\"zero-timeout-message\";var r=function(r){M(e,r);window.postMessage(t,\"*\")};var n=function(r){if(r.source===window&&r.data===t){r.stopPropagation();if(e.length===0){return}var n=N(e);n()}};window.addEventListener(\"message\",n,true);return r}}var o=function(){var e=S.Promise;var t=e&&e.resolve&&e.resolve();return t&&function(e){return t.then(e)}};var i=ce.IsCallable(S.setImmediate)?S.setImmediate:typeof process===\"object\"&&process.nextTick?process.nextTick:o()||(ce.IsCallable(n)?n():function(t){e(t,0)});var a=function(e){return e};var u=function(e){throw e};var f=0;var s=1;var c=2;var l=0;var p=1;var v=2;var y={};var h=function(e,t,r){i(function(){g(e,t,r)})};var g=function(e,t,r){var n,o;if(t===y){return e(r)}try{n=e(r);o=t.resolve}catch(i){n=i;o=t.reject}o(n)};var d=function(e,t){var r=e._promise;var n=r.reactionLength;if(n>0){h(r.fulfillReactionHandler0,r.reactionCapability0,t);r.fulfillReactionHandler0=void 0;r.rejectReactions0=void 0;r.reactionCapability0=void 0;if(n>1){for(var o=1,i=0;o<n;o++,i+=3){h(r[i+l],r[i+v],t);e[i+l]=void 0;e[i+p]=void 0;e[i+v]=void 0}}}r.result=t;r.state=s;r.reactionLength=0};var m=function(e,t){var r=e._promise;var n=r.reactionLength;if(n>0){h(r.rejectReactionHandler0,r.reactionCapability0,t);r.fulfillReactionHandler0=void 0;r.rejectReactions0=void 0;r.reactionCapability0=void 0;if(n>1){for(var o=1,i=0;o<n;o++,i+=3){h(r[i+p],r[i+v],t);e[i+l]=void 0;e[i+p]=void 0;e[i+v]=void 0}}}r.result=t;r.state=c;r.reactionLength=0};var O=function(e){var t=false;var r=function(r){var n;if(t){return}t=true;if(r===e){return m(e,new TypeError(\"Self resolution\"))}if(!ce.TypeIsObject(r)){return d(e,r)}try{n=r.then}catch(o){return m(e,o)}if(!ce.IsCallable(n)){return d(e,r)}i(function(){j(e,r,n)})};var n=function(r){if(t){return}t=true;return m(e,r)};return{resolve:r,reject:n}};var w=function(e,r,n,o){if(e===I){t(e,r,n,o,y)}else{t(e,r,n,o)}};var j=function(e,t,r){var n=O(e);var o=n.resolve;var i=n.reject;try{w(r,t,o,i)}catch(a){i(a)}};var T,I;var E=function(){var e=function Promise(t){if(!(this instanceof e)){throw new TypeError('Constructor Promise requires \"new\"')}if(this&&this._promise){throw new TypeError(\"Bad construction\")}if(!ce.IsCallable(t)){throw new TypeError(\"not a valid resolver\")}var r=Ae(this,e,T,{_promise:{result:void 0,state:f,reactionLength:0,fulfillReactionHandler0:void 0,rejectReactionHandler0:void 0,reactionCapability0:void 0}});var n=O(r);var o=n.reject;try{t(n.resolve,o)}catch(i){o(i)}return r};return e}();T=E.prototype;var P=function(e,t,r,n){var o=false;return function(i){if(o){return}o=true;t[e]=i;if(--n.count===0){var a=r.resolve;a(t)}}};var C=function(e,t,r){var n=e.iterator;var o=[];var i={count:1};var a,u;var f=0;while(true){try{a=ce.IteratorStep(n);if(a===false){e.done=true;break}u=a.value}catch(s){e.done=true;throw s}o[f]=void 0;var c=t.resolve(u);var l=P(f,o,r,i);i.count+=1;w(c.then,c,l,r.reject);f+=1}if(--i.count===0){var p=r.resolve;p(o)}return r.promise};var x=function(e,t,r){var n=e.iterator;var o,i,a;while(true){try{o=ce.IteratorStep(n);if(o===false){e.done=true;break}i=o.value}catch(u){e.done=true;throw u}a=t.resolve(i);w(a.then,a,r.resolve,r.reject)}return r.promise};b(E,{all:function all(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Promise is not object\")}var n=new r(t);var o,i;try{o=ce.GetIterator(e);i={iterator:o,done:false};return C(i,t,n)}catch(a){var u=a;if(i&&!i.done){try{ce.IteratorClose(o,true)}catch(f){u=f}}var s=n.reject;s(u);return n.promise}},race:function race(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Promise is not object\")}var n=new r(t);var o,i;try{o=ce.GetIterator(e);i={iterator:o,done:false};return x(i,t,n)}catch(a){var u=a;if(i&&!i.done){try{ce.IteratorClose(o,true)}catch(f){u=f}}var s=n.reject;s(u);return n.promise}},reject:function reject(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Bad promise constructor\")}var n=new r(t);var o=n.reject;o(e);return n.promise},resolve:function resolve(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Bad promise constructor\")}if(ce.IsPromise(e)){var n=e.constructor;if(n===t){return e}}var o=new r(t);var i=o.resolve;i(e);return o.promise}});b(T,{\"catch\":function(e){return this.then(null,e)},then:function then(e,t){var n=this;if(!ce.IsPromise(n)){throw new TypeError(\"not a promise\")}var o=ce.SpeciesConstructor(n,E);var i;var b=arguments.length>2&&arguments[2]===y;if(b&&o===E){i=y}else{i=new r(o)}var g=ce.IsCallable(e)?e:a;var d=ce.IsCallable(t)?t:u;var m=n._promise;var O;if(m.state===f){if(m.reactionLength===0){m.fulfillReactionHandler0=g;m.rejectReactionHandler0=d;m.reactionCapability0=i}else{var w=3*(m.reactionLength-1);m[w+l]=g;m[w+p]=d;m[w+v]=i}m.reactionLength+=1}else if(m.state===s){O=m.result;h(g,i,O)}else if(m.state===c){O=m.result;h(d,i,O)}else{throw new TypeError(\"unexpected Promise state\")}return i.promise}});y=new r(E);I=T.then;return E}();if(S.Promise){delete S.Promise.accept;delete S.Promise.defer;delete S.Promise.prototype.chain}if(typeof Fr===\"function\"){b(S,{Promise:Fr});var Dr=w(S.Promise,function(e){return e.resolve(42).then(function(){})instanceof e});var zr=!i(function(){return S.Promise.reject(42).then(null,5).then(null,W)});var qr=i(function(){return S.Promise.call(3,W)});var Wr=function(e){var t=e.resolve(5);t.constructor={};var r=e.resolve(t);try{r.then(null,W).then(null,W)}catch(n){return true}return t===r}(S.Promise);var Gr=s&&function(){var e=0;var t=Object.defineProperty({},\"then\",{get:function(){e+=1}});Promise.resolve(t);return e===1}();var Hr=function BadResolverPromise(e){var t=new Promise(e);e(3,function(){});this.then=t.then;this.constructor=BadResolverPromise};Hr.prototype=Promise.prototype;Hr.all=Promise.all;var Vr=a(function(){return!!Hr.all([1,2])});if(!Dr||!zr||!qr||Wr||!Gr||Vr){Promise=Fr;ne(S,\"Promise\",Fr)}if(Promise.all.length!==1){var Br=Promise.all;ne(Promise,\"all\",function all(e){return ce.Call(Br,this,arguments)})}if(Promise.race.length!==1){var Ur=Promise.race;ne(Promise,\"race\",function race(e){return ce.Call(Ur,this,arguments)})}if(Promise.resolve.length!==1){var $r=Promise.resolve;ne(Promise,\"resolve\",function resolve(e){return ce.Call($r,this,arguments)})}if(Promise.reject.length!==1){var Jr=Promise.reject;ne(Promise,\"reject\",function reject(e){return ce.Call(Jr,this,arguments)})}Mt(Promise,\"all\");Mt(Promise,\"race\");Mt(Promise,\"resolve\");Mt(Promise,\"reject\");Ce(Promise)}var Xr=function(e){var t=n(p(e,function(e,t){e[t]=true;return e},{}));return e.join(\":\")===t.join(\":\")};var Kr=Xr([\"z\",\"a\",\"bb\"]);var Zr=Xr([\"z\",1,\"a\",\"3\",2]);if(s){var Yr=function fastkey(e,t){if(!t&&!Kr){return null}if(se(e)){return\"^\"+ce.ToString(e)}else if(typeof e===\"string\"){return\"$\"+e}else if(typeof e===\"number\"){if(!Zr){return\"n\"+e}return e}else if(typeof e===\"boolean\"){return\"b\"+e}return null};var Qr=function emptyObject(){return Object.create?Object.create(null):{}};var en=function addIterableToMap(e,n,o){if(r(o)||re.string(o)){l(o,function(e){if(!ce.TypeIsObject(e)){throw new TypeError(\"Iterator value \"+e+\" is not an entry object\")}n.set(e[0],e[1])})}else if(o instanceof e){t(e.prototype.forEach,o,function(e,t){n.set(t,e)})}else{var i,a;if(!se(o)){a=n.set;if(!ce.IsCallable(a)){throw new TypeError(\"bad map\")}i=ce.GetIterator(o)}if(typeof i!==\"undefined\"){while(true){var u=ce.IteratorStep(i);if(u===false){break}var f=u.value;try{if(!ce.TypeIsObject(f)){throw new TypeError(\"Iterator value \"+f+\" is not an entry object\")}t(a,n,f[0],f[1])}catch(s){ce.IteratorClose(i,true);throw s}}}}};var tn=function addIterableToSet(e,n,o){if(r(o)||re.string(o)){l(o,function(e){n.add(e)})}else if(o instanceof e){t(e.prototype.forEach,o,function(e){n.add(e)})}else{var i,a;if(!se(o)){a=n.add;if(!ce.IsCallable(a)){throw new TypeError(\"bad set\")}i=ce.GetIterator(o)}if(typeof i!==\"undefined\"){while(true){var u=ce.IteratorStep(i);if(u===false){break}var f=u.value;try{t(a,n,f)}catch(s){ce.IteratorClose(i,true);throw s}}}}};var rn={Map:function(){var e={};var r=function MapEntry(e,t){this.key=e;this.value=t;this.next=null;this.prev=null};r.prototype.isRemoved=function isRemoved(){return this.key===e};var n=function isMap(e){return!!e._es6map};var o=function requireMapSlot(e,t){if(!ce.TypeIsObject(e)||!n(e)){throw new TypeError(\"Method Map.prototype.\"+t+\" called on incompatible receiver \"+ce.ToString(e))}};var i=function MapIterator(e,t){o(e,\"[[MapIterator]]\");this.head=e._head;this.i=this.head;this.kind=t};i.prototype={isMapIterator:true,next:function next(){if(!this.isMapIterator){throw new TypeError(\"Not a MapIterator\")}var e=this.i;var t=this.kind;var r=this.head;if(typeof this.i===\"undefined\"){return Ke()}while(e.isRemoved()&&e!==r){e=e.prev}var n;while(e.next!==r){e=e.next;if(!e.isRemoved()){if(t===\"key\"){n=e.key}else if(t===\"value\"){n=e.value}else{n=[e.key,e.value]}this.i=e;return Ke(n)}}this.i=void 0;return Ke()}};Me(i.prototype);var a;var u=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}if(this&&this._es6map){throw new TypeError(\"Bad construction\")}var e=Ae(this,Map,a,{_es6map:true,_head:null,_map:G?new G:null,_size:0,_storage:Qr()});var t=new r(null,null);t.next=t.prev=t;e._head=t;if(arguments.length>0){en(Map,e,arguments[0])}return e};a=u.prototype;m.getter(a,\"size\",function(){if(typeof this._size===\"undefined\"){throw new TypeError(\"size method called on incompatible Map\")}return this._size});b(a,{get:function get(e){o(this,\"get\");var t;var r=Yr(e,true);if(r!==null){t=this._storage[r];if(t){return t.value}else{return}}if(this._map){t=V.call(this._map,e);if(t){return t.value}else{return}}var n=this._head;var i=n;while((i=i.next)!==n){if(ce.SameValueZero(i.key,e)){return i.value}}},has:function has(e){o(this,\"has\");var t=Yr(e,true);if(t!==null){return typeof this._storage[t]!==\"undefined\"}if(this._map){return B.call(this._map,e)}var r=this._head;var n=r;while((n=n.next)!==r){if(ce.SameValueZero(n.key,e)){return true}}return false},set:function set(e,t){o(this,\"set\");var n=this._head;var i=n;var a;var u=Yr(e,true);if(u!==null){if(typeof this._storage[u]!==\"undefined\"){this._storage[u].value=t;return this}else{a=this._storage[u]=new r(e,t);i=n.prev}}else if(this._map){if(B.call(this._map,e)){V.call(this._map,e).value=t}else{a=new r(e,t);U.call(this._map,e,a);i=n.prev}}while((i=i.next)!==n){if(ce.SameValueZero(i.key,e)){i.value=t;return this}}a=a||new r(e,t);if(ce.SameValue(-0,e)){a.key=+0}a.next=this._head;a.prev=this._head.prev;a.prev.next=a;a.next.prev=a;this._size+=1;return this},\"delete\":function(t){o(this,\"delete\");var r=this._head;var n=r;var i=Yr(t,true);if(i!==null){if(typeof this._storage[i]===\"undefined\"){return false}n=this._storage[i].prev;delete this._storage[i]}else if(this._map){if(!B.call(this._map,t)){return false}n=V.call(this._map,t).prev;H.call(this._map,t)}while((n=n.next)!==r){if(ce.SameValueZero(n.key,t)){n.key=e;n.value=e;n.prev.next=n.next;n.next.prev=n.prev;this._size-=1;return true}}return false},clear:function clear(){o(this,\"clear\");this._map=G?new G:null;this._size=0;this._storage=Qr();var t=this._head;var r=t;var n=r.next;while((r=n)!==t){r.key=e;r.value=e;n=r.next;r.next=r.prev=t}t.next=t.prev=t},keys:function keys(){o(this,\"keys\");return new i(this,\"key\")},values:function values(){o(this,\"values\");return new i(this,\"value\")},entries:function entries(){o(this,\"entries\");return new i(this,\"key+value\")},forEach:function forEach(e){o(this,\"forEach\");var r=arguments.length>1?arguments[1]:null;var n=this.entries();for(var i=n.next();!i.done;i=n.next()){if(r){t(e,r,i.value[1],i.value[0],this)}else{e(i.value[1],i.value[0],this)}}}});Me(a,a.entries);return u}(),Set:function(){var e=function isSet(e){return e._es6set&&typeof e._storage!==\"undefined\"};var r=function requireSetSlot(t,r){if(!ce.TypeIsObject(t)||!e(t)){throw new TypeError(\"Set.prototype.\"+r+\" called on incompatible receiver \"+ce.ToString(t))}};var o;var i=function Set(){if(!(this instanceof Set)){throw new TypeError('Constructor Set requires \"new\"')}if(this&&this._es6set){throw new TypeError(\"Bad construction\")}var e=Ae(this,Set,o,{_es6set:true,\"[[SetData]]\":null,_storage:Qr()});if(!e._es6set){throw new TypeError(\"bad set\")}if(arguments.length>0){tn(Set,e,arguments[0])}return e};o=i.prototype;var a=function(e){var t=e;if(t===\"^null\"){return null}else if(t===\"^undefined\"){return void 0}else{var r=t.charAt(0);if(r===\"$\"){return C(t,1)}else if(r===\"n\"){return+C(t,1)}else if(r===\"b\"){return t===\"btrue\"}}return+t};var u=function ensureMap(e){if(!e[\"[[SetData]]\"]){var t=new rn.Map;e[\"[[SetData]]\"]=t;l(n(e._storage),function(e){var r=a(e);t.set(r,r)});e[\"[[SetData]]\"]=t}e._storage=null};m.getter(i.prototype,\"size\",function(){r(this,\"size\");if(this._storage){return n(this._storage).length}u(this);return this[\"[[SetData]]\"].size});b(i.prototype,{has:function has(e){r(this,\"has\");var t;if(this._storage&&(t=Yr(e))!==null){return!!this._storage[t]}u(this);return this[\"[[SetData]]\"].has(e)},add:function add(e){r(this,\"add\");var t;if(this._storage&&(t=Yr(e))!==null){this._storage[t]=true;return this}u(this);this[\"[[SetData]]\"].set(e,e);return this},\"delete\":function(e){r(this,\"delete\");var t;if(this._storage&&(t=Yr(e))!==null){var n=z(this._storage,t);return delete this._storage[t]&&n}u(this);return this[\"[[SetData]]\"][\"delete\"](e)},clear:function clear(){r(this,\"clear\");if(this._storage){this._storage=Qr()}if(this[\"[[SetData]]\"]){this[\"[[SetData]]\"].clear()}},values:function values(){r(this,\"values\");u(this);return new f(this[\"[[SetData]]\"].values())},entries:function entries(){r(this,\"entries\");u(this);return new f(this[\"[[SetData]]\"].entries())},forEach:function forEach(e){r(this,\"forEach\");var n=arguments.length>1?arguments[1]:null;var o=this;u(o);this[\"[[SetData]]\"].forEach(function(r,i){if(n){t(e,n,i,i,o)}else{e(i,i,o)}})}});h(i.prototype,\"keys\",i.prototype.values,true);Me(i.prototype,i.prototype.values);var f=function SetIterator(e){this.it=e};f.prototype={isSetIterator:true,next:function next(){if(!this.isSetIterator){throw new TypeError(\"Not a SetIterator\")}return this.it.next()}};Me(f.prototype);return i}()};var nn=S.Set&&!Set.prototype[\"delete\"]&&Set.prototype.remove&&Set.prototype.items&&Set.prototype.map&&Array.isArray((new Set).keys);if(nn){S.Set=rn.Set}if(S.Map||S.Set){var on=a(function(){return new Map([[1,2]]).get(1)===2});if(!on){S.Map=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}var e=new G;if(arguments.length>0){en(Map,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,S.Map.prototype);return e};S.Map.prototype=O(G.prototype);h(S.Map.prototype,\"constructor\",S.Map,true);m.preserveToString(S.Map,G)}var an=new Map;var un=function(){var e=new Map([[1,0],[2,0],[3,0],[4,0]]);e.set(-0,e);return e.get(0)===e&&e.get(-0)===e&&e.has(0)&&e.has(-0)}();var fn=an.set(1,2)===an;if(!un||!fn){ne(Map.prototype,\"set\",function set(e,r){t(U,this,e===0?0:e,r);return this})}if(!un){b(Map.prototype,{get:function get(e){return t(V,this,e===0?0:e)},has:function has(e){return t(B,this,e===0?0:e)}},true);m.preserveToString(Map.prototype.get,V);m.preserveToString(Map.prototype.has,B)}var sn=new Set;var cn=Set.prototype[\"delete\"]&&Set.prototype.add&&Set.prototype.has&&function(e){e[\"delete\"](0);e.add(-0);return!e.has(0)}(sn);var ln=sn.add(1)===sn;if(!cn||!ln){var pn=Set.prototype.add;Set.prototype.add=function add(e){t(pn,this,e===0?0:e);return this};m.preserveToString(Set.prototype.add,pn)}if(!cn){var vn=Set.prototype.has;Set.prototype.has=function has(e){return t(vn,this,e===0?0:e)};m.preserveToString(Set.prototype.has,vn);var yn=Set.prototype[\"delete\"];Set.prototype[\"delete\"]=function SetDelete(e){return t(yn,this,e===0?0:e)};m.preserveToString(Set.prototype[\"delete\"],yn)}var hn=w(S.Map,function(e){var t=new e([]);t.set(42,42);return t instanceof e});var bn=Object.setPrototypeOf&&!hn;var gn=function(){try{return!(S.Map()instanceof S.Map)}catch(e){return e instanceof TypeError}}();if(S.Map.length!==0||bn||!gn){S.Map=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}var e=new G;if(arguments.length>0){en(Map,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,Map.prototype);return e};S.Map.prototype=G.prototype;h(S.Map.prototype,\"constructor\",S.Map,true);m.preserveToString(S.Map,G)}var dn=w(S.Set,function(e){var t=new e([]);t.add(42,42);return t instanceof e});var mn=Object.setPrototypeOf&&!dn;var On=function(){try{return!(S.Set()instanceof S.Set)}catch(e){return e instanceof TypeError}}();if(S.Set.length!==0||mn||!On){var wn=S.Set;S.Set=function Set(){if(!(this instanceof Set)){throw new TypeError('Constructor Set requires \"new\"')}var e=new wn;if(arguments.length>0){tn(Set,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,Set.prototype);return e};S.Set.prototype=wn.prototype;h(S.Set.prototype,\"constructor\",S.Set,true);m.preserveToString(S.Set,wn)}var jn=new S.Map;var Sn=!a(function(){return jn.keys().next().done});if(typeof S.Map.prototype.clear!==\"function\"||(new S.Set).size!==0||jn.size!==0||typeof S.Map.prototype.keys!==\"function\"||typeof S.Set.prototype.keys!==\"function\"||typeof S.Map.prototype.forEach!==\"function\"||typeof S.Set.prototype.forEach!==\"function\"||u(S.Map)||u(S.Set)||typeof jn.keys().next!==\"function\"||Sn||!hn){b(S,{Map:rn.Map,Set:rn.Set},true)}if(S.Set.prototype.keys!==S.Set.prototype.values){h(S.Set.prototype,\"keys\",S.Set.prototype.values,true)}Me(Object.getPrototypeOf((new S.Map).keys()));Me(Object.getPrototypeOf((new S.Set).keys()));if(c&&S.Set.prototype.has.name!==\"has\"){var Tn=S.Set.prototype.has;ne(S.Set.prototype,\"has\",function has(e){return t(Tn,this,e)})}}b(S,rn);Ce(S.Map);Ce(S.Set)}var In=function throwUnlessTargetIsObject(e){if(!ce.TypeIsObject(e)){throw new TypeError(\"target must be an object\")}};var En={apply:function apply(){return ce.Call(ce.Call,null,arguments)},construct:function construct(e,t){if(!ce.IsConstructor(e)){throw new TypeError(\"First argument must be a constructor.\")}var r=arguments.length>2?arguments[2]:e;if(!ce.IsConstructor(r)){throw new TypeError(\"new.target must be a constructor.\")}return ce.Construct(e,t,r,\"internal\")},deleteProperty:function deleteProperty(e,t){In(e);if(s){var r=Object.getOwnPropertyDescriptor(e,t);if(r&&!r.configurable){return false}}return delete e[t]},has:function has(e,t){In(e);return t in e}};if(Object.getOwnPropertyNames){Object.assign(En,{ownKeys:function ownKeys(e){In(e);var t=Object.getOwnPropertyNames(e);if(ce.IsCallable(Object.getOwnPropertySymbols)){x(t,Object.getOwnPropertySymbols(e))}return t}})}var Pn=function ConvertExceptionToBoolean(e){return!i(e)};if(Object.preventExtensions){Object.assign(En,{isExtensible:function isExtensible(e){In(e);return Object.isExtensible(e)},preventExtensions:function preventExtensions(e){In(e);return Pn(function(){return Object.preventExtensions(e)})}})}if(s){var Cn=function get(e,t,r){var n=Object.getOwnPropertyDescriptor(e,t);if(!n){var o=Object.getPrototypeOf(e);if(o===null){return void 0}return Cn(o,t,r)}if(\"value\"in n){return n.value}if(n.get){return ce.Call(n.get,r)}return void 0};var Mn=function set(e,r,n,o){var i=Object.getOwnPropertyDescriptor(e,r);if(!i){var a=Object.getPrototypeOf(e);if(a!==null){return Mn(a,r,n,o)}i={value:void 0,writable:true,enumerable:true,configurable:true}}if(\"value\"in i){if(!i.writable){return false}if(!ce.TypeIsObject(o)){return false}var u=Object.getOwnPropertyDescriptor(o,r);if(u){return ae.defineProperty(o,r,{value:n})}else{return ae.defineProperty(o,r,{value:n,writable:true,enumerable:true,configurable:true})}}if(i.set){t(i.set,o,n);return true}return false};Object.assign(En,{defineProperty:function defineProperty(e,t,r){In(e);return Pn(function(){return Object.defineProperty(e,t,r)})},getOwnPropertyDescriptor:function getOwnPropertyDescriptor(e,t){In(e);return Object.getOwnPropertyDescriptor(e,t)},get:function get(e,t){In(e);var r=arguments.length>2?arguments[2]:e;return Cn(e,t,r)},set:function set(e,t,r){In(e);var n=arguments.length>3?arguments[3]:e;return Mn(e,t,r,n)}})}if(Object.getPrototypeOf){var xn=Object.getPrototypeOf;En.getPrototypeOf=function getPrototypeOf(e){In(e);return xn(e)}}if(Object.setPrototypeOf&&En.getPrototypeOf){var Nn=function(e,t){var r=t;while(r){if(e===r){return true}r=En.getPrototypeOf(r)}return false};Object.assign(En,{setPrototypeOf:function setPrototypeOf(e,t){In(e);if(t!==null&&!ce.TypeIsObject(t)){throw new TypeError(\"proto must be an object or null\")}if(t===ae.getPrototypeOf(e)){return true}if(ae.isExtensible&&!ae.isExtensible(e)){return false}if(Nn(e,t)){return false}Object.setPrototypeOf(e,t);return true}})}var An=function(e,t){if(!ce.IsCallable(S.Reflect[e])){h(S.Reflect,e,t)}else{var r=a(function(){S.Reflect[e](1);S.Reflect[e](NaN);S.Reflect[e](true);return true});if(r){ne(S.Reflect,e,t)}}};Object.keys(En).forEach(function(e){An(e,En[e])});var Rn=S.Reflect.getPrototypeOf;if(c&&Rn&&Rn.name!==\"getPrototypeOf\"){ne(S.Reflect,\"getPrototypeOf\",function getPrototypeOf(e){return t(Rn,S.Reflect,e)})}if(S.Reflect.setPrototypeOf){if(a(function(){S.Reflect.setPrototypeOf(1,{});return true})){ne(S.Reflect,\"setPrototypeOf\",En.setPrototypeOf)}}if(S.Reflect.defineProperty){if(!a(function(){var e=!S.Reflect.defineProperty(1,\"test\",{value:1});var t=typeof Object.preventExtensions!==\"function\"||!S.Reflect.defineProperty(Object.preventExtensions({}),\"test\",{});return e&&t})){ne(S.Reflect,\"defineProperty\",En.defineProperty)}}if(S.Reflect.construct){if(!a(function(){var e=function F(){};return S.Reflect.construct(function(){},[],e)instanceof e})){ne(S.Reflect,\"construct\",En.construct)}}if(String(new Date(NaN))!==\"Invalid Date\"){var _n=Date.prototype.toString;var kn=function toString(){var e=+this;if(e!==e){return\"Invalid Date\"}return ce.Call(_n,this)};ne(Date.prototype,\"toString\",kn)}var Ln={anchor:function anchor(e){return ce.CreateHTML(this,\"a\",\"name\",e)},big:function big(){return ce.CreateHTML(this,\"big\",\"\",\"\")},blink:function blink(){return ce.CreateHTML(this,\"blink\",\"\",\"\")},bold:function bold(){return ce.CreateHTML(this,\"b\",\"\",\"\")},fixed:function fixed(){return ce.CreateHTML(this,\"tt\",\"\",\"\")},fontcolor:function fontcolor(e){return ce.CreateHTML(this,\"font\",\"color\",e)},fontsize:function fontsize(e){return ce.CreateHTML(this,\"font\",\"size\",e)},italics:function italics(){return ce.CreateHTML(this,\"i\",\"\",\"\")},link:function link(e){return ce.CreateHTML(this,\"a\",\"href\",e)},small:function small(){return ce.CreateHTML(this,\"small\",\"\",\"\")},strike:function strike(){return ce.CreateHTML(this,\"strike\",\"\",\"\")},sub:function sub(){return ce.CreateHTML(this,\"sub\",\"\",\"\")},sup:function sub(){return ce.CreateHTML(this,\"sup\",\"\",\"\")}};l(Object.keys(Ln),function(e){var r=String.prototype[e];var n=false;if(ce.IsCallable(r)){var o=t(r,\"\",' \" ');var i=P([],o.match(/\"/g)).length;n=o!==o.toLowerCase()||i>2}else{n=true}if(n){ne(String.prototype,e,Ln[e])}});var Fn=function(){if(!oe){return false}var e=typeof JSON===\"object\"&&typeof JSON.stringify===\"function\"?JSON.stringify:null;if(!e){return false}if(typeof e($())!==\"undefined\"){return true}if(e([$()])!==\"[null]\"){return true}var t={a:$()};t[$()]=true;if(e(t)!==\"{}\"){return true}return false}();var Dn=a(function(){if(!oe){return true}return JSON.stringify(Object($()))===\"{}\"&&JSON.stringify([Object($())])===\"[{}]\"});if(Fn||!Dn){var zn=JSON.stringify;ne(JSON,\"stringify\",function stringify(e){if(typeof e===\"symbol\"){return}var n;if(arguments.length>1){n=arguments[1]}var o=[e];if(!r(n)){var i=ce.IsCallable(n)?n:null;var a=function(e,r){var n=i?t(i,this,e,r):r;if(typeof n!==\"symbol\"){if(re.symbol(n)){return Nt({})(n)}else{return n}}};o.push(a)}else{o.push(n)}if(arguments.length>2){o.push(arguments[2])}return zn.apply(this,o)})}return S});\n//# sourceMappingURL=es6-shim.map\n/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */\n!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return t(e)}:t(e)}(\"undefined\"!=typeof window?window:this,function(C,e){\"use strict\";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return\"function\"==typeof e&&\"number\"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement(\"script\");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?n[o.call(e)]||\"object\":typeof e}var f=\"3.4.1\",k=function(e,t){return new k.fn.init(e,t)},p=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;function d(e){var t=!!e&&\"length\"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&0<t&&t-1 in e)}k.fn=k.prototype={jquery:f,constructor:k,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=k.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return k.each(this,e)},map:function(n){return this.pushStack(k.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},k.extend=k.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for(\"boolean\"==typeof a&&(l=a,a=arguments[s]||{},s++),\"object\"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],\"__proto__\"!==t&&a!==r&&(l&&r&&(k.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||k.isPlainObject(n)?n:{},i=!1,a[t]=k.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},k.extend({expando:\"jQuery\"+(f+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||\"[object Object]\"!==o.call(e))&&(!(t=r(e))||\"function\"==typeof(n=v.call(t,\"constructor\")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t){b(e,{nonce:t&&t.nonce})},each:function(e,t){var n,r=0;if(d(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?\"\":(e+\"\").replace(p,\"\")},makeArray:function(e,t){var n=t||[];return null!=e&&(d(Object(e))?k.merge(n,\"string\"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(d(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g.apply([],a)},guid:1,support:y}),\"function\"==typeof Symbol&&(k.fn[Symbol.iterator]=t[Symbol.iterator]),k.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){n[\"[object \"+t+\"]\"]=t.toLowerCase()});var h=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,k=\"sizzle\"+1*new Date,m=n.document,S=0,r=0,p=ue(),x=ue(),N=ue(),A=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",M=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",I=\"(?:\\\\\\\\.|[\\\\w-]|[^\\0-\\\\xa0])+\",W=\"\\\\[\"+M+\"*(\"+I+\")(?:\"+M+\"*([*^$|!~]?=)\"+M+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+I+\"))|)\"+M+\"*\\\\]\",$=\":(\"+I+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+W+\")*)|.*)\\\\)|)\",F=new RegExp(M+\"+\",\"g\"),B=new RegExp(\"^\"+M+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+M+\"+$\",\"g\"),_=new RegExp(\"^\"+M+\"*,\"+M+\"*\"),z=new RegExp(\"^\"+M+\"*([>+~]|\"+M+\")\"+M+\"*\"),U=new RegExp(M+\"|>\"),X=new RegExp($),V=new RegExp(\"^\"+I+\"$\"),G={ID:new RegExp(\"^#(\"+I+\")\"),CLASS:new RegExp(\"^\\\\.(\"+I+\")\"),TAG:new RegExp(\"^(\"+I+\"|[*])\"),ATTR:new RegExp(\"^\"+W),PSEUDO:new RegExp(\"^\"+$),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+M+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+M+\"*(?:([+-]|)\"+M+\"*(\\\\d+)|))\"+M+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+R+\")$\",\"i\"),needsContext:new RegExp(\"^\"+M+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+M+\"*((?:-\\\\d)?\\\\d*)\"+M+\"*\\\\)|)(?=[^-]|$)\",\"i\")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\\d$/i,K=/^[^{]+\\{\\s*\\[native \\w/,Z=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,ee=/[+~]/,te=new RegExp(\"\\\\\\\\([\\\\da-f]{1,6}\"+M+\"?|(\"+M+\")|.)\",\"ig\"),ne=function(e,t,n){var r=\"0x\"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,ie=function(e,t){return t?\"\\0\"===e?\"\\ufffd\":e.slice(0,-1)+\"\\\\\"+e.charCodeAt(e.length-1).toString(16)+\" \":\"\\\\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&\"fieldset\"===e.nodeName.toLowerCase()},{dir:\"parentNode\",next:\"legend\"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],\"string\"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+\" \"]&&(!v||!v.test(t))&&(1!==p||\"object\"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute(\"id\"))?s=s.replace(re,ie):e.setAttribute(\"id\",s=k),o=(l=h(t)).length;while(o--)l[o]=\"#\"+s+\" \"+xe(l[o]);c=l.join(\",\"),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute(\"id\")}}}return g(t.replace(B,\"$1\"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+\" \")>b.cacheLength&&delete e[r.shift()],e[t+\" \"]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement(\"fieldset\");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split(\"|\"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return\"input\"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return(\"input\"===t||\"button\"===t)&&e.type===n}}function ge(t){return function(e){return\"form\"in e?e.parentNode&&!1===e.disabled?\"label\"in e?\"label\"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:\"label\"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&\"undefined\"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||\"HTML\")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener(\"unload\",oe,!1):n.attachEvent&&n.attachEvent(\"onunload\",oe)),d.attributes=ce(function(e){return e.className=\"i\",!e.getAttribute(\"className\")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment(\"\")),!e.getElementsByTagName(\"*\").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute(\"id\")===t}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t=\"undefined\"!=typeof e.getAttributeNode&&e.getAttributeNode(\"id\");return t&&t.value===n}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return\"undefined\"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if(\"*\"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if(\"undefined\"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML=\"<a id='\"+k+\"'></a><select id='\"+k+\"-\\r\\\\' msallowcapture=''><option selected=''></option></select>\",e.querySelectorAll(\"[msallowcapture^='']\").length&&v.push(\"[*^$]=\"+M+\"*(?:''|\\\"\\\")\"),e.querySelectorAll(\"[selected]\").length||v.push(\"\\\\[\"+M+\"*(?:value|\"+R+\")\"),e.querySelectorAll(\"[id~=\"+k+\"-]\").length||v.push(\"~=\"),e.querySelectorAll(\":checked\").length||v.push(\":checked\"),e.querySelectorAll(\"a#\"+k+\"+*\").length||v.push(\".#.+[+~]\")}),ce(function(e){e.innerHTML=\"<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>\";var t=C.createElement(\"input\");t.setAttribute(\"type\",\"hidden\"),e.appendChild(t).setAttribute(\"name\",\"D\"),e.querySelectorAll(\"[name=d]\").length&&v.push(\"name\"+M+\"*[*^$|!~]?=\"),2!==e.querySelectorAll(\":enabled\").length&&v.push(\":enabled\",\":disabled\"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(\":disabled\").length&&v.push(\":enabled\",\":disabled\"),e.querySelectorAll(\"*,:x\"),v.push(\",.*:\")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,\"*\"),c.call(e,\"[s!='']:x\"),s.push(\"!=\",$)}),v=v.length&&new RegExp(v.join(\"|\")),s=s.length&&new RegExp(s.join(\"|\")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+\" \"]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!==C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!==C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+\"\").replace(re,ie)},se.error=function(e){throw new Error(\"Syntax error, unrecognized expression: \"+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n=\"\",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if(\"string\"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||\"\").replace(te,ne),\"~=\"===e[2]&&(e[3]=\" \"+e[3]+\" \"),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),\"nth\"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*(\"even\"===e[3]||\"odd\"===e[3])),e[5]=+(e[7]+e[8]||\"odd\"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||\"\":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(\")\",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return\"*\"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+\" \"];return t||(t=new RegExp(\"(^|\"+M+\")\"+e+\"(\"+M+\"|$)\"))&&p(e,function(e){return t.test(\"string\"==typeof e.className&&e.className||\"undefined\"!=typeof e.getAttribute&&e.getAttribute(\"class\")||\"\")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?\"!=\"===r:!r||(t+=\"\",\"=\"===r?t===i:\"!=\"===r?t!==i:\"^=\"===r?i&&0===t.indexOf(i):\"*=\"===r?i&&-1<t.indexOf(i):\"$=\"===r?i&&t.slice(-i.length)===i:\"~=\"===r?-1<(\" \"+t.replace(F,\" \")+\" \").indexOf(i):\"|=\"===r&&(t===i||t.slice(0,i.length+1)===i+\"-\"))}},CHILD:function(h,e,t,g,v){var y=\"nth\"!==h.slice(0,3),m=\"last\"!==h.slice(-4),x=\"of-type\"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?\"nextSibling\":\"previousSibling\",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l=\"only\"===h&&!u&&\"nextSibling\"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[S,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[S,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error(\"unsupported pseudo: \"+e);return a[k]?a(o):1<a.length?(t=[e,e,\"\",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace(B,\"$1\"));return s[k]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||\"\")||se.error(\"unsupported lang: \"+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute(\"xml:lang\")||e.getAttribute(\"lang\"))return(t=t.toLowerCase())===n||0===t.indexOf(n+\"-\")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&!!e.checked||\"option\"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&\"button\"===e.type||\"button\"===t},text:function(e){var t;return\"input\"===e.nodeName.toLowerCase()&&\"text\"===e.type&&(null==(t=e.getAttribute(\"type\"))||\"text\"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r=\"\";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&\"parentNode\"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[S,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[k]||(e[k]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===S&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[k]&&(v=Ce(v)),y&&!y[k]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||\"*\",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[\" \"],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[k]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:\" \"===e[s-2].type?\"*\":\"\"})).replace(B,\"$1\"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+\" \"];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace(B,\" \")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=N[e+\" \"];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[k]?i.push(a):o.push(a);(a=N(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l=\"0\",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG(\"*\",i),h=S+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t===C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument===C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(S=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(S=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l=\"function\"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&\"ID\"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=k.split(\"\").sort(D).join(\"\")===k,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement(\"fieldset\"))}),ce(function(e){return e.innerHTML=\"<a href='#'></a>\",\"#\"===e.firstChild.getAttribute(\"href\")})||fe(\"type|href|height|width\",function(e,t,n){if(!n)return e.getAttribute(t,\"type\"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML=\"<input/>\",e.firstChild.setAttribute(\"value\",\"\"),\"\"===e.firstChild.getAttribute(\"value\")})||fe(\"value\",function(e,t,n){if(!n&&\"input\"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute(\"disabled\")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);k.find=h,k.expr=h.selectors,k.expr[\":\"]=k.expr.pseudos,k.uniqueSort=k.unique=h.uniqueSort,k.text=h.getText,k.isXMLDoc=h.isXML,k.contains=h.contains,k.escapeSelector=h.escape;var T=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&k(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},N=k.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var D=/^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):\"string\"!=typeof n?k.grep(e,function(e){return-1<i.call(n,e)!==r}):k.filter(n,e,r)}k.filter=function(e,t,n){var r=t[0];return n&&(e=\":not(\"+e+\")\"),1===t.length&&1===r.nodeType?k.find.matchesSelector(r,e)?[r]:[]:k.find.matches(e,k.grep(t,function(e){return 1===e.nodeType}))},k.fn.extend({find:function(e){var t,n,r=this.length,i=this;if(\"string\"!=typeof e)return this.pushStack(k(e).filter(function(){for(t=0;t<r;t++)if(k.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)k.find(e,i[t],n);return 1<r?k.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,\"string\"==typeof e&&N.test(e)?k(e):e||[],!1).length}});var q,L=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,\"string\"==typeof e){if(!(r=\"<\"===e[0]&&\">\"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(k.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a=\"string\"!=typeof e&&k(e);if(!N.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&k.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?k.uniqueSort(o):o)},index:function(e){return e?\"string\"==typeof e?i.call(k(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(k.uniqueSort(k.merge(this.get(),k(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),k.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return T(e,\"parentNode\")},parentsUntil:function(e,t,n){return T(e,\"parentNode\",n)},next:function(e){return P(e,\"nextSibling\")},prev:function(e){return P(e,\"previousSibling\")},nextAll:function(e){return T(e,\"nextSibling\")},prevAll:function(e){return T(e,\"previousSibling\")},nextUntil:function(e,t,n){return T(e,\"nextSibling\",n)},prevUntil:function(e,t,n){return T(e,\"previousSibling\",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return\"undefined\"!=typeof e.contentDocument?e.contentDocument:(A(e,\"template\")&&(e=e.content||e),k.merge([],e.childNodes))}},function(r,i){k.fn[r]=function(e,t){var n=k.map(this,i,e);return\"Until\"!==r.slice(-5)&&(t=e),t&&\"string\"==typeof t&&(n=k.filter(t,n)),1<this.length&&(O[r]||k.uniqueSort(n),H.test(r)&&n.reverse()),this.pushStack(n)}});var R=/[^\\x20\\t\\r\\n\\f]+/g;function M(e){return e}function I(e){throw e}function W(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}k.Callbacks=function(r){var e,n;r=\"string\"==typeof r?(e=r,n={},k.each(e.match(R)||[],function(e,t){n[t]=!0}),n):k.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:\"\")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){k.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&\"string\"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return k.each(arguments,function(e,t){var n;while(-1<(n=k.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<k.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t=\"\",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=\"\"),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},k.extend({Deferred:function(e){var o=[[\"notify\",\"progress\",k.Callbacks(\"memory\"),k.Callbacks(\"memory\"),2],[\"resolve\",\"done\",k.Callbacks(\"once memory\"),k.Callbacks(\"once memory\"),0,\"resolved\"],[\"reject\",\"fail\",k.Callbacks(\"once memory\"),k.Callbacks(\"once memory\"),1,\"rejected\"]],i=\"pending\",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},\"catch\":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return k.Deferred(function(r){k.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+\"With\"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError(\"Thenable self-resolution\");t=e&&(\"object\"==typeof e||\"function\"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,M,s),l(u,o,I,s)):(u++,t.call(e,l(u,o,M,s),l(u,o,I,s),l(u,o,M,o.notifyWith))):(a!==M&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){k.Deferred.exceptionHook&&k.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==I&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(k.Deferred.getStackHook&&(t.stackTrace=k.Deferred.getStackHook()),C.setTimeout(t))}}return k.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:M,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:M)),o[2][3].add(l(0,e,m(n)?n:I))}).promise()},promise:function(e){return null!=e?k.extend(e,a):a}},s={};return k.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+\"With\"](this===s?void 0:this,arguments),this},s[t[0]+\"With\"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=k.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(W(e,o.done(a(t)).resolve,o.reject,!n),\"pending\"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)W(i[t],a(t),o.reject);return o.promise()}});var $=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;k.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&$.test(e.name)&&C.console.warn(\"jQuery.Deferred exception: \"+e.message,e.stack,t)},k.readyException=function(e){C.setTimeout(function(){throw e})};var F=k.Deferred();function B(){E.removeEventListener(\"DOMContentLoaded\",B),C.removeEventListener(\"load\",B),k.ready()}k.fn.ready=function(e){return F.then(e)[\"catch\"](function(e){k.readyException(e)}),this},k.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--k.readyWait:k.isReady)||(k.isReady=!0)!==e&&0<--k.readyWait||F.resolveWith(E,[k])}}),k.ready.then=F.then,\"complete\"===E.readyState||\"loading\"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(k.ready):(E.addEventListener(\"DOMContentLoaded\",B),C.addEventListener(\"load\",B));var _=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if(\"object\"===w(n))for(s in i=!0,n)_(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(k(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},z=/^-ms-/,U=/-([a-z])/g;function X(e,t){return t.toUpperCase()}function V(e){return e.replace(z,\"ms-\").replace(U,X)}var G=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function Y(){this.expando=k.expando+Y.uid++}Y.uid=1,Y.prototype={cache:function(e){var t=e[this.expando];return t||(t={},G(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if(\"string\"==typeof t)i[V(t)]=n;else for(r in t)i[V(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][V(t)]},access:function(e,t,n){return void 0===t||t&&\"string\"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(V):(t=V(t))in r?[t]:t.match(R)||[]).length;while(n--)delete r[t[n]]}(void 0===t||k.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!k.isEmptyObject(t)}};var Q=new Y,J=new Y,K=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,Z=/[A-Z]/g;function ee(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r=\"data-\"+t.replace(Z,\"-$&\").toLowerCase(),\"string\"==typeof(n=e.getAttribute(r))){try{n=\"true\"===(i=n)||\"false\"!==i&&(\"null\"===i?null:i===+i+\"\"?+i:K.test(i)?JSON.parse(i):i)}catch(e){}J.set(e,t,n)}else n=void 0;return n}k.extend({hasData:function(e){return J.hasData(e)||Q.hasData(e)},data:function(e,t,n){return J.access(e,t,n)},removeData:function(e,t){J.remove(e,t)},_data:function(e,t,n){return Q.access(e,t,n)},_removeData:function(e,t){Q.remove(e,t)}}),k.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=J.get(o),1===o.nodeType&&!Q.get(o,\"hasDataAttrs\"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf(\"data-\")&&(r=V(r.slice(5)),ee(o,r,i[r]));Q.set(o,\"hasDataAttrs\",!0)}return i}return\"object\"==typeof n?this.each(function(){J.set(this,n)}):_(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=J.get(o,n))?t:void 0!==(t=ee(o,n))?t:void 0;this.each(function(){J.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){J.remove(this,e)})}}),k.extend({queue:function(e,t,n){var r;if(e)return t=(t||\"fx\")+\"queue\",r=Q.get(e,t),n&&(!r||Array.isArray(n)?r=Q.access(e,t,k.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||\"fx\";var n=k.queue(e,t),r=n.length,i=n.shift(),o=k._queueHooks(e,t);\"inprogress\"===i&&(i=n.shift(),r--),i&&(\"fx\"===t&&n.unshift(\"inprogress\"),delete o.stop,i.call(e,function(){k.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+\"queueHooks\";return Q.get(e,n)||Q.access(e,n,{empty:k.Callbacks(\"once memory\").add(function(){Q.remove(e,[t+\"queue\",n])})})}}),k.fn.extend({queue:function(t,n){var e=2;return\"string\"!=typeof t&&(n=t,t=\"fx\",e--),arguments.length<e?k.queue(this[0],t):void 0===n?this:this.each(function(){var e=k.queue(this,t,n);k._queueHooks(this,t),\"fx\"===t&&\"inprogress\"!==e[0]&&k.dequeue(this,t)})},dequeue:function(e){return this.each(function(){k.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||\"fx\",[])},promise:function(e,t){var n,r=1,i=k.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};\"string\"!=typeof e&&(t=e,e=void 0),e=e||\"fx\";while(a--)(n=Q.get(o[a],e+\"queueHooks\"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var te=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,ne=new RegExp(\"^(?:([+-])=|)(\"+te+\")([a-z%]*)$\",\"i\"),re=[\"Top\",\"Right\",\"Bottom\",\"Left\"],ie=E.documentElement,oe=function(e){return k.contains(e.ownerDocument,e)},ae={composed:!0};ie.getRootNode&&(oe=function(e){return k.contains(e.ownerDocument,e)||e.getRootNode(ae)===e.ownerDocument});var se=function(e,t){return\"none\"===(e=t||e).style.display||\"\"===e.style.display&&oe(e)&&\"none\"===k.css(e,\"display\")},ue=function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];for(o in i=n.apply(e,r||[]),t)e.style[o]=a[o];return i};function le(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return k.css(e,t,\"\")},u=s(),l=n&&n[3]||(k.cssNumber[t]?\"\":\"px\"),c=e.nodeType&&(k.cssNumber[t]||\"px\"!==l&&+u)&&ne.exec(k.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)k.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,k.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ce={};function fe(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?(\"none\"===n&&(l[c]=Q.get(r,\"display\")||null,l[c]||(r.style.display=\"\")),\"\"===r.style.display&&se(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ce[s])||(o=a.body.appendChild(a.createElement(s)),u=k.css(o,\"display\"),o.parentNode.removeChild(o),\"none\"===u&&(u=\"block\"),ce[s]=u)))):\"none\"!==n&&(l[c]=\"none\",Q.set(r,\"display\",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}k.fn.extend({show:function(){return fe(this,!0)},hide:function(){return fe(this)},toggle:function(e){return\"boolean\"==typeof e?e?this.show():this.hide():this.each(function(){se(this)?k(this).show():k(this).hide()})}});var pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i,he=/^$|^module$|\\/(?:java|ecma)script/i,ge={option:[1,\"<select multiple='multiple'>\",\"</select>\"],thead:[1,\"<table>\",\"</table>\"],col:[2,\"<table><colgroup>\",\"</colgroup></table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:[0,\"\",\"\"]};function ve(e,t){var n;return n=\"undefined\"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):\"undefined\"!=typeof e.querySelectorAll?e.querySelectorAll(t||\"*\"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Q.set(e[n],\"globalEval\",!t||Q.get(t[n],\"globalEval\"))}ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;var me,xe,be=/<|&#?\\w+;/;function we(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if(\"object\"===w(o))k.merge(p,o.nodeType?[o]:o);else if(be.test(o)){a=a||f.appendChild(t.createElement(\"div\")),s=(de.exec(o)||[\"\",\"\"])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+k.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;k.merge(p,a.childNodes),(a=f.firstChild).textContent=\"\"}else p.push(t.createTextNode(o));f.textContent=\"\",d=0;while(o=p[d++])if(r&&-1<k.inArray(o,r))i&&i.push(o);else if(l=oe(o),a=ve(f.appendChild(o),\"script\"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||\"\")&&n.push(o)}return f}me=E.createDocumentFragment().appendChild(E.createElement(\"div\")),(xe=E.createElement(\"input\")).setAttribute(\"type\",\"radio\"),xe.setAttribute(\"checked\",\"checked\"),xe.setAttribute(\"name\",\"t\"),me.appendChild(xe),y.checkClone=me.cloneNode(!0).cloneNode(!0).lastChild.checked,me.innerHTML=\"<textarea>x</textarea>\",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==(\"focus\"===t)}function Ae(e,t,n,r,i,o){var a,s;if(\"object\"==typeof t){for(s in\"string\"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&(\"string\"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return\"undefined\"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||\"\").match(R)||[\"\"]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(\".\")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||\"\").match(R)||[\"\"]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&(\"**\"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,\"handle events\")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,\"events\")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t<arguments.length;t++)u[t]=arguments[t];if(s.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,s)){a=k.event.handlers.call(this,s,l),t=0;while((i=a[t++])&&!s.isPropagationStopped()){s.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!s.isImmediatePropagationStopped())s.rnamespace&&!1!==o.namespace&&!s.rnamespace.test(o.namespace)||(s.handleObj=o,s.data=o.data,void 0!==(r=((k.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,u))&&!1===(s.result=r)&&(s.preventDefault(),s.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,s),s.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!(\"click\"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&(\"click\"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+\" \"]&&(a[i]=r.needsContext?-1<k(i,this).index(l):k.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(k.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[k.expando]?e:new k.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,\"input\")&&De(t,\"click\",ke),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,\"input\")&&De(t,\"click\"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,\"input\")&&Q.get(t,\"click\")||A(t,\"a\")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},k.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},k.Event=function(e,t){if(!(this instanceof k.Event))return new k.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?ke:Se,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&k.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[k.expando]=!0},k.Event.prototype={constructor:k.Event,isDefaultPrevented:Se,isPropagationStopped:Se,isImmediatePropagationStopped:Se,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=ke,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=ke,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=ke,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},k.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,\"char\":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&Te.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&Ce.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},k.event.addProp),k.each({focus:\"focusin\",blur:\"focusout\"},function(e,t){k.event.special[e]={setup:function(){return De(this,e,Ne),!1},trigger:function(){return De(this,e),!0},delegateType:t}}),k.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(e,i){k.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||k.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),k.fn.extend({on:function(e,t,n,r){return Ae(this,e,t,n,r)},one:function(e,t,n,r){return Ae(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,k(e.delegateTarget).off(r.namespace?r.origType+\".\"+r.namespace:r.origType,r.selector,r.handler),this;if(\"object\"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&\"function\"!=typeof t||(n=t,t=void 0),!1===n&&(n=Se),this.each(function(){k.event.remove(this,e,n,t)})}});var je=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)[^>]*)\\/>/gi,qe=/<script|<style|<link/i,Le=/checked\\s*(?:[^=]|=\\s*.checked.)/i,He=/^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;function Oe(e,t){return A(e,\"table\")&&A(11!==t.nodeType?t:t.firstChild,\"tr\")&&k(e).children(\"tbody\")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute(\"type\"))+\"/\"+e.type,e}function Re(e){return\"true/\"===(e.type||\"\").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute(\"type\"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n<r;n++)k.event.add(t,i,l[i][n]);J.hasData(e)&&(s=J.access(e),u=k.extend({},s),J.set(t,u))}}function Ie(n,r,i,o){r=g.apply([],r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&\"string\"==typeof d&&!y.checkClone&&Le.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Ie(t,r,i,o)});if(f&&(t=(e=we(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=k.map(ve(e,\"script\"),Pe)).length;c<f;c++)u=e,c!==p&&(u=k.clone(u,!0,!0),s&&k.merge(a,ve(u,\"script\"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,k.map(a,Re),c=0;c<s;c++)u=a[c],he.test(u.type||\"\")&&!Q.access(u,\"globalEval\")&&k.contains(l,u)&&(u.src&&\"module\"!==(u.type||\"\").toLowerCase()?k._evalUrl&&!u.noModule&&k._evalUrl(u.src,{nonce:u.nonce||u.getAttribute(\"nonce\")}):b(u.textContent.replace(He,\"\"),u,l))}return n}function We(e,t,n){for(var r,i=t?k.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||k.cleanData(ve(r)),r.parentNode&&(n&&oe(r)&&ye(ve(r,\"script\")),r.parentNode.removeChild(r));return e}k.extend({htmlPrefilter:function(e){return e.replace(je,\"<$1></$2>\")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,\"input\"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:\"input\"!==l&&\"textarea\"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Me(o[r],a[r]);else Me(e,c);return 0<(a=ve(c,\"script\")).length&&ye(a,!f&&ve(e,\"script\")),c},cleanData:function(e){for(var t,n,r,i=k.event.special,o=0;void 0!==(n=e[o]);o++)if(G(n)){if(t=n[Q.expando]){if(t.events)for(r in t.events)i[r]?k.event.remove(n,r):k.removeEvent(n,r,t.handle);n[Q.expando]=void 0}n[J.expando]&&(n[J.expando]=void 0)}}}),k.fn.extend({detach:function(e){return We(this,e,!0)},remove:function(e){return We(this,e)},text:function(e){return _(this,function(e){return void 0===e?k.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Ie(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Oe(this,e).appendChild(e)})},prepend:function(){return Ie(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Oe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(k.cleanData(ve(e,!1)),e.textContent=\"\");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return k.clone(this,e,t)})},html:function(e){return _(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if(\"string\"==typeof e&&!qe.test(e)&&!ge[(de.exec(e)||[\"\",\"\"])[1].toLowerCase()]){e=k.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(k.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Ie(this,arguments,function(e){var t=this.parentNode;k.inArray(this,n)<0&&(k.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),k.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(e,a){k.fn[e]=function(e){for(var t,n=[],r=k(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),k(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var $e=new RegExp(\"^(\"+te+\")(?!px)[a-z%]+$\",\"i\"),Fe=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},Be=new RegExp(re.join(\"|\"),\"i\");function _e(e,t,n){var r,i,o,a,s=e.style;return(n=n||Fe(e))&&(\"\"!==(a=n.getPropertyValue(t)||n[t])||oe(e)||(a=k.style(e,t)),!y.pixelBoxStyles()&&$e.test(a)&&Be.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+\"\":a}function ze(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(u){s.style.cssText=\"position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0\",u.style.cssText=\"position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%\",ie.appendChild(s).appendChild(u);var e=C.getComputedStyle(u);n=\"1%\"!==e.top,a=12===t(e.marginLeft),u.style.right=\"60%\",o=36===t(e.right),r=36===t(e.width),u.style.position=\"absolute\",i=12===t(u.offsetWidth/3),ie.removeChild(s),u=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s=E.createElement(\"div\"),u=E.createElement(\"div\");u.style&&(u.style.backgroundClip=\"content-box\",u.cloneNode(!0).style.backgroundClip=\"\",y.clearCloneStyle=\"content-box\"===u.style.backgroundClip,k.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),a},scrollboxSize:function(){return e(),i}}))}();var Ue=[\"Webkit\",\"Moz\",\"ms\"],Xe=E.createElement(\"div\").style,Ve={};function Ge(e){var t=k.cssProps[e]||Ve[e];return t||(e in Xe?e:Ve[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Ue.length;while(n--)if((e=Ue[n]+t)in Xe)return e}(e)||e)}var Ye=/^(none|table(?!-c[ea]).+)/,Qe=/^--/,Je={position:\"absolute\",visibility:\"hidden\",display:\"block\"},Ke={letterSpacing:\"0\",fontWeight:\"400\"};function Ze(e,t,n){var r=ne.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||\"px\"):t}function et(e,t,n,r,i,o){var a=\"width\"===t?1:0,s=0,u=0;if(n===(r?\"border\":\"content\"))return 0;for(;a<4;a+=2)\"margin\"===n&&(u+=k.css(e,n+re[a],!0,i)),r?(\"content\"===n&&(u-=k.css(e,\"padding\"+re[a],!0,i)),\"margin\"!==n&&(u-=k.css(e,\"border\"+re[a]+\"Width\",!0,i))):(u+=k.css(e,\"padding\"+re[a],!0,i),\"padding\"!==n?u+=k.css(e,\"border\"+re[a]+\"Width\",!0,i):s+=k.css(e,\"border\"+re[a]+\"Width\",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e[\"offset\"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function tt(e,t,n){var r=Fe(e),i=(!y.boxSizingReliable()||n)&&\"border-box\"===k.css(e,\"boxSizing\",!1,r),o=i,a=_e(e,t,r),s=\"offset\"+t[0].toUpperCase()+t.slice(1);if($e.test(a)){if(!n)return a;a=\"auto\"}return(!y.boxSizingReliable()&&i||\"auto\"===a||!parseFloat(a)&&\"inline\"===k.css(e,\"display\",!1,r))&&e.getClientRects().length&&(i=\"border-box\"===k.css(e,\"boxSizing\",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+et(e,t,n||(i?\"border\":\"content\"),o,r,a)+\"px\"}function nt(e,t,n,r,i){return new nt.prototype.init(e,t,n,r,i)}k.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=_e(e,\"opacity\");return\"\"===n?\"1\":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=V(t),u=Qe.test(t),l=e.style;if(u||(t=Ge(s)),a=k.cssHooks[t]||k.cssHooks[s],void 0===n)return a&&\"get\"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];\"string\"===(o=typeof n)&&(i=ne.exec(n))&&i[1]&&(n=le(e,t,i),o=\"number\"),null!=n&&n==n&&(\"number\"!==o||u||(n+=i&&i[3]||(k.cssNumber[s]?\"\":\"px\")),y.clearCloneStyle||\"\"!==n||0!==t.indexOf(\"background\")||(l[t]=\"inherit\"),a&&\"set\"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=V(t);return Qe.test(t)||(t=Ge(s)),(a=k.cssHooks[t]||k.cssHooks[s])&&\"get\"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=_e(e,t,r)),\"normal\"===i&&t in Ke&&(i=Ke[t]),\"\"===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),k.each([\"height\",\"width\"],function(e,u){k.cssHooks[u]={get:function(e,t,n){if(t)return!Ye.test(k.css(e,\"display\"))||e.getClientRects().length&&e.getBoundingClientRect().width?tt(e,u,n):ue(e,Je,function(){return tt(e,u,n)})},set:function(e,t,n){var r,i=Fe(e),o=!y.scrollboxSize()&&\"absolute\"===i.position,a=(o||n)&&\"border-box\"===k.css(e,\"boxSizing\",!1,i),s=n?et(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e[\"offset\"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-et(e,u,\"border\",!1,i)-.5)),s&&(r=ne.exec(t))&&\"px\"!==(r[3]||\"px\")&&(e.style[u]=t,t=k.css(e,u)),Ze(0,t,s)}}}),k.cssHooks.marginLeft=ze(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(_e(e,\"marginLeft\"))||e.getBoundingClientRect().left-ue(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+\"px\"}),k.each({margin:\"\",padding:\"\",border:\"Width\"},function(i,o){k.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r=\"string\"==typeof e?e.split(\" \"):[e];t<4;t++)n[i+re[t]+o]=r[t]||r[t-2]||r[0];return n}},\"margin\"!==i&&(k.cssHooks[i+o].set=Ze)}),k.fn.extend({css:function(e,t){return _(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Fe(e),i=t.length;a<i;a++)o[t[a]]=k.css(e,t[a],!1,r);return o}return void 0!==n?k.style(e,t,n):k.css(e,t)},e,t,1<arguments.length)}}),((k.Tween=nt).prototype={constructor:nt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||k.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(k.cssNumber[n]?\"\":\"px\")},cur:function(){var e=nt.propHooks[this.prop];return e&&e.get?e.get(this):nt.propHooks._default.get(this)},run:function(e){var t,n=nt.propHooks[this.prop];return this.options.duration?this.pos=t=k.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):nt.propHooks._default.set(this),this}}).init.prototype=nt.prototype,(nt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=k.css(e.elem,e.prop,\"\"))&&\"auto\"!==t?t:0},set:function(e){k.fx.step[e.prop]?k.fx.step[e.prop](e):1!==e.elem.nodeType||!k.cssHooks[e.prop]&&null==e.elem.style[Ge(e.prop)]?e.elem[e.prop]=e.now:k.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=nt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},k.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:\"swing\"},k.fx=nt.prototype.init,k.fx.step={};var rt,it,ot,at,st=/^(?:toggle|show|hide)$/,ut=/queueHooks$/;function lt(){it&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(lt):C.setTimeout(lt,k.fx.interval),k.fx.tick())}function ct(){return C.setTimeout(function(){rt=void 0}),rt=Date.now()}function ft(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i[\"margin\"+(n=re[r])]=i[\"padding\"+n]=e;return t&&(i.opacity=i.width=e),i}function pt(e,t,n){for(var r,i=(dt.tweeners[t]||[]).concat(dt.tweeners[\"*\"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function dt(o,e,t){var n,a,r=0,i=dt.prefilters.length,s=k.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=rt||ct(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:k.extend({},e),opts:k.extend(!0,{specialEasing:{},easing:k.easing._default},t),originalProperties:e,originalOptions:t,startTime:rt||ct(),duration:t.duration,tweens:[],createTween:function(e,t){var n=k.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=V(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=k.cssHooks[r])&&\"expand\"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=dt.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(k._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return k.map(c,pt,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),k.fx.timer(k.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}k.Animation=k.extend(dt,{tweeners:{\"*\":[function(e,t){var n=this.createTween(e,t);return le(n.elem,e,ne.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=[\"*\"]):e=e.match(R);for(var n,r=0,i=e.length;r<i;r++)n=e[r],dt.tweeners[n]=dt.tweeners[n]||[],dt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f=\"width\"in t||\"height\"in t,p=this,d={},h=e.style,g=e.nodeType&&se(e),v=Q.get(e,\"fxshow\");for(r in n.queue||(null==(a=k._queueHooks(e,\"fx\")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,k.queue(e,\"fx\").length||a.empty.fire()})})),t)if(i=t[r],st.test(i)){if(delete t[r],o=o||\"toggle\"===i,i===(g?\"hide\":\"show\")){if(\"show\"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||k.style(e,r)}if((u=!k.isEmptyObject(t))||!k.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Q.get(e,\"display\")),\"none\"===(c=k.css(e,\"display\"))&&(l?c=l:(fe([e],!0),l=e.style.display||l,c=k.css(e,\"display\"),fe([e]))),(\"inline\"===c||\"inline-block\"===c&&null!=l)&&\"none\"===k.css(e,\"float\")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l=\"none\"===c?\"\":c)),h.display=\"inline-block\")),n.overflow&&(h.overflow=\"hidden\",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?\"hidden\"in v&&(g=v.hidden):v=Q.access(e,\"fxshow\",{display:l}),o&&(v.hidden=!g),g&&fe([e],!0),p.done(function(){for(r in g||fe([e]),Q.remove(e,\"fxshow\"),d)k.style(e,r,d[r])})),u=pt(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?dt.prefilters.unshift(e):dt.prefilters.push(e)}}),k.speed=function(e,t,n){var r=e&&\"object\"==typeof e?k.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return k.fx.off?r.duration=0:\"number\"!=typeof r.duration&&(r.duration in k.fx.speeds?r.duration=k.fx.speeds[r.duration]:r.duration=k.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue=\"fx\"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&k.dequeue(this,r.queue)},r},k.fn.extend({fadeTo:function(e,t,n,r){return this.filter(se).css(\"opacity\",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=k.isEmptyObject(t),o=k.speed(e,n,r),a=function(){var e=dt(this,k.extend({},t),o);(i||Q.get(this,\"finish\"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return\"string\"!=typeof i&&(o=e,e=i,i=void 0),e&&!1!==i&&this.queue(i||\"fx\",[]),this.each(function(){var e=!0,t=null!=i&&i+\"queueHooks\",n=k.timers,r=Q.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&ut.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||k.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||\"fx\"),this.each(function(){var e,t=Q.get(this),n=t[a+\"queue\"],r=t[a+\"queueHooks\"],i=k.timers,o=n?n.length:0;for(t.finish=!0,k.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),k.each([\"toggle\",\"show\",\"hide\"],function(e,r){var i=k.fn[r];k.fn[r]=function(e,t,n){return null==e||\"boolean\"==typeof e?i.apply(this,arguments):this.animate(ft(r,!0),e,t,n)}}),k.each({slideDown:ft(\"show\"),slideUp:ft(\"hide\"),slideToggle:ft(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(e,r){k.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),k.timers=[],k.fx.tick=function(){var e,t=0,n=k.timers;for(rt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||k.fx.stop(),rt=void 0},k.fx.timer=function(e){k.timers.push(e),k.fx.start()},k.fx.interval=13,k.fx.start=function(){it||(it=!0,lt())},k.fx.stop=function(){it=null},k.fx.speeds={slow:600,fast:200,_default:400},k.fn.delay=function(r,e){return r=k.fx&&k.fx.speeds[r]||r,e=e||\"fx\",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},ot=E.createElement(\"input\"),at=E.createElement(\"select\").appendChild(E.createElement(\"option\")),ot.type=\"checkbox\",y.checkOn=\"\"!==ot.value,y.optSelected=at.selected,(ot=E.createElement(\"input\")).value=\"t\",ot.type=\"radio\",y.radioValue=\"t\"===ot.value;var ht,gt=k.expr.attrHandle;k.fn.extend({attr:function(e,t){return _(this,k.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){k.removeAttr(this,e)})}}),k.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return\"undefined\"==typeof e.getAttribute?k.prop(e,t,n):(1===o&&k.isXMLDoc(e)||(i=k.attrHooks[t.toLowerCase()]||(k.expr.match.bool.test(t)?ht:void 0)),void 0!==n?null===n?void k.removeAttr(e,t):i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+\"\"),n):i&&\"get\"in i&&null!==(r=i.get(e,t))?r:null==(r=k.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&\"radio\"===t&&A(e,\"input\")){var n=e.value;return e.setAttribute(\"type\",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(R);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),ht={set:function(e,t,n){return!1===t?k.removeAttr(e,n):e.setAttribute(n,n),n}},k.each(k.expr.match.bool.source.match(/\\w+/g),function(e,t){var a=gt[t]||k.find.attr;gt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=gt[o],gt[o]=r,r=null!=a(e,t,n)?o:null,gt[o]=i),r}});var vt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;function mt(e){return(e.match(R)||[]).join(\" \")}function xt(e){return e.getAttribute&&e.getAttribute(\"class\")||\"\"}function bt(e){return Array.isArray(e)?e:\"string\"==typeof e&&e.match(R)||[]}k.fn.extend({prop:function(e,t){return _(this,k.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[k.propFix[e]||e]})}}),k.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&k.isXMLDoc(e)||(t=k.propFix[t]||t,i=k.propHooks[t]),void 0!==n?i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&\"get\"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=k.find.attr(e,\"tabindex\");return t?parseInt(t,10):vt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{\"for\":\"htmlFor\",\"class\":\"className\"}}),y.optSelected||(k.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),k.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){k.propFix[this.toLowerCase()]=this}),k.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).addClass(t.call(this,e,xt(this)))});if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&\" \"+mt(i)+\" \"){a=0;while(o=e[a++])r.indexOf(\" \"+o+\" \")<0&&(r+=o+\" \");i!==(s=mt(r))&&n.setAttribute(\"class\",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).removeClass(t.call(this,e,xt(this)))});if(!arguments.length)return this.attr(\"class\",\"\");if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&\" \"+mt(i)+\" \"){a=0;while(o=e[a++])while(-1<r.indexOf(\" \"+o+\" \"))r=r.replace(\" \"+o+\" \",\" \");i!==(s=mt(r))&&n.setAttribute(\"class\",s)}return this},toggleClass:function(i,t){var o=typeof i,a=\"string\"===o||Array.isArray(i);return\"boolean\"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){k(this).toggleClass(i.call(this,e,xt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=k(this),r=bt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&\"boolean\"!==o||((e=xt(this))&&Q.set(this,\"__className__\",e),this.setAttribute&&this.setAttribute(\"class\",e||!1===i?\"\":Q.get(this,\"__className__\")||\"\"))})},hasClass:function(e){var t,n,r=0;t=\" \"+e+\" \";while(n=this[r++])if(1===n.nodeType&&-1<(\" \"+mt(xt(n))+\" \").indexOf(t))return!0;return!1}});var wt=/\\r/g;k.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,k(this).val()):n)?t=\"\":\"number\"==typeof t?t+=\"\":Array.isArray(t)&&(t=k.map(t,function(e){return null==e?\"\":e+\"\"})),(r=k.valHooks[this.type]||k.valHooks[this.nodeName.toLowerCase()])&&\"set\"in r&&void 0!==r.set(this,t,\"value\")||(this.value=t))})):t?(r=k.valHooks[t.type]||k.valHooks[t.nodeName.toLowerCase()])&&\"get\"in r&&void 0!==(e=r.get(t,\"value\"))?e:\"string\"==typeof(e=t.value)?e.replace(wt,\"\"):null==e?\"\":e:void 0}}),k.extend({valHooks:{option:{get:function(e){var t=k.find.attr(e,\"value\");return null!=t?t:mt(k.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a=\"select-one\"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,\"optgroup\"))){if(t=k(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=k.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<k.inArray(k.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),k.each([\"radio\",\"checkbox\"],function(){k.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<k.inArray(k(e).val(),t)}},y.checkOn||(k.valHooks[this].get=function(e){return null===e.getAttribute(\"value\")?\"on\":e.value})}),y.focusin=\"onfocusin\"in C;var Tt=/^(?:focusinfocus|focusoutblur)$/,Ct=function(e){e.stopPropagation()};k.extend(k.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,\"type\")?e.type:e,h=v.call(e,\"namespace\")?e.namespace.split(\".\"):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!Tt.test(d+k.event.triggered)&&(-1<d.indexOf(\".\")&&(d=(h=d.split(\".\")).shift(),h.sort()),u=d.indexOf(\":\")<0&&\"on\"+d,(e=e[k.expando]?e:new k.Event(d,\"object\"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join(\".\"),e.rnamespace=e.namespace?new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:k.makeArray(t,[e]),c=k.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,Tt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Q.get(o,\"events\")||{})[e.type]&&Q.get(o,\"handle\"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&G(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!G(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),k.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,Ct),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,Ct),k.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=k.extend(new k.Event,n,{type:e,isSimulated:!0});k.event.trigger(r,null,t)}}),k.fn.extend({trigger:function(e,t){return this.each(function(){k.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return k.event.trigger(e,t,n,!0)}}),y.focusin||k.each({focus:\"focusin\",blur:\"focusout\"},function(n,r){var i=function(e){k.event.simulate(r,e.target,k.event.fix(e))};k.event.special[r]={setup:function(){var e=this.ownerDocument||this,t=Q.access(e,r);t||e.addEventListener(n,i,!0),Q.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this,t=Q.access(e,r)-1;t?Q.access(e,r,t):(e.removeEventListener(n,i,!0),Q.remove(e,r))}}});var Et=C.location,kt=Date.now(),St=/\\?/;k.parseXML=function(e){var t;if(!e||\"string\"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,\"text/xml\")}catch(e){t=void 0}return t&&!t.getElementsByTagName(\"parsererror\").length||k.error(\"Invalid XML: \"+e),t};var Nt=/\\[\\]$/,At=/\\r?\\n/g,Dt=/^(?:submit|button|image|reset|file)$/i,jt=/^(?:input|select|textarea|keygen)/i;function qt(n,e,r,i){var t;if(Array.isArray(e))k.each(e,function(e,t){r||Nt.test(n)?i(n,t):qt(n+\"[\"+(\"object\"==typeof t&&null!=t?e:\"\")+\"]\",t,r,i)});else if(r||\"object\"!==w(e))i(n,e);else for(t in e)qt(n+\"[\"+t+\"]\",e[t],r,i)}k.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+\"=\"+encodeURIComponent(null==n?\"\":n)};if(null==e)return\"\";if(Array.isArray(e)||e.jquery&&!k.isPlainObject(e))k.each(e,function(){i(this.name,this.value)});else for(n in e)qt(n,e[n],t,i);return r.join(\"&\")},k.fn.extend({serialize:function(){return k.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=k.prop(this,\"elements\");return e?k.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!k(this).is(\":disabled\")&&jt.test(this.nodeName)&&!Dt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=k(this).val();return null==n?null:Array.isArray(n)?k.map(n,function(e){return{name:t.name,value:e.replace(At,\"\\r\\n\")}}):{name:t.name,value:n.replace(At,\"\\r\\n\")}}).get()}});var Lt=/%20/g,Ht=/#.*$/,Ot=/([?&])_=[^&]*/,Pt=/^(.*?):[ \\t]*([^\\r\\n]*)$/gm,Rt=/^(?:GET|HEAD)$/,Mt=/^\\/\\//,It={},Wt={},$t=\"*/\".concat(\"*\"),Ft=E.createElement(\"a\");function Bt(o){return function(e,t){\"string\"!=typeof e&&(t=e,e=\"*\");var n,r=0,i=e.toLowerCase().match(R)||[];if(m(t))while(n=i[r++])\"+\"===n[0]?(n=n.slice(1)||\"*\",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function _t(t,i,o,a){var s={},u=t===Wt;function l(e){var r;return s[e]=!0,k.each(t[e]||[],function(e,t){var n=t(i,o,a);return\"string\"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s[\"*\"]&&l(\"*\")}function zt(e,t){var n,r,i=k.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&k.extend(!0,e,r),e}Ft.href=Et.href,k.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Et.href,type:\"GET\",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Et.protocol),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":$t,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":JSON.parse,\"text xml\":k.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,k.ajaxSettings),t):zt(k.ajaxSettings,e)},ajaxPrefilter:Bt(It),ajaxTransport:Bt(Wt),ajax:function(e,t){\"object\"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=k.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?k(y):k.event,x=k.Deferred(),b=k.Callbacks(\"once memory\"),w=v.statusCode||{},a={},s={},u=\"canceled\",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Pt.exec(p))n[t[1].toLowerCase()+\" \"]=(n[t[1].toLowerCase()+\" \"]||[]).concat(t[2])}t=n[e.toLowerCase()+\" \"]}return null==t?null:t.join(\", \")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Et.href)+\"\").replace(Mt,Et.protocol+\"//\"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||\"*\").toLowerCase().match(R)||[\"\"],null==v.crossDomain){r=E.createElement(\"a\");try{r.href=v.url,r.href=r.href,v.crossDomain=Ft.protocol+\"//\"+Ft.host!=r.protocol+\"//\"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&\"string\"!=typeof v.data&&(v.data=k.param(v.data,v.traditional)),_t(It,v,t,T),h)return T;for(i in(g=k.event&&v.global)&&0==k.active++&&k.event.trigger(\"ajaxStart\"),v.type=v.type.toUpperCase(),v.hasContent=!Rt.test(v.type),f=v.url.replace(Ht,\"\"),v.hasContent?v.data&&v.processData&&0===(v.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&(v.data=v.data.replace(Lt,\"+\")):(o=v.url.slice(f.length),v.data&&(v.processData||\"string\"==typeof v.data)&&(f+=(St.test(f)?\"&\":\"?\")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Ot,\"$1\"),o=(St.test(f)?\"&\":\"?\")+\"_=\"+kt+++o),v.url=f+o),v.ifModified&&(k.lastModified[f]&&T.setRequestHeader(\"If-Modified-Since\",k.lastModified[f]),k.etag[f]&&T.setRequestHeader(\"If-None-Match\",k.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader(\"Content-Type\",v.contentType),T.setRequestHeader(\"Accept\",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+(\"*\"!==v.dataTypes[0]?\", \"+$t+\"; q=0.01\":\"\"):v.accepts[\"*\"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u=\"abort\",b.add(v.complete),T.done(v.success),T.fail(v.error),c=_t(Wt,v,t,T)){if(T.readyState=1,g&&m.trigger(\"ajaxSend\",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort(\"timeout\")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,\"No Transport\");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||\"\",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while(\"*\"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader(\"Content-Type\"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+\" \"+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if(\"*\"===o)o=u;else if(\"*\"!==u&&u!==o){if(!(a=l[u+\" \"+o]||l[\"* \"+o]))for(i in l)if((s=i.split(\" \"))[1]===o&&(a=l[u+\" \"+s[0]]||l[\"* \"+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e[\"throws\"])t=a(t);else try{t=a(t)}catch(e){return{state:\"parsererror\",error:a?e:\"No conversion from \"+u+\" to \"+o}}}return{state:\"success\",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader(\"Last-Modified\"))&&(k.lastModified[f]=u),(u=T.getResponseHeader(\"etag\"))&&(k.etag[f]=u)),204===e||\"HEAD\"===v.type?l=\"nocontent\":304===e?l=\"notmodified\":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l=\"error\",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+\"\",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?\"ajaxSuccess\":\"ajaxError\",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger(\"ajaxComplete\",[T,v]),--k.active||k.event.trigger(\"ajaxStop\")))}return T},getJSON:function(e,t,n){return k.get(e,t,n,\"json\")},getScript:function(e,t){return k.get(e,void 0,t,\"script\")}}),k.each([\"get\",\"post\"],function(e,i){k[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),k.ajax(k.extend({url:e,type:i,dataType:r,data:t,success:n},k.isPlainObject(e)&&e))}}),k._evalUrl=function(e,t){return k.ajax({url:e,type:\"GET\",dataType:\"script\",cache:!0,async:!1,global:!1,converters:{\"text script\":function(){}},dataFilter:function(e){k.globalEval(e,t)}})},k.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=k(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){k(this).wrapInner(n.call(this,e))}):this.each(function(){var e=k(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){k(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not(\"body\").each(function(){k(this).replaceWith(this.childNodes)}),this}}),k.expr.pseudos.hidden=function(e){return!k.expr.pseudos.visible(e)},k.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},k.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var Ut={0:200,1223:204},Xt=k.ajaxSettings.xhr();y.cors=!!Xt&&\"withCredentials\"in Xt,y.ajax=Xt=!!Xt,k.ajaxTransport(function(i){var o,a;if(y.cors||Xt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e[\"X-Requested-With\"]||(e[\"X-Requested-With\"]=\"XMLHttpRequest\"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,\"abort\"===e?r.abort():\"error\"===e?\"number\"!=typeof r.status?t(0,\"error\"):t(r.status,r.statusText):t(Ut[r.status]||r.status,r.statusText,\"text\"!==(r.responseType||\"text\")||\"string\"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o(\"error\"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o(\"abort\");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),k.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),k.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(e){return k.globalEval(e),e}}}),k.ajaxPrefilter(\"script\",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type=\"GET\")}),k.ajaxTransport(\"script\",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=k(\"<script>\").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on(\"load error\",i=function(e){r.remove(),i=null,e&&t(\"error\"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\\?(?=&|$)|\\?\\?/;k.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var e=Gt.pop()||k.expando+\"_\"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter(\"json jsonp\",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?\"url\":\"string\"==typeof e.data&&0===(e.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&Yt.test(e.data)&&\"data\");if(a||\"jsonp\"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,\"$1\"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?\"&\":\"?\")+e.jsonp+\"=\"+r),e.converters[\"script json\"]=function(){return o||k.error(r+\" was not called\"),o[0]},e.dataTypes[0]=\"json\",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),\"script\"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument(\"\").body).innerHTML=\"<form></form><form></form>\",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return\"string\"!=typeof e?[]:(\"boolean\"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument(\"\")).createElement(\"base\")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(\" \");return-1<s&&(r=mt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&\"object\"==typeof t&&(i=\"POST\"),0<a.length&&k.ajax({url:e,type:i||\"GET\",dataType:\"html\",data:t}).done(function(e){o=arguments,a.html(r?k(\"<div>\").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,\"position\"),c=k(e),f={};\"static\"===l&&(e.style.position=\"relative\"),s=c.offset(),o=k.css(e,\"top\"),u=k.css(e,\"left\"),(\"absolute\"===l||\"fixed\"===l)&&-1<(o+u).indexOf(\"auto\")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),\"using\"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if(\"fixed\"===k.css(r,\"position\"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&\"static\"===k.css(e,\"position\"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,\"borderTopWidth\",!0),i.left+=k.css(e,\"borderLeftWidth\",!0))}return{top:t.top-i.top-k.css(r,\"marginTop\",!0),left:t.left-i.left-k.css(r,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&\"static\"===k.css(e,\"position\"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(t,i){var o=\"pageYOffset\"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each([\"top\",\"left\"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+\"px\":t})}),k.each({Height:\"height\",Width:\"width\"},function(a,s){k.each({padding:\"inner\"+a,content:s,\"\":\"outer\"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||\"boolean\"!=typeof e),i=r||(!0===e||!0===t?\"margin\":\"border\");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf(\"outer\")?e[\"inner\"+a]:e.document.documentElement[\"client\"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body[\"scroll\"+a],r[\"scroll\"+a],e.body[\"offset\"+a],r[\"offset\"+a],r[\"client\"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each(\"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu\".split(\" \"),function(e,n){k.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}}),k.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),k.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)}}),k.proxy=function(e,t){var n,r,i;if(\"string\"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||k.guid++,i},k.holdReady=function(e){e?k.readyWait++:k.ready(!0)},k.isArray=Array.isArray,k.parseJSON=JSON.parse,k.nodeName=A,k.isFunction=m,k.isWindow=x,k.camelCase=V,k.type=w,k.now=Date.now,k.isNumeric=function(e){var t=k.type(e);return(\"number\"===t||\"string\"===t)&&!isNaN(e-parseFloat(e))},\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return k});var Qt=C.jQuery,Jt=C.$;return k.noConflict=function(e){return C.$===k&&(C.$=Jt),e&&C.jQuery===k&&(C.jQuery=Qt),k},e||(C.jQuery=C.$=k),k});\n/*\n * jQuery throttle / debounce - v1.1 - 3/7/2010\n * http://benalman.com/projects/jquery-throttle-debounce-plugin/\n * \n * Copyright (c) 2010 \"Cowboy\" Ben Alman\n * Dual licensed under the MIT and GPL licenses.\n * http://benalman.com/about/license/\n */\n(function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!==\"boolean\"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this);\n/*!\n * imagesLoaded PACKAGED v4.1.0\n * JavaScript is all like \"You images are done yet or what?\"\n * MIT License\n */\n!function(t,e){\"function\"==typeof define&&define.amd?define(\"ev-emitter/ev-emitter\",e):\"object\"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}(this,function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var i=this._events=this._events||{},n=i[t]=i[t]||[];return-1==n.indexOf(e)&&n.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var i=this._onceEvents=this._onceEvents||{},n=i[t]=i[t]||[];return n[e]=!0,this}},e.off=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=i.indexOf(e);return-1!=n&&i.splice(n,1),this}},e.emitEvent=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=0,o=i[n];e=e||[];for(var r=this._onceEvents&&this._onceEvents[t];o;){var s=r&&r[o];s&&(this.off(t,o),delete r[o]),o.apply(this,e),n+=s?0:1,o=i[n]}return this}},t}),function(t,e){\"use strict\";\"function\"==typeof define&&define.amd?define([\"ev-emitter/ev-emitter\"],function(i){return e(t,i)}):\"object\"==typeof module&&module.exports?module.exports=e(t,require(\"ev-emitter\")):t.imagesLoaded=e(t,t.EvEmitter)}(window,function(t,e){function i(t,e){for(var i in e)t[i]=e[i];return t}function n(t){var e=[];if(Array.isArray(t))e=t;else if(\"number\"==typeof t.length)for(var i=0;i<t.length;i++)e.push(t[i]);else e.push(t);return e}function o(t,e,r){return this instanceof o?(\"string\"==typeof t&&(t=document.querySelectorAll(t)),this.elements=n(t),this.options=i({},this.options),\"function\"==typeof e?r=e:i(this.options,e),r&&this.on(\"always\",r),this.getImages(),h&&(this.jqDeferred=new h.Deferred),void setTimeout(function(){this.check()}.bind(this))):new o(t,e,r)}function r(t){this.img=t}function s(t,e){this.url=t,this.element=e,this.img=new Image}var h=t.jQuery,a=t.console;o.prototype=Object.create(e.prototype),o.prototype.options={},o.prototype.getImages=function(){this.images=[],this.elements.forEach(this.addElementImages,this)},o.prototype.addElementImages=function(t){\"IMG\"==t.nodeName&&this.addImage(t),this.options.background===!0&&this.addElementBackgroundImages(t);var e=t.nodeType;if(e&&d[e]){for(var i=t.querySelectorAll(\"img\"),n=0;n<i.length;n++){var o=i[n];this.addImage(o)}if(\"string\"==typeof this.options.background){var r=t.querySelectorAll(this.options.background);for(n=0;n<r.length;n++){var s=r[n];this.addElementBackgroundImages(s)}}}};var d={1:!0,9:!0,11:!0};return o.prototype.addElementBackgroundImages=function(t){var e=getComputedStyle(t);if(e)for(var i=/url\\((['\"])?(.*?)\\1\\)/gi,n=i.exec(e.backgroundImage);null!==n;){var o=n&&n[2];o&&this.addBackground(o,t),n=i.exec(e.backgroundImage)}},o.prototype.addImage=function(t){var e=new r(t);this.images.push(e)},o.prototype.addBackground=function(t,e){var i=new s(t,e);this.images.push(i)},o.prototype.check=function(){function t(t,i,n){setTimeout(function(){e.progress(t,i,n)})}var e=this;return this.progressedCount=0,this.hasAnyBroken=!1,this.images.length?void this.images.forEach(function(e){e.once(\"progress\",t),e.check()}):void this.complete()},o.prototype.progress=function(t,e,i){this.progressedCount++,this.hasAnyBroken=this.hasAnyBroken||!t.isLoaded,this.emitEvent(\"progress\",[this,t,e]),this.jqDeferred&&this.jqDeferred.notify&&this.jqDeferred.notify(this,t),this.progressedCount==this.images.length&&this.complete(),this.options.debug&&a&&a.log(\"progress: \"+i,t,e)},o.prototype.complete=function(){var t=this.hasAnyBroken?\"fail\":\"done\";if(this.isComplete=!0,this.emitEvent(t,[this]),this.emitEvent(\"always\",[this]),this.jqDeferred){var e=this.hasAnyBroken?\"reject\":\"resolve\";this.jqDeferred[e](this)}},r.prototype=Object.create(e.prototype),r.prototype.check=function(){var t=this.getIsImageComplete();return t?void this.confirm(0!==this.img.naturalWidth,\"naturalWidth\"):(this.proxyImage=new Image,this.proxyImage.addEventListener(\"load\",this),this.proxyImage.addEventListener(\"error\",this),this.img.addEventListener(\"load\",this),this.img.addEventListener(\"error\",this),void(this.proxyImage.src=this.img.src))},r.prototype.getIsImageComplete=function(){return this.img.complete&&void 0!==this.img.naturalWidth},r.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent(\"progress\",[this,this.img,e])},r.prototype.handleEvent=function(t){var e=\"on\"+t.type;this[e]&&this[e](t)},r.prototype.onload=function(){this.confirm(!0,\"onload\"),this.unbindEvents()},r.prototype.onerror=function(){this.confirm(!1,\"onerror\"),this.unbindEvents()},r.prototype.unbindEvents=function(){this.proxyImage.removeEventListener(\"load\",this),this.proxyImage.removeEventListener(\"error\",this),this.img.removeEventListener(\"load\",this),this.img.removeEventListener(\"error\",this)},s.prototype=Object.create(r.prototype),s.prototype.check=function(){this.img.addEventListener(\"load\",this),this.img.addEventListener(\"error\",this),this.img.src=this.url;var t=this.getIsImageComplete();t&&(this.confirm(0!==this.img.naturalWidth,\"naturalWidth\"),this.unbindEvents())},s.prototype.unbindEvents=function(){this.img.removeEventListener(\"load\",this),this.img.removeEventListener(\"error\",this)},s.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent(\"progress\",[this,this.element,e])},o.makeJQueryPlugin=function(e){e=e||t.jQuery,e&&(h=e,h.fn.imagesLoaded=function(t,e){var i=new o(this,t,e);return i.jqDeferred.promise(h(this))})},o.makeJQueryPlugin(),o});\n/*! lz-string-1.3.3-min.js | (c) 2013 Pieroxy | Licensed under a WTFPL license */\nvar LZString={_keyStr:\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\",_f:String.fromCharCode,compressToBase64:function(e){if(e==null)return\"\";var t=\"\";var n,r,i,s,o,u,a;var f=0;e=LZString.compress(e);while(f<e.length*2){if(f%2==0){n=e.charCodeAt(f/2)>>8;r=e.charCodeAt(f/2)&255;if(f/2+1<e.length)i=e.charCodeAt(f/2+1)>>8;else i=NaN}else{n=e.charCodeAt((f-1)/2)&255;if((f+1)/2<e.length){r=e.charCodeAt((f+1)/2)>>8;i=e.charCodeAt((f+1)/2)&255}else r=i=NaN}f+=3;s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+LZString._keyStr.charAt(s)+LZString._keyStr.charAt(o)+LZString._keyStr.charAt(u)+LZString._keyStr.charAt(a)}return t},decompressFromBase64:function(e){if(e==null)return\"\";var t=\"\",n=0,r,i,s,o,u,a,f,l,c=0,h=LZString._f;e=e.replace(/[^A-Za-z0-9\\+\\/\\=]/g,\"\");while(c<e.length){u=LZString._keyStr.indexOf(e.charAt(c++));a=LZString._keyStr.indexOf(e.charAt(c++));f=LZString._keyStr.indexOf(e.charAt(c++));l=LZString._keyStr.indexOf(e.charAt(c++));i=u<<2|a>>4;s=(a&15)<<4|f>>2;o=(f&3)<<6|l;if(n%2==0){r=i<<8;if(f!=64){t+=h(r|s)}if(l!=64){r=o<<8}}else{t=t+h(r|i);if(f!=64){r=s<<8}if(l!=64){t+=h(r|o)}}n+=3}return LZString.decompress(t)},compressToUTF16:function(e){if(e==null)return\"\";var t=\"\",n,r,i,s=0,o=LZString._f;e=LZString.compress(e);for(n=0;n<e.length;n++){r=e.charCodeAt(n);switch(s++){case 0:t+=o((r>>1)+32);i=(r&1)<<14;break;case 1:t+=o(i+(r>>2)+32);i=(r&3)<<13;break;case 2:t+=o(i+(r>>3)+32);i=(r&7)<<12;break;case 3:t+=o(i+(r>>4)+32);i=(r&15)<<11;break;case 4:t+=o(i+(r>>5)+32);i=(r&31)<<10;break;case 5:t+=o(i+(r>>6)+32);i=(r&63)<<9;break;case 6:t+=o(i+(r>>7)+32);i=(r&127)<<8;break;case 7:t+=o(i+(r>>8)+32);i=(r&255)<<7;break;case 8:t+=o(i+(r>>9)+32);i=(r&511)<<6;break;case 9:t+=o(i+(r>>10)+32);i=(r&1023)<<5;break;case 10:t+=o(i+(r>>11)+32);i=(r&2047)<<4;break;case 11:t+=o(i+(r>>12)+32);i=(r&4095)<<3;break;case 12:t+=o(i+(r>>13)+32);i=(r&8191)<<2;break;case 13:t+=o(i+(r>>14)+32);i=(r&16383)<<1;break;case 14:t+=o(i+(r>>15)+32,(r&32767)+32);s=0;break}}return t+o(i+32)},decompressFromUTF16:function(e){if(e==null)return\"\";var t=\"\",n,r,i=0,s=0,o=LZString._f;while(s<e.length){r=e.charCodeAt(s)-32;switch(i++){case 0:n=r<<1;break;case 1:t+=o(n|r>>14);n=(r&16383)<<2;break;case 2:t+=o(n|r>>13);n=(r&8191)<<3;break;case 3:t+=o(n|r>>12);n=(r&4095)<<4;break;case 4:t+=o(n|r>>11);n=(r&2047)<<5;break;case 5:t+=o(n|r>>10);n=(r&1023)<<6;break;case 6:t+=o(n|r>>9);n=(r&511)<<7;break;case 7:t+=o(n|r>>8);n=(r&255)<<8;break;case 8:t+=o(n|r>>7);n=(r&127)<<9;break;case 9:t+=o(n|r>>6);n=(r&63)<<10;break;case 10:t+=o(n|r>>5);n=(r&31)<<11;break;case 11:t+=o(n|r>>4);n=(r&15)<<12;break;case 12:t+=o(n|r>>3);n=(r&7)<<13;break;case 13:t+=o(n|r>>2);n=(r&3)<<14;break;case 14:t+=o(n|r>>1);n=(r&1)<<15;break;case 15:t+=o(n|r);i=0;break}s++}return LZString.decompress(t)},compress:function(e){if(e==null)return\"\";var t,n,r={},i={},s=\"\",o=\"\",u=\"\",a=2,f=3,l=2,c=\"\",h=0,p=0,d,v=LZString._f;for(d=0;d<e.length;d+=1){s=e.charAt(d);if(!Object.prototype.hasOwnProperty.call(r,s)){r[s]=f++;i[s]=true}o=u+s;if(Object.prototype.hasOwnProperty.call(r,o)){u=o}else{if(Object.prototype.hasOwnProperty.call(i,u)){if(u.charCodeAt(0)<256){for(t=0;t<l;t++){h=h<<1;if(p==15){p=0;c+=v(h);h=0}else{p++}}n=u.charCodeAt(0);for(t=0;t<8;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}else{n=1;for(t=0;t<l;t++){h=h<<1|n;if(p==15){p=0;c+=v(h);h=0}else{p++}n=0}n=u.charCodeAt(0);for(t=0;t<16;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}delete i[u]}else{n=r[u];for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}r[o]=f++;u=String(s)}}if(u!==\"\"){if(Object.prototype.hasOwnProperty.call(i,u)){if(u.charCodeAt(0)<256){for(t=0;t<l;t++){h=h<<1;if(p==15){p=0;c+=v(h);h=0}else{p++}}n=u.charCodeAt(0);for(t=0;t<8;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}else{n=1;for(t=0;t<l;t++){h=h<<1|n;if(p==15){p=0;c+=v(h);h=0}else{p++}n=0}n=u.charCodeAt(0);for(t=0;t<16;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}delete i[u]}else{n=r[u];for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}}n=2;for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}while(true){h=h<<1;if(p==15){c+=v(h);break}else p++}return c},decompress:function(e){if(e==null)return\"\";if(e==\"\")return null;var t=[],n,r=4,i=4,s=3,o=\"\",u=\"\",a,f,l,c,h,p,d,v=LZString._f,m={string:e,val:e.charCodeAt(0),position:32768,index:1};for(a=0;a<3;a+=1){t[a]=a}l=0;h=Math.pow(2,2);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}switch(n=l){case 0:l=0;h=Math.pow(2,8);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}d=v(l);break;case 1:l=0;h=Math.pow(2,16);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}d=v(l);break;case 2:return\"\"}t[3]=d;f=u=d;while(true){if(m.index>m.string.length){return\"\"}l=0;h=Math.pow(2,s);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}switch(d=l){case 0:l=0;h=Math.pow(2,8);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}t[i++]=v(l);d=i-1;r--;break;case 1:l=0;h=Math.pow(2,16);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}t[i++]=v(l);d=i-1;r--;break;case 2:return u}if(r==0){r=Math.pow(2,s);s++}if(t[d]){o=t[d]}else{if(d===i){o=f+f.charAt(0)}else{return null}}u+=o;t[i++]=f+o.charAt(0);r--;f=o;if(r==0){r=Math.pow(2,s);s++}}}};if(typeof module!==\"undefined\"&&module!=null){module.exports=LZString}\n/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */\nvar saveAs=saveAs||navigator.msSaveBlob&&navigator.msSaveBlob.bind(navigator)||function(e){\"use strict\";var t=e.document,n=function(){return e.URL||e.webkitURL||e},r=e.URL||e.webkitURL||e,i=t.createElementNS(\"http://www.w3.org/1999/xhtml\",\"a\"),s=\"download\"in i,o=function(n){var r=t.createEvent(\"MouseEvents\");r.initMouseEvent(\"click\",true,false,e,0,0,0,0,0,false,false,false,false,0,null);n.dispatchEvent(r)},u=e.webkitRequestFileSystem,a=e.requestFileSystem||u||e.mozRequestFileSystem,f=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},l=\"application/octet-stream\",c=0,h=[],p=function(){var e=h.length;while(e--){var t=h[e];if(typeof t===\"string\"){r.revokeObjectURL(t)}else{t.remove()}}h.length=0},d=function(e,t,n){t=[].concat(t);var r=t.length;while(r--){var i=e[\"on\"+t[r]];if(typeof i===\"function\"){try{i.call(e,n||e)}catch(s){f(s)}}}},v=function(t,r){var f=this,p=t.type,v=false,m,g,y=function(){var e=n().createObjectURL(t);h.push(e);return e},b=function(){d(f,\"writestart progress write writeend\".split(\" \"))},w=function(){if(v||!m){m=y(t)}if(g){g.location.href=m}else{window.open(m,\"_blank\")}f.readyState=f.DONE;b()},E=function(e){return function(){if(f.readyState!==f.DONE){return e.apply(this,arguments)}}},S={create:true,exclusive:false},x;f.readyState=f.INIT;if(!r){r=\"download\"}if(s){m=y(t);i.href=m;i.download=r;o(i);f.readyState=f.DONE;b();return}if(e.chrome&&p&&p!==l){x=t.slice||t.webkitSlice;t=x.call(t,0,t.size,l);v=true}if(u&&r!==\"download\"){r+=\".download\"}if(p===l||u){g=e}if(!a){w();return}c+=t.size;a(e.TEMPORARY,c,E(function(e){e.root.getDirectory(\"saved\",S,E(function(e){var n=function(){e.getFile(r,S,E(function(e){e.createWriter(E(function(n){n.onwriteend=function(t){g.location.href=e.toURL();h.push(e);f.readyState=f.DONE;d(f,\"writeend\",t)};n.onerror=function(){var e=n.error;if(e.code!==e.ABORT_ERR){w()}};\"writestart progress write abort\".split(\" \").forEach(function(e){n[\"on\"+e]=f[\"on\"+e]});n.write(t);f.abort=function(){n.abort();f.readyState=f.DONE};f.readyState=f.WRITING}),w)}),w)};e.getFile(r,{create:false},E(function(e){e.remove();n()}),E(function(e){if(e.code===e.NOT_FOUND_ERR){n()}else{w()}}))}),w)}),w)},m=v.prototype,g=function(e,t){return new v(e,t)};m.abort=function(){var e=this;e.readyState=e.DONE;d(e,\"abort\")};m.readyState=m.INIT=0;m.WRITING=1;m.DONE=2;m.error=m.onwritestart=m.onprogress=m.onwrite=m.onabort=m.onerror=m.onwriteend=null;e.addEventListener(\"unload\",p,false);return g}(self)\n/*! seedrandom.js v2.3.3 | (c) 2013 David Bau, all rights reserved. | Licensed under a BSD-style license */\n!function(a,b,c,d,e,f,g,h,i){function j(a){var b,c=a.length,e=this,f=0,g=e.i=e.j=0,h=e.S=[];for(c||(a=[c++]);d>f;)h[f]=f++;for(f=0;d>f;f++)h[f]=h[g=r&g+a[f%c]+(b=h[f])],h[g]=b;(e.g=function(a){for(var b,c=0,f=e.i,g=e.j,h=e.S;a--;)b=h[f=r&f+1],c=c*d+h[r&(h[f]=h[g=r&g+b])+(h[g]=b)];return e.i=f,e.j=g,c})(d)}function k(a,b){var c,d=[],e=typeof a;if(b&&\"object\"==e)for(c in a)try{d.push(k(a[c],b-1))}catch(f){}return d.length?d:\"string\"==e?a:a+\"\\0\"}function l(a,b){for(var c,d=a+\"\",e=0;e<d.length;)b[r&e]=r&(c^=19*b[r&e])+d.charCodeAt(e++);return n(b)}function m(c){try{return a.crypto.getRandomValues(c=new Uint8Array(d)),n(c)}catch(e){return[+new Date,a,(c=a.navigator)&&c.plugins,a.screen,n(b)]}}function n(a){return String.fromCharCode.apply(0,a)}var o=c.pow(d,e),p=c.pow(2,f),q=2*p,r=d-1,s=c[\"seed\"+i]=function(a,f,g){var h=[],r=l(k(f?[a,n(b)]:null==a?m():a,3),h),s=new j(h);return l(n(s.S),b),(g||function(a,b,d){return d?(c[i]=a,b):a})(function(){for(var a=s.g(e),b=o,c=0;p>a;)a=(a+c)*d,b*=d,c=s.g(1);for(;a>=q;)a/=2,b/=2,c>>>=1;return(a+c)/b},r,this==c)};l(c[i](),b),g&&g.exports?g.exports=s:h&&h.amd&&h(function(){return s})}(this,[],Math,256,6,52,\"object\"==typeof module&&module,\"function\"==typeof define&&define,\"random\");\n/*! console_hack.js | (c) 2015 Thomas Michael Edwards | Licensed under SugarCube's Simple BSD license */\n!function(){for(var methods=[\"assert\",\"clear\",\"count\",\"debug\",\"dir\",\"dirxml\",\"error\",\"exception\",\"group\",\"groupCollapsed\",\"groupEnd\",\"info\",\"log\",\"markTimeline\",\"profile\",\"profileEnd\",\"table\",\"time\",\"timeEnd\",\"timeline\",\"timelineEnd\",\"timeStamp\",\"trace\",\"warn\"],length=methods.length,noop=function(){},console=window.console=window.console||{};length--;){var method=methods[length];console[method]||(console[method]=noop)}}();\n}else{document.documentElement.setAttribute(\"data-init\", \"lacking\");}\n</script>\n<style id=\"style-normalize\" type=\"text/css\">/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\n\n/**\n * 1. Set default font family to sans-serif.\n * 2. Prevent iOS and IE text size adjust after device orientation change,\n *    without disabling user zoom.\n */\n\nhtml {\n  font-family: sans-serif; /* 1 */\n  -ms-text-size-adjust: 100%; /* 2 */\n  -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/**\n * Remove default margin.\n */\n\nbody {\n  margin: 0;\n}\n\n/* HTML5 display definitions\n   ========================================================================== */\n\n/**\n * Correct `block` display not defined for any HTML5 element in IE 8/9.\n * Correct `block` display not defined for `details` or `summary` in IE 10/11\n * and Firefox.\n * Correct `block` display not defined for `main` in IE 11.\n */\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\n\n/**\n * 1. Correct `inline-block` display not defined in IE 8/9.\n * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n */\n\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block; /* 1 */\n  vertical-align: baseline; /* 2 */\n}\n\n/**\n * Prevent modern browsers from displaying `audio` without controls.\n * Remove excess height in iOS 5 devices.\n */\n\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n\n/**\n * Address `[hidden]` styling not present in IE 8/9/10.\n * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.\n */\n\n[hidden],\ntemplate {\n  display: none;\n}\n\n/* Links\n   ========================================================================== */\n\n/**\n * Remove the gray background color from active links in IE 10.\n */\n\na {\n  background-color: transparent;\n}\n\n/**\n * Improve readability of focused elements when they are also in an\n * active/hover state.\n */\n\na:active,\na:hover {\n  outline: 0;\n}\n\n/* Text-level semantics\n   ========================================================================== */\n\n/**\n * Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n */\n\nabbr[title] {\n  border-bottom: 1px dotted;\n}\n\n/**\n * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n */\n\nb,\nstrong {\n  font-weight: bold;\n}\n\n/**\n * Address styling not present in Safari and Chrome.\n */\n\ndfn {\n  font-style: italic;\n}\n\n/**\n * Address variable `h1` font-size and margin within `section` and `article`\n * contexts in Firefox 4+, Safari, and Chrome.\n */\n\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\n/**\n * Address styling not present in IE 8/9.\n */\n\nmark {\n  background: #ff0;\n  color: #000;\n}\n\n/**\n * Address inconsistent and variable font size in all browsers.\n */\n\nsmall {\n  font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` affecting `line-height` in all browsers.\n */\n\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\n/* Embedded content\n   ========================================================================== */\n\n/**\n * Remove border when inside `a` element in IE 8/9/10.\n */\n\nimg {\n  border: 0;\n}\n\n/**\n * Correct overflow not hidden in IE 9/10/11.\n */\n\nsvg:not(:root) {\n  overflow: hidden;\n}\n\n/* Grouping content\n   ========================================================================== */\n\n/**\n * Address margin not present in IE 8/9 and Safari.\n */\n\nfigure {\n  margin: 1em 40px;\n}\n\n/**\n * Address differences between Firefox and other browsers.\n */\n\nhr {\n  box-sizing: content-box;\n  height: 0;\n}\n\n/**\n * Contain overflow in all browsers.\n */\n\npre {\n  overflow: auto;\n}\n\n/**\n * Address odd `em`-unit font size rendering in all browsers.\n */\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\n\n/* Forms\n   ========================================================================== */\n\n/**\n * Known limitation: by default, Chrome and Safari on OS X allow very limited\n * styling of `select`, unless a `border` property is set.\n */\n\n/**\n * 1. Correct color not being inherited.\n *    Known issue: affects color of disabled elements.\n * 2. Correct font properties not being inherited.\n * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit; /* 1 */\n  font: inherit; /* 2 */\n  margin: 0; /* 3 */\n}\n\n/**\n * Address `overflow` set to `hidden` in IE 8/9/10/11.\n */\n\nbutton {\n  overflow: visible;\n}\n\n/**\n * Address inconsistent `text-transform` inheritance for `button` and `select`.\n * All other form control elements do not inherit `text-transform` values.\n * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n * Correct `select` style inheritance in Firefox.\n */\n\nbutton,\nselect {\n  text-transform: none;\n}\n\n/**\n * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n *    and `video` controls.\n * 2. Correct inability to style clickable `input` types in iOS.\n * 3. Improve usability and consistency of cursor style between image-type\n *    `input` and others.\n */\n\nbutton,\nhtml input[type=\"button\"], /* 1 */\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button; /* 2 */\n  cursor: pointer; /* 3 */\n}\n\n/**\n * Re-set default cursor for disabled elements.\n */\n\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\n\n/**\n * Remove inner padding and border in Firefox 4+.\n */\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\n\n/**\n * Address Firefox 4+ setting `line-height` on `input` using `!important` in\n * the UA stylesheet.\n */\n\ninput {\n  line-height: normal;\n}\n\n/**\n * It's recommended that you don't attempt to style these elements.\n * Firefox's implementation doesn't respect box-sizing, padding, or width.\n *\n * 1. Address box sizing set to `content-box` in IE 8/9/10.\n * 2. Remove excess padding in IE 8/9/10.\n */\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Fix the cursor style for Chrome's increment/decrement buttons. For certain\n * `font-size` values of the `input`, it causes the cursor style of the\n * decrement button to change from `default` to `text`.\n */\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\n/**\n * 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.\n */\n\ninput[type=\"search\"] {\n  -webkit-appearance: textfield; /* 1 */\n  box-sizing: content-box; /* 2 */\n}\n\n/**\n * Remove inner padding and search cancel button in Safari and Chrome on OS X.\n * Safari (but not Chrome) clips the cancel button when the search input has\n * padding (and `textfield` appearance).\n */\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n/**\n * Define consistent border, margin, and padding.\n */\n\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\n\n/**\n * 1. Correct `color` not being inherited in IE 8/9/10/11.\n * 2. Remove padding so people aren't caught out if they zero out fieldsets.\n */\n\nlegend {\n  border: 0; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Remove default vertical scrollbar in IE 8/9/10/11.\n */\n\ntextarea {\n  overflow: auto;\n}\n\n/**\n * Don't inherit the `font-weight` (applied by a rule above).\n * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n */\n\noptgroup {\n  font-weight: bold;\n}\n\n/* Tables\n   ========================================================================== */\n\n/**\n * Remove most spacing between table cells.\n */\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\ntd,\nth {\n  padding: 0;\n}\n</style>\n<style id=\"style-init-screen\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/init-screen.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n@-webkit-keyframes init-loading-spin {\n\t0%   { -webkit-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); }\n}\n\n@-o-keyframes init-loading-spin {\n\t0%   { -o-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -o-transform: rotate(360deg); transform: rotate(360deg); }\n}\n\n@keyframes init-loading-spin {\n\t0%   { -webkit-transform: rotate(0deg); -o-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -webkit-transform: rotate(360deg); -o-transform: rotate(360deg); transform: rotate(360deg); }\n}\n#init-screen {\n\tdisplay: none;\n\tz-index: 500000;\n\tposition: fixed;\n\ttop: 0px;\n\tleft: 0px;\n\theight: 100%;\n\twidth: 100%;\n\tfont: 28px/1 Helmet, Freesans, sans-serif;\n\tfont-weight: bold;\n\tcolor: #eee;\n\tbackground-color: #111;\n\ttext-align: center;\n}\n#init-screen > div {\n\tdisplay: none;\n\tposition: relative;\n\tmargin: 0 auto;\n\tmax-width: 1136px;\n\ttop: 25%;\n}\nhtml[data-init=\"no-js\"] #init-screen, html[data-init=\"lacking\"] #init-screen, html[data-init=\"loading\"] #init-screen {\n\tdisplay: block;\n}\nhtml[data-init=\"no-js\"] #init-no-js, html[data-init=\"lacking\"] #init-lacking {\n\tdisplay: block;\n\tpadding: 0 1em;\n}\nhtml[data-init=\"no-js\"] #init-no-js {\n\tcolor: red;\n}\nhtml[data-init=\"loading\"] #init-loading {\n\tdisplay: block;\n\tborder: 24px solid transparent;\n\tborder-radius: 50%;\n\tborder-top-color: #7f7f7f;\n\tborder-bottom-color: #7f7f7f;\n\twidth: 100px;\n\theight: 100px;\n\t-webkit-animation: init-loading-spin 2s linear infinite;\n\t     -o-animation: init-loading-spin 2s linear infinite;\n\t        animation: init-loading-spin 2s linear infinite;\n}\nhtml[data-init=\"loading\"] #init-loading > div {\n\ttext-indent: 9999em;\n\toverflow: hidden;\n\twhite-space: nowrap;\n}\nhtml[data-init=\"loading\"] #ui-bar, html[data-init=\"loading\"] #passages {\n\tdisplay: none;\n}\n</style>\n<style id=\"style-font\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/font.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n@font-face {\n\t/*\n\t\ttme-fa-icons (2020-03-27)\n\n\t\t`tme-fa-icons` is a subset of the Font Awesome font v4.7.0 by Dave Gandy (http://fontawesome.com)\n\t\tand is licensed under the SIL OFL 1.1 (http://scripts.sil.org/OFL).\n\t*/\n\tfont-family: \"tme-fa-icons\";\n\tsrc: url('data:application/octet-stream;base64,d09GRgABAAAAADLAAA8AAAAAWHgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABWAAAADsAAABUIIslek9TLzIAAAGUAAAAQwAAAFY+IEkIY21hcAAAAdgAAAG8AAAF3rob9jFjdnQgAAADlAAAABMAAAAgBtX/BGZwZ20AAAOoAAAFkAAAC3CKkZBZZ2FzcAAACTgAAAAIAAAACAAAABBnbHlmAAAJQAAAI6gAADv+gJOpzGhlYWQAACzoAAAAMwAAADYY1IZaaGhlYQAALRwAAAAgAAAAJAfCBClobXR4AAAtPAAAAJEAAAFMBfb/0WxvY2EAAC3QAAAAqAAAAKhjiHI5bWF4cAAALngAAAAgAAAAIAFjDA9uYW1lAAAumAAAAY0AAAL94+zEpHBvc3QAADAoAAACHAAAA11cG/YjcHJlcAAAMkQAAAB6AAAAhuVBK7x4nGNgZGBg4GIwYLBjYHJx8wlh4MtJLMljkGJgYYAAkDwymzEnMz2RgQPGA8qxgGkOIGaDiAIAJjsFSAB4nGNgZNZgnMDAysDAVMW0h4GBoQdCMz5gMGRkAooysDIzYAUBaa4pDA4vGF4EMgf9z2KIYg5imAYUZgTJAQDSIQumAHic7dTVbltRAETR7dpNCikzQ8rMzMxt/M39mHnsU1/TfZz5jFpaV7pXJunMDLAZmOqaZjD5y4Tx+uPTyeL5lG2L5zN+L94zG8+ztr7ulXH1fra4bvK9M79xiWW2sNXPbWeFHexkF7vZw172sZ8DHOQQhznCUY5xnBOc5BSnOcNZVjnHeS5wkUtc5gpX/f3r3OAmt7jNHe5yj/s84CGPeMwTnvKM57zgJa94zRve8o73fOAjn/jMF77yje/84Ce/WGPun1zi/2tlXKbp3Xyc44bFyZanSWokJDXOOjXSk/LUSXn+pEwCKTNBaqQqZU5IjX+XMjukTBEp80TKZJEyY6RMGylzR8oEkjKLpEwlKfNJyqSSMrOkTC8pc0zKRJMy26RMOSnzTsrkk7IDpGwDKXtByoaQsiukbA0p+0PKJpGyU6RsFyl7RmosQcrukbKFpOwjKZtJyo6Ssq2k7C0pG0zKLpOy1aTsNymbTsrOk7L9pNwBUi4CKbeBlCtByr0g5XKQckNIuSak3BVSLgwpt4aUq0PK/SHlEpFyk0i5TqTcKVIuFim3i5QrRso9I+WykXLjXOYNzP8BuAPUwHicY2BAAxIQyBz0PwuEARJsA90AeJytVml300YUHXlJnIQsJQstamHExGmwRiZswYAJQbJjIF2crZWgixQ76b7xid/gX/Nk2nPoN35a7xsvJJC053Cak6N3583VzNtlElqS2AvrkZSbL8XU1iaN7DwJ6YZNy1F8KDt7IWWKyd8FURCtltq3HYdERCJQta6wRBD7HlmaZHzoUUbLtqRXTcotPekuW+NBvVXffho6yrE7oaRmM3RoPbIlVRhVokimPVLSpmWo+itJK7y/wsxXzVDCiE4iabwZxtBI3htntMpoNbbjKIpsstwoUiSa4UEUeZTVEufkigkMygfNkPLKpxHlw/yIrNijnFawS7bT/L4vead3OT+xX29RtuRAH8iO7ODsdCVfhFtbYdy0k+0oVBF213dCbNnsVP9mj/KaRgO3KzK90IxgqXyFECs/ocz+IVktnE/5kkejWrKRE0HrZU7sSz6B1uOIKXHNGFnQ3dEJEdT9kjMM9pg+Hvzx3imWCxMCeBzLekclnAgTKWFzNEnaMHJgJWWLKqn1rpg45XVaxFvCfu3a0ZfOaONQd2I8Ww8dWzlRyfFoUqeZTJ3aSc2jKQ2ilHQmeMyvAyg/oklebWM1iZVH0zhmxoREIgIt3EtTQSw7saQpBM2jGb25G6a5di1apMkD9dyj9/TmVri501PaDvSzRn9Wp2I62AvT6WnkL/Fp2uUiRen66Rl+TOJB1gIykS02w5SDB2/9DtLL15YchdcG2O7t8yuofdZE8KQB+xvQHk/VKQlMhZhViFZAYq1rWZbJ1awWqcjUd0OaVr6s0wSKchwXx76Mcf1fMzOWmBK+34nTsyMuPXPtSwjTHHybdT2a16nFcgFxZnlOp1mW7+s0x/IDneZZntfpCEtbp6MsP9RpgeVHOh1jeUELmnTfwZCLMOQCDpAwhKUDQ1hegiEsFQxhuQhDWBZhCMslGMLyYxjCchmGsLysZdXUU0nj2plYBmxCYGKOHrnMReVqKrlUQrtoVGpDnhJulVQUz6p/ZaBePPKGObAWSJfIml8xzpWPRuX41hUtbxo7V8Cx6m8fjvY58VLWi4U/Bf/V1lQlvWLNw5Or8BuGnmwnqjapeHRNl89VPbr+X1RUWAv0G0iFWCjKsmxwZyKEjzqdhmqglUPMbMw8tOt1y5qfw/03MUIWUP34NxQaC9yDTllJWe3grNXX27LcO4NyOBMsSTE38/pW+CIjs9J+kVnKno98HnAFjEpl2GoDrRW82ScxD5neJM8EcVtRNkja2M4EiQ0c84B5850EJmHqqg3kTuGGDfgFYW7BeSdconqjLIfuRezzKKT8W6fiRPaoaIzAs9kbYa/vQspvcQwkNPmlfgxUFaGpGDUV0DRSbqgGX8bZum1Cxg70Iyp2w7Ks4sPHFveVkm0ZhHykiNWjo5/WXqJOqtx+ZhSX752+BcEgNTF/e990cZDKu1rJMkdtA1O3GpVT15pD41WH6uZR9b3j7BM5a5puuiceel/TqtvBxVwssPZtDtJSJhfU9WGFDaLLxaVQ6mU0Se+4BxgWGNDvUIqN/6v62HyeK1WF0XEk307Ut9HnYAz8D9h/R/UD0Pdj6HINLs/3mhOfbvThbJmuohfrp+g3MGutuVm6BtzQdAPiIUetjrjKDXynBnF6pLkc6SHgY90V4gHAJoDF4BPdtYzmUwCj+Yw5PsDnzGHQZA6DLeYw2GbOGsAOcxjsMofBHnMYfMGcdYAvmcMgZA6DiDkMnjAnAHjKHAZfMYfB18xh8A1z7gN8yxwGMXMYJMxhsK/p1jDMLV7QXaC2QVWgA1NPWNzD4lBTZcj+jheG/b1BzP7BIKb+qOn2kPoTLwz1Z4OY+otBTP1V050h9TdeGOrvBjH1D4OY+ky/GMtlBr+MfJcKB5RdbD7n74n3D9vFQLkAAQAB//8AD3icrXsLcFzlleZ//v+++nb37dfte/VotVrdrW5JltuKpO6WJVluPyXbsmOEbGRjO4KVjWPZlsM4QIU4IYGlgCE2yxqKIQkJg2GreKQCTCZb1CZkiswjzOwOmSTATNVWTZLdDUwSMrVDsomD23vOf69assFAqgbk+773P4//nPOdc/5mwNjFl8WjosbaWblmxiOmIlTGYXzb11M7Z2ohAMbZCcZ5iG9prZl4whfwGju05xtttitUdwXYEUgkbQtWga5lC+XBaqJI285qpb8dVEc8Gnm5L5QM/f58yAlB399a7dD0mWAmdAqaMvBmKPKX9TdDwSjod9yhx03FAPcvI6Gk2lV33XoXUtKgL8C6Wa0WSzXbVjhg6JoqIPShCK0FOvOuE48K1V4B1VUQAVevugmP7Fz2CmTzW5/8+ZGP/+Kp7h/8oI4MuOZ7M5B9IvujH2Wf+PnCAjzn8ZK6AieMKRcvXnxWWSWCzGARlPcqtqs21WZzEBFgYIVDAYWzVJIrXBlH+hXGlWNM00GAJmYZ8sKBzTJFVZVppijqDFMVdTIWLa0o5JrdaHusPZGIG1IjFhQGK2mAZEe56kJnR1bTY7ZT7eivFGODBTdma3pHtlCNDVbwmgMHx/aO4R8ffeet5/ZCG6TfuV03IaSJU3oIzKsGO9+5PV+BwU5xqnOQx1aO8fW71yvD9fPn55/fA22PmsaFvfSgwZ8wzPiFvZ2DUMnzJ2hHVDMmHucPsSRrq7UQo4DMAV/AW7CANw/Zru3NIx20bBEpXwukArlxxOPReibaG63/SyQyiftzcBy3k1HuOHgjEgFHnkYfh4VodDJC4138Ff8hv5PlWbrWmm2O6grNEgGNCWGnbFtRm1Z04gzQPPWvkqMWF4eWU8DB267Df+gNe84bBvfRpfNI5Ny5yAmHDh5/PPLuByMlekDS9DsRR73nWHetwBShSO5PqCBQONO4E2wGlSvYZG6gMzeQ09SWFZC0tWION3oOVVXGTbGM+hrAzQj0O25yoN8R8YzzRsaZdzLwhpsGPEm783hAJ9+kq286eDX5pn/VydDjvk7i8EuchU21JJ3DNOqFzeABmywPcNXxhu/wB+3whrqwVw7Cn1j8vPfdDH6O7PR3fDV/Cb85wua/waSit309grZJHHOhHEQ9CA7zTGVCUb0ZvXzc1lrRe5Af+4An0aSL9op0IU9y6vRFtAYGKy7KJGFbQrdg2dXqGAwWilld0zUy9xLqd6A/zeFuy7gzYFmBOwOhZ6NNhZakm8YTI7S1pyM1mM032V26qevXGlzZ8+TKvROlB/BBkO9ACDalB7OZuBnuC5tRcAItpalENNOfhajVH1A2a1HjbHZ4N4r54oWLz4qPoe4jrMo2sonapm5QRQBQ3XycKVxwRRxjQuVCnWc6mrzOZ5FvBiraOmia5FubYRpok8n0ioRTKOQMNbWiszxYWAFZrQ1sB+dDJTFYghzyiBN3oB857ndIAha4Se/+YGUtjAkXXUO2xPE2eoe3TWPeMOXmzNi+j9w1HghvVbSAmu4c6nFac6MgbzXFU2baDr1241+98TfHtU/9t7df+MzU4msmfPYj06Wbw8Gqohda0/FkSyiyvtPGG/FsMKq1pLqmPvndkye/+y+08eYIHEJZpFmJra2Nop/VWuKcCwPvgRhnGlOFps6iIdAEmFVAKh53jblZyBU6nAFdbfX03tGwioZ9oGnEyDSWTQCyFzhoR+s/jdjgWLmc3L2K21zEmXCsM5aDm4g9Ny5v0PZVb+dY9Rcd/sl5eTiPj0nTaeiU+BhhW2qbuzJcUy2Nc2gCrjBkxWCqZiArGgOuwSzjAlDb5L91XfpvfYbpij6ZRIUWYoVcLqC2+UqNLddsMrekY3GZztVl2uQjpl4xjedIM+Uybc/r5viShuHgcgXuwQtpuoMHz8utCe/s8S+Y/7xMaYu2DX1yDrez3lp3cyyKdop+HLcLi878Uh9SKOSlj73cOIUFRVKVKHhaSS9JP452RCcYoJ3w85bz8Ckp9VN4xeZj9atpH4FnPCV4OtiDNIVYCrWwsbauK81VxUlaQnA+riFBisoUsiU0LbQpASCmmRAwg1MNJoH19uQ6WpriUV1jIQjphA5QjosiTfiy1tF+kPJKMTFYpAu6lkx40odnTv7VjYtC/QtTJyGH9HmMnKamGrcaqmaagRsMUwR9WeLmwsQREvIRevSvYa8uVFXo9Sc0w5A8/Rp5+jcxhXLuYAOIx/pbY+ggFp0FV8lNoLNAEQvyDkwBZR9T1ZC6xR0qFgsybix3DJcR7iIGwCsCHHQM0nYKVSBXQZPnqG7KDZiqrn8K524gpN9ghAx42k4GsvF3nohnA0kbnglkC9mrl7h4Db2TommKcVE1QOPRd97K5WJxsKO5nIjHbHtx/og3kK8iWys1he/EkKlqCbFOB6iKQp5Q5Yp6DB0AsjmPvHEFSGsoFraPaVpI2zLc2lmudErjJ/eeQwbKPoRBZulcwhwXYc6i1SdiEpiCF+KrFOIrAzKaHdhQ79tw4MAGuJv4rt8sQQu80jloGnnDfNVJBa+vn1WjSg1d8NHrg44FbTgdJ5+T77yy/gDI5wY7633yTbI7+CdyMDyEL2paDd0BvZjyfIYXH2/H+aqjDfXUisgnk3rFYMePoyZBegWanQpM5hKdlUSU1JnoQH2iG1d90IYADi0JPV2/oxMEeB7apm+aBngFw/ObMjzHzv7dgzyOh48fHZnmO9c8Wv+2RAGwHiP20UNnzx46mvYxyaMixDpZX22lQqQgRDqG4kYcMo92cpypAOo0Ti+iSYXJRGc5l8wvQhPfqpE0SYa7nDwkeQyh26OOlbecqVumoCwJ8+mDm+9/5T4eOyOt+4wk8WjavYTIG+7nD5Li2cWv8zGkMYoz51q2u3Y1JQSwfcumSn9JUxW0CZIWQ5isqKCo8zoGFPybx/lyHD2w4AaCBw7Ap1HIxAaHyZlr1tXG1owMt7h5Ox5QmxF4Iv6vDhaQoTFAYADuYIlnLa7b7RwtiOBDtVK1dbyCMXXxn5azOIIKfLFKaQP9K3HKIMYEQosvhkIWH23TQ9wIpCq9M4WxycnJsQIUYrEJ/bPGuOZohfHVzdmMaAmHm418c7DU3xdoyYPebFktPJtpHu7fefjw4R0VHiNTa06ZUTPe09a1sdTUVNrYtbo3nth11VW7tBa1d/U1a1t71rdG2u1IJNkWDYdbUs0pnnFT+OloWzISsdsjqVpvy9prqrNjed41POfPx2+J7TIXaWP5Wgf5bvToBEvpppQYOXPOJoda4gTQE6TsNK8sAvUSSHBFygfnfM9wL+8aK/Bddv0tZ8SufyKZ7ml7s20iCWdsPpPu4YVaXuur/2M6WX8riReTE21vtPUAnn4iyTxdf0vJ+/QM0pwsUL4D5BmUBQEeXpaU4W6RtExzN1In7eT9qHPpIoUdqAzSrdyHIPo1JNRps1uioCWJyIm2U/JG8oO4aZMXozF8b4RupRd5JJv7Nn8ZeUyxjlrakhJHcwO2gHMUDgGLR0MmS0GrIoMRWos0K81LUnPZYgmkw6sM8HtCoQTaT9y0Wu3f/MZuCYfijhMPhUVQNdL2hY8kMroS/8UvEqqeSfC/xzPV07k3vsqyrL+2ykYnhJjEz45OLIdbu4ncrbrWhImzltU7oqqaXAEdMWiHxPsSdvuF70K6/xf6FejjL13YBvFVP+UXrkwnyelZjBcltoLypQIoEmsoiDUw4C2QFS/I/J6yx5ybWOOqaMad0kJlKo+ElAdLqvRTMqOsgucuM64j3hgHU1H1mIkQ084Oje3eXT1lZwL1nwaD0BZMNfFTcHpv+sf7v6LEo4oZMlRbFNqH9tb60nEN0UkQ0mYawZNpR878eFuD1lWsl/Jb9J5iMbPlDKnkh3raBmS66U1M9Jm5rKUmMel1dKLOcxrVSgf5dJqU4o0g0pJyTlV37x4bytpCATOG8VUT4+m9cPoURiakE34ZMes/wbB0Roun+2p7h9oLSlwzQqZq2eIr+xe2/Rhp5QF8hHn5Hh/FfM9ibs32UrNG+l22ZbrnJ8N+fERAcD6YCp6nuPc2Aq/vWXiMfzKaye/BDfzTLPwe33MT8ns4P/y0uiLBdyZw3qRvNvGZegjF6H+escXvreOnkD7zm7IkADTbJEkU4sdw1jmwzpTj42smHLB82ijenjfx9YsXkccR+B5+I1azGtQk+4maTpnLlsBL75E7O1IPea+mzfPmUwQt00FJoG+nPxN/zruZzZprTljyx2GpXiHdYWBZtcINeB+2xVP16/GT9euDwf00TbqgK5gK7QvCmfp/wPn15WDa3BcM1l/Hy8F9wZQ31nf4Q2IjjrXyG+BnzXnMmqXiTuB5CLa01gINjvb8mesSTwHuSAEtzm8anp+uvwbdprkfhUs0wCNIxH6TP1l/vf6aPDThK0TXI5I+tjj+SX/8wIcaPxWX4y+CqsCiEIiAIzhsKrgfh+6qv+4L4RETPl6/zqMKukki9AA96OseZb3Zk7UKVKxZKt65tpR1J9p1sTGgP5Z4ah+KEzl73R/xEfr+I8H5fchlN/Jr0n0c3fSGkrz+vbhd5m2ZWltThDeKUaKh3WTZXWauS+WomBdMkjGvOCRuT9YfcIZxk0x24/5cT3q8redxe8TpTsLn03b9LIaFo/I0eQ7uxtjQm6rffI4elnTcJfbwX/qRFyG+Vw+SaJdyFIpugk0WXCcnaZFo1323viNAWHZPvk1+ugfjTf2sbcPR5LDT442bhwPj6Z5z9qi9wr8B85Ji51yXb3tISxlpSUtaZEYnFX8ZbHI6C8vk4ll2h5/YdRQbM0CUbSmXHsd5rH5zWz7fBnc/5iA1NLANwyQZ2+5JjiYfQ4mle+BxJA1prT9g+770dv4zTz9RnTPp+JlY4DJKoroOucmyT4fnsGIeFC3H9EtmB+qnGyP6413tPvs4BhIwipskDKakeIg+KKTgbl92JBkkHn1J3c8t+9ia2vBKhMFkGBJtEjrGDIzKE1SeAgTJiDAVRYpKmSGwMlksJor5gUWgjKlXYS0gurS4neaYflXJnaWBUjDKNAVhkWoF1WhHz7uJ2PapE8NHJkulySPD62/qVmLapMq10a997JqvnphQarc8dO3UQ2smYr38pfOWszK6fTs+eBKfHy4j8t2uWNrWnbDx5CNfe+TkxrHVE/EEW4ynxM9H2FhtpAeE2tnGFUH1J4xXChxD5hACLNXbLgOA3WU353rI37Y44SipbwdxwED/mEC0rOmuIzmlGkw7SBzNxZ6NN3519+zXRhV1Uosp3TdtGD68s4eXJo8uzHVtjyXc85gC9MYmRh+euuaRk+vhAG43Tm3RLGW7Clp52Oesq3N7dKVjnW9KxCdWjyFvi/nUs+Ja5CnPxtn+2t4NnVwLrELw76JqDMz1MacMGJoR0I5RVsA1lR/DLEdonLJLQWnOMcSamKlrszLnWWZ3mzcVOjsrnYWynTfVNmQ6aQFxrWtL9SQtgjqsojbxf5lp+qquSF1rVGyk02qZZEEKRkPdlv9ff3LVQ6MTFMas8xSft3fNVbd+vqg1KaF5w7RwBsirUye24UVXDS3oIcj/nz+56mF6qQlUAQ++gGoNytcxFG7P98DWMXMoHIL/6l/Z7p1riv8ko2oiyiru129WsSrmUjO1XdtWc0Pr7miOoWOV9YUQ07WQPmsCisWYDge5puAUAI3NIk6EQACmaQ+BGRaAwOSemV1TH90+vnlDrZBNFOi/nEUlLL96lYx5VZLqB5zDQLFQzGm6KuUX89L6YqxRuaPsCwXYTlJE1EVJt9ycWTo8bereoW7Wv38ewfOzmgI/N42Kn53LatjTxUCv85zbEyg+Y5hTcDddq99M2ysc8/51lABfjZ++8KvSxvUlnpCj7U+mIG3vR8yhXSbXEbaB3cDmatdds4lrhi9Z8hskNo2hkI+RQHWN6fMIUwKGFZiNhDmCNq6BoR1gejCoTzNdD86woB6cPDh33YFr91w99dHJLePr1tp525NylKZkzJtthLplN+ADzhOxjpiN1trRPwb/vhKfqIcMg8Mr3DDqd38o4cM36y9KWa+Tsn7v4/ocj134Vcg2TZsf/ABFKH4tYwrtObZYYxoF3QiQC+PjATwUho5+W8MkQlOOqUDxnlMNjZpsfB8zjJCxZe2afKeTjXeuboqT2XcOlsACB6XROFhWch7AeNy/VsZfx4fO5Aj8EjTVRPjLdtrmTS1NX7Azce6kmjZnnHf+1iuBiG0duzsmQTiZPzfjEoTGAqZ7xqt/nmmai8gXOWb0/sG9z8vyyPNOZjKDf9DlRgmQR93keVlHOU/9RTkfH8W8ieTQzWpsc21DGRM0Xw4soAUWDEDPtMB0oS9I5qeXC0PhMySPyTWjuYFctn9JEgWLp6FSXdz71TeSgzuQBmnXVHPXGqWhIhXkF+H2lQXxVqiSO5OthN9CQQSazmBOhdycwSgoZRJvQ28Yz8SVltDiwd3PUxMLN9De1dWehinH5783RvA9xhpyoHgnWAfGvE3sqtqOFT25rGIoMB4GBa0NAaepg2KYyiwVijQqFKGtopEeUFFYgQCboj0jZ8cCk7U1Q2W3MBBLjMRi0SCKxO0od6gD6Muon6Q35JGLDZS9DEpfLNZTA4aqrmrD0rwHCAO8Cs/Ur4a3J0Lql9WU4RfBJiYySfg+cviqaczLvipt59LuhbjXflPdSuRLUUd/9VV422jRv6SF/NbehYrcQ1p2AZ6jd80L5+kSRwE3WV+OVGTs9GvnU6yLDbJsrZ2aE+iijskqPtuHgTAktgz0r+xtaUaslZRRH6FKlRJrBwO9bK+lef8YXipg7j8GSJjM+GRPmSApRv6n//T4VrH3qqbRaNxoqoxSNMfwD6MV18yPulftrX+xZ7gXeka7vMCPgf2aQ8+N4bPuaKz7lg2LIGjjTT3x4T4jvubPYKL+cFtPTxscwm0DA+yVNaMjbFNt/cE9k+sUpoxgas8Gu1qjhG7GqUu+oAFel8B2gTDcgt+54If2XXv1VVsmVvRkM4m4TnnrYCGLtt5foc4F2rWO/NrIbxENvBHUy0WJBYqEg8hbyklAxoATvupfHMCZ3wAHaASEAFz/Y7pUPh+ZumWK7z65G1KGftgMJro0NbIzrOvbm1sCuhL9tBGKtrof1aLaZkdRjS4zYhzSDTDVw4bldnrPGtubWgKGiH0adR1JuR9VI/qErSgB72HMk0emp2+anr6F7kfTydZ+zdKSO0EdDRuTqaip3xAIjapaLa1aWqg/kmqNQEiXzza3ZFbqId3euezR4Iiqbkj5j7ZEIeTX7X4n9vLvLmKL2mAXILVUp0WPoyLCVJVGQ+/yNlGhjP8PNLq4y9vNy9rPrn+eW36OaPmdX0nTF7EIpu9XPlvW1XMgOiHbSHIL1ji1nsbpBdbAyXtlTRwjSHuCqyJvkjfAVEiMe317oeLEURlNKa/CI7tfVLxLp5qb4tFwUFVYJ3R6/STHqy1Xi1R9RLvvd6lSPIba14rZoo6zwa3w/7L18OGzRwC+N7B52+HD2zYPfA8OP3iIH9kyjkd4Fdwj9x85skUPzfXhQd9cSN96mB+97yjgoYUXvZ7kxYu/UW7mL7Eo+rwKK9byTKWsSWWz6N8VBaZxB5ShgDJZHerscm0J6L1at2fNGPH4CqQNZ+gAGTeaPZVNBB52IJ7nt/uI3N/B0707Do+8vmEH37rpdTLX8eEDd47Xr564Y3aIj+67azM8Q4dwYHjpHbJoOu1/8OkH++lk4s59Y2Lo+tsevG1ukA/N3uHb9f9TbkFebNRET61I/GEuOEtdCkxKcdfISpPptmSn01kdVNF4Y4NjHF1rWnh0cxWZKImsJdKcKPPIkZR5RIoYkcJ7dh665dDOHqV/4jgc2ILXkYz77zgwypGsH1zKst/L+ir6nJVsPdtR2zaC4aQTZC9CR4p0jigDQ6gmexJcUeeXdbS0xY7WslzDdpPF8uryAPX0L+tqoVNFD5QrFi7rbKGXwYnkJGCpwra4XMZe1th6JZcOCL0VgV445HepqL+l5jVdKMHP1VeH89a/WtYaK2/9Z/g4noyFYduzjf6WpSS0FIKDRovrC4aaQ9ZArQ9b1r/K58P0Yhi/4Msl4WPhFbUuzCTBb1OitsjmCVsAn+Qs3eokTJ1FeEQlI1nGXNlfnbS8tcc/sYz4wU8vsbd+lr/UII5u7mncOYBJ+WKc+5jsETe/L03AXCfmN4IlTVnCOYiVSxyWr5h45up7d/Lpu568c7ey4zRcu6yjzk9P3Xvu3im5qb9yaf98ab2AwZIsy0Zrq6nXxkG22zi121ScGiC71IoiZwcZqlAmzUCmvaU5GgkkzaQfoNCjlKimWnxvGhtR5b4r0roYFX59BZLFsvVB5NMRIVAGQ65bJoBsRuaFbLJM/0n3nZCLlZaWYKj+efWy88WezKv+yiG5dKnN23mX2uUJbi5bY+Rc4XgxBrHXGnlYb637gwLPEuXVBmD1ViiIyzgRfl5f9NddvfoB9NDxw0clWD9KV0FbdhMMjzfc+H7uJXEG8fo6Ns4O1q5fU+KCCq16PhXG3JuJcczFw6GwEaLSBXkQwNwF4DgLs1AgHDqA2FToAXEgCDpj+jTudDaDgUmnGsaG9bWx1UOVctJGzBlDf2HJWgZyh1HHkeV53RK5WC6Gc8fr45AzKSByxwlWHShTsxydSgfVLhALUZsXOiS8w0TlVOdJ006bC4ZayA43j7cN9WCqeCgYDTvGJzKnKG0Jn7ou6KSC18Frs8FUk2Jch1frv65/kWLdMMbf2fWfDKac4HFdaYpb8HY9ZDXZhnEylEgHP7t2L6YMcO46M22b111HA113zoFBDJQUpy/WLx6B36K+MxQdmlHBKerm0BIJKqUu68GgoLY0VSpexdChJiDC1WpC9qwK1cQYpS7U0BW0JAzeMrX6P+hRI2Dy4z/hqqmb4gS3jG8GLT77P1Ue5E4wfOFTFoioAS8NYVYZhv9umJapaPV6hct6wHdkHiowcqVYnvUivt5Qa+3vK/X2dBXy2Uy6pclBE4pR4XkwxWHTtq93vH+tv0l2U6pFvbNRePWrv51uBFbBWmgHbw/upXv+0LnRc1AxL/RjLrVgmvx/yP0Fq1KJxarV2A+PHct2HDvWwbvxJIYX60/THfzHrcdGH7shQm/iC2l6E/fXRumtaPU/ybeyx+p34UkVL0LJv9PAUHOomzL1w8q9uZaYoV3SIOoujHBKKii60eKMxhJHXUMgTQW0InVqqErq22AbYN6BHOMkFCMtlpWLDDc/0NM23tYLZ1uGMX5ZrWfPtkQj+chQ61lZiH+gZSiai0Sbz4JhDbeswXd2PSVr8E/twqtr8KXdu690Q2KpI6jHMMuhBjdRdbG9iQslEae6YVhDV7gBdOiHgK4iKtSERkv4yOpAP8ZMpimmNqtSRuUFG50FDD2AeaYRNrasGS0P2LTwuGDncpRJNtZ5Fpev85SVhMY6T3ewBJrtjAFIs8XZi95eSXOXLJkW75wKaXmE7afkst1TsjBDJxP3v3I//kG6Z9R+ce7WnfcfrvHRo6fPnT46CpteTMJZ7yXKMb2XTlHieMpspgUYLz+k3UsJV/LFTWNH7vvT08eHlfWHHtx+69yLSbZMRhHWhDn2SG0oYCC3qE/B0qAKuZqPg+b5XkErlwWmYkKlMkNY2eLmUAqF3OJinmKjrPIhuK1/W/IJ6z8kh5K1D2aK+/UTWqOzkz1fC4xVOgKKKqgjZqKV9nhTGGOgUGnZjiK4Mq8jJFKOMwJ0UxSLdlO/Ymvrtq8H3/UG+nBNcG0e7Vh79xt/yOf37KklDMPYaeyc3LZ1y8hwT671KoP8BApooL9agOqYUm2FATeRptTcdeQGxexmC3pWyw2u5ZSr4l9xsLCKW+DaaeqxVskXZql+XdTggY9NDrcHk331MoTzqZSj3fGlCe3GxJQT6IsGjeBkQOGQO53v+VKSb9E1EVMQ5vKs2/R7axiimWAmiVCh4/MZ1eYrecvvMWx9oa71KppmNkVhBs6G6m+veHkw8amOFi0QFY4pTI7RrikRxSd1jgBaCeytDEHmYSsUN/HTEEyqQVQ6ppY4937ER/nPmMXaWK6W8TvQy1cj+s28wcIlS70LHqQsSoS5rB18abP70ubwv0VMqrRhJALnb2SJXZ76vg7pAPc9++oF2+s8XzLyZUMt/3ajhy35encPGy4n+lIy4Xvvou1JERMJFmTa8zqHldSwlaBa9k6VC63heDzM/3cYttfndDMiKlbIwCN7eV2F8FS61toUNZhCzHltUoKChwg/yah6WVnr8jIXJer+ultoizj14CWn/GfvvEU5uIjTdtnx8nw86K1TlzWF5QsXBhYXGlw+3rLk/5IB/G8+gzZuYUagPa8ByoUaWfiRIuA35I4CrJOMVariLtOCaKD+Ryq3gvWTwSDci1AAfVtQi7zzsmWE4F5Vq/+RPKDe8714vX5SVSVGuXjxa2K/iCyN42qyOkbLkXwt6FIjmt5sRsHC11VB2yANZQl1HL+GWjFC9Em4Vx7Q2oKTeB2+oKkeL3xEkBU015zWlri4VEBrpICIlwZ7Eso2mgSVKs8GLeJN5YsLnmn7Lh7/45KS6ncSg5I/Por8NcaWi7UW27Te2JeyTGPqPg3VS9j2CzJyeznjn1qaGXCrpsq8ro655n7+1zi3WwkBRkGuRl5e3eMyi6L0TvDJcnYwTnM14fWG5Xyh5nXVLya56BmNJRUi25oYoiGRJBGXdaO+Rb1Y9R861mlZYzodsf21K8/wZ1mC8I75Hr9viTsF+fsW5BzxTSO1IFQNz6DJvnC/lPv9L6Ab4KcvfJU6gC94y9NfMP31s7i5XY5RIn6LJqKRxjAKDuOVppiQA65ycUhaEvVeQya8dVuF6uCYKClVFADVGd5FyGt9RTWAAgg50ahiNFm2YkcCarHv3QTW/6Jna0TY0VA0FEpnMkbciKJ0RGSrrMN/XzzKfy7p3saOsq21cUl7FVQ2Dboqxg8D38S4hnxooL2bGRU1qurqAtP1Q1M7xzd3Sd4MKlx9aN7cxtWq/1OQAi25ohrK0s0ilVHwbgmKVNGWD1T/IMmcmd2u68h5MhPsLpW6Mf7ZEUPfceC+0zfhdXy9uTm5cQffujnZrMQFzmZdv+n0HyDOnl33Z4RjOcFoIL338N50IIpBxBEd9+2+7fV+vGGHQ5Y18NCTDw1EwkITYRu/JwZe9fPMI+IfxFUsyjbSqvKhAcwt168pdedsTBbTzZxTnRzRxQyV/if8uggP8y2VcpqWw7iyTmgJOy3GuEu5oK35P5xC0L6GZFag308hopD9/6r3KyoE7rKG5Tqi3D9z8s6TM/3+7mEeeCxiPDanxdWDjxmRxwKIeebmVFVePajGtTl5VaWLcGDdLdMVpbTvxD0n9pWUyvQtew1RfioQFOU/1vU/Lotg4KmyMEz9nnuM2OINTVu8ETPuuUeXPuNZUcFYEmd9rFRbYSxfVUjLiN9dFerqyvd2yKWFBEEB548Fup3m1PWnBQHUERnjyKYur0O1v1pBfvl30u2Hnj4EwydOw/CBOyd23vd4+YefpuUbvHb84elmO9HXD1P3Tq1f48YM5VZ17msH5/d1fPtmWQndeOwTd1EnZNeXbtwsoBRbcbJ29T3T0GbGDO+3J95aen6KxViWDVCHL8i5wsPAxPLfE1FDb55RmQnmCYgrEoijOyX+6KeDoE66Tt5ONjkSgheKBA9LqL6qpqchU0E7QaSYtJ3+irSVimrrmpLJU3ej0gsK6vTRXbdlEXtnb9u17Z9B+Un9m9Hg5rmoE93YF4zCPwZ31H9b/6f6b3cEgzvAgAIYO4IwfMe64Q03nOX3fXzD8Lo7brzrLtiCz85tCkajwb6N0b9LJD738MOfSxTs2x7mj3yGsEgjzzBYB9Xw2hGCYAZOzYWG2uR6nFlvxlJeEZfO732ziNsX84be4ffMGz7/gRmQb1dyTX8Q/dtArU8Hb8Wybmgod53NBlQOilxbg9mPCIstK3sTAzE7O5BMJuTKkvJgwfulBskXM0CBMymXLQrpkSoDMVmJ6aA2QjGG4SJkRk38g5sd61dtYGoQ4St+jHY+U23r4aVWOEjtseoMnDgvfwCEm2+hp6r/X91AK4zYkU3HMVEaxnR3qBfqPzn+/wHPnsOreJxjYGRgYABi1vIsoXh+m68M3MwvgCIMt5YoxkDp2P9f/2exVDAHAbkcDEwgUQAz1Qu/AHicY2BkYGAO+p/FwMBS9v/r/68sFQxAERQQDACh8QbyeJxdT0sVwzAMy49AkAxAkbT3UQiAITGAISmAYQiA9th4ttUs7Q568UeSlVidiwSkB3PUPg+ESd6ZD/+8v7HyrtzwghY89ZB6BcyrYqc6RZhw48YhaA1Wc/v1PQtdeXJ/HppUmFM597nvBVK7D+Z+E8/uQZLBgDyaz3Llvxx02S3c/Hv813JrznryZP4F+6lSfQAAAAAAAAAAUAC2ATABaAGyAfoCJAKwAzYDmgQSBFwExgUyBbQF/AZOBvwHRAe2B/YISgigCPIJGglCCWQJignACgAKQAp2CroLAAtGC4oL8gxcDPINng5iDuYPag/6EF4RIBGGEeQSShKYEyQTbhOyFAoUYhS+FVoVphYoFooXHBeGGFoYnhjGGOwZChlOGXgZrBneGhwaWhqgGtIbLhvyHHQc2B1QHZ4d/wABAAAAUwBtAAYAAAAAAAIAIAAwAHMAAAB2C3AAAAAAeJx1kN9q2zAUh39q0441YxcbjN3tXJWWEcc1lEGvWkLbXZeSu8JUV/6T2VKQlY48w95ifYa9zt6jd/vFESUUYiP5O5/O8ZEE4AP+QWH9nHKsWeEdozXv4A0uIu/Sf488IN9G3sMQPyLv0/+MfICv+BV5iI/4wz+owVtGM/yNrPBZfYm8g/fqW+Rd+svIA/Jd5D18UovI+/S/Ix9gqp4iD3GoniduvvR1WQU5mhxLlmap3C/FUdVWN6IXoXK+k3MpnA2maVySuza0ZlToUZ07292YctFov6k2eWp8VzsrJ0m6qa+NNV4H87Dq1j2WWQiFFN61chX7yNy7mclDUoUwPxuPN/tjAoc5lvCoUaJCgOCI9pjfDGk/BPfMEGaus2pYaDQ0GgtWVP1Kx/ico2BkaQ0zGnKCnHNL09KNuK451721rLqhLfmfht5vzdrmp7Sr3nUfC07YL92afU1r+wrd7/Dh5WwdHrmLjDawanUK3+9acPXqPML7Wq3NaHL6pL+1QHuGMd8t5/8PvPGO3QAAAHicbZLnlpswEIV9DRiwvZtseu89Ib333vvmBWRZYMVC0pHEEufpg8BO/kTncOfTaLgMOtPr97o17P1/baKPACEiDBAjQYohRhhjDevYhu3YwA7sxC7sxh7sxT7sxwEcxCEcxhEcxTEcxwmcxCmcxhmcxTmcxwVcxCVkuIwruIpruI4buIlbuI07uIt7uI8HeIhHeIwneIpneI4XeIlXeI03eIt3eI8P+IhP+Iwv+Ipv+I5N/OiF1hEz9JKxUrtFrDl1lWF9NR9QIikToRaVjUouKxvOmNBjLxnlhgo2DbnM1djLKrNGnGPScSUzItzGv93yPP2bSQSX84z9cqFQdJ56yZRmMhW8mLlJJSaBI0XYPDaZKDUviZmvr6DrNjJMi0WcK1MTM02mqpbZlJtEsNx5SI238jSodJtoS7qv+BpPw67IY9xU+dg5TXjROTWwdGrIOzWhT+uA0jolxqjaZrSOnCF2Nmq16651EYpMm1fakAul9SJQeR5QVYQlk1VkZ8SwoVNFIVjWnKQrlBGdMToftdoZjrs77DajqXKrS02YEFxbbtdWkG0x44JJVUS5aBqKSlJwmhDrmOF2Hv9Wqsy4TNqoKhfmSrrQKuNSL5nvPG6p0s0AkEWkSWVZMy1Kx3ljk03qLuZ14lTmB8gNGmByGrGfjLrhlhJV2f7SaIneNF1ypQNbybBUSgZswQaWEUNngeay1/sD4l/60HicY/DewXAiKGIjI2Nf5AbGnRwMHAzJBRsZWJ02MTAyaIEYm7mYGDkgLD4GMIvNaRfTAaA0J5DN7rSLwQHCZmZw2ajC2BEYscGhI2Ijc4rLRjUQbxdHAwMji0NHckgESEkkEGzmYWLk0drB+L91A0vvRiYGFwAMdiP0AAA=') format('woff');\n}\n</style>\n<style id=\"style-core\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\nhtml {\n\t/*\n\t\tWe define the base font size and line height here as they affect the layout\n\t\tof the base page elements (i.e. `#ui-bar`, `#ui-dialog`, and `#story`).\n\t*/\n\tfont: 16px/1 Helmet, Freesans, sans-serif;\n}\n\n/* Story data styling. */\n#store-area, tw-storydata {\n\tdisplay: none !important;\n\tz-index: 0;\n}\n\n/* Special no transition styling. */\n.no-transition {\n\t-o-transition: none !important;\n\ttransition: none !important;\n}\n\n\n/*\n\tFullscreen appearance styles.\n*/\n*:-webkit-full-screen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\n*:-moz-full-screen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\n*:-ms-fullscreen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\n*:fullscreen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\nbody::-ms-backdrop { /* Prevent IE 11 from hiding the `body` element's background. */\n\tbackground: none;\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n*:focus {\n\toutline: thin dotted;\n}\n*:disabled {\n\tcursor: not-allowed !important;\n}\nbody {\n\tcolor: #eee;\n\tbackground-color: #111;\n\toverflow: auto;\n}\na {\n\tcursor: pointer;\n\tcolor: #68d;\n\ttext-decoration: none;\n\t-o-transition-duration: 200ms;\n\t   transition-duration: 200ms;\n}\na:hover {\n\tcolor: #8af;\n\ttext-decoration: underline;\n}\na.link-broken {\n\tcolor: #c22;\n}\na.link-broken:hover {\n\tcolor: #e44;\n}\na[disabled], span.link-disabled {\n\tcolor: #aaa;\n\tcursor: not-allowed !important;\n\t/*\n\t\tNOTE: Do not use `pointer-events` here as it disables\n\t\tthe display of a cursor in some browsers.\n\n\t\tpointer-events: none;\n\t*/\n\ttext-decoration: none;\n}\narea {\n\tcursor: pointer;\n}\nbutton {\n\tcursor: pointer;\n\tcolor: #eee;\n\tbackground-color: #35a;\n\tborder: 1px solid #57c;\n\tline-height: normal;\n\tpadding: 0.4em;\n\t-o-transition-duration: 200ms;\n\t   transition-duration: 200ms;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\nbutton:hover {\n\tbackground-color: #57c;\n\tborder-color: #79e;\n}\nbutton:disabled {\n\tbackground-color: #444;\n\tborder: 1px solid #666;\n}\ninput, select, textarea {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tpadding: 0.4em;\n}\nselect {\n\tpadding: 0.34em 0.4em;\n}\ninput[type=\"text\"] {\n\tmin-width: 18em;\n}\ntextarea {\n\tmin-width: 30em;\n\tresize: vertical;\n}\ninput[type=\"checkbox\"], input[type=\"file\"], input[type=\"radio\"], select {\n\tcursor: pointer;\n}\n/* BEGIN: input[type=\"range\"] */\ninput[type=\"range\"] {\n\t-webkit-appearance: none;\n\tmin-height: 1.2em;\n}\ninput[type=\"range\"]:focus {\n\toutline: none;\n}\ninput[type=\"range\"]::-webkit-slider-runnable-track {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: 100%;\n}\ninput[type=\"range\"]::-webkit-slider-thumb {\n\t-webkit-appearance: none;\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 18px;\n\t/*\n\t\tNOTE: Ideally, `margin-top` should be `0` for Edge/Spartan (ca. v17), but\n\t\treal WebKit/Blink-based browsers need it.  Since there's more of them and\n\t\tEdge is co-opting the prefix anyway, we cater to them.  Edge will simply\n\t\thave to look ever so slightly off.\n\t*/\n\tmargin-top: -5px;\n\twidth: 33px;\n}\ninput[type=\"range\"]:focus::-webkit-slider-runnable-track {\n\tbackground: #222;\n}\ninput[type=\"range\"]::-moz-range-track {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: 100%;\n}\ninput[type=\"range\"]::-moz-range-thumb {\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 18px;\n\twidth: 33px;\n}\ninput[type=\"range\"]::-ms-track {\n\tbackground: transparent;\n\tborder-color: transparent;\n\tcolor: transparent;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: calc(100% - 1px);\n}\ninput[type=\"range\"]::-ms-fill-lower {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n}\ninput[type=\"range\"]::-ms-fill-upper {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n}\ninput[type=\"range\"]::-ms-thumb {\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 16px;\n\twidth: 33px;\n}\n/* END: input[type=\"range\"] */\ninput:not(:disabled):focus, select:not(:disabled):focus, textarea:not(:disabled):focus,\ninput:not(:disabled):hover, select:not(:disabled):hover, textarea:not(:disabled):hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\nhr {\n\tdisplay: block;\n\theight: 1px;\n\tborder: none;\n\tborder-top: 1px solid #eee;\n\tmargin: 1em 0;\n\tpadding: 0;\n}\naudio, canvas, progress, video {\n\tmax-width: 100%;\n\tvertical-align: middle;\n}\n\n.error-view {\n\tbackground-color: #511;\n\tborder-left: 0.5em solid #c22;\n\tdisplay: inline-block;\n\tmargin: 0.1em;\n\tmax-width: 100%;\n\tpadding: 0 0.25em;\n\tposition: relative;\n}\n.error-view > .error-toggle {\n\tbackground-color: transparent;\n\tborder: none;\n\tline-height: inherit;\n\tleft: 0;\n\tpadding: 0;\n\tposition: absolute;\n\ttop: 0;\n\twidth: 1.75em;\n}\n.error-view > .error {\n\tdisplay: inline-block;\n\tmargin-left: 0.25em;\n}\n.error-view > .error-toggle + .error {\n\tmargin-left: 1.5em;\n}\n.error-view > .error-source[hidden] {\n\tdisplay: none;\n}\n.error-view > .error-source:not([hidden]) {\n\tbackground-color: rgba(0, 0, 0, 0.2);\n\tdisplay: block;\n\tmargin: 0 0 0.25em;\n\toverflow-x: auto;\n\tpadding: 0.25em;\n}\n\n.highlight, .marked {\n\tcolor: yellow;\n\tfont-weight: bold;\n\tfont-style: italic;\n}\n.nobr {\n\twhite-space: nowrap;\n}\n\n[data-icon]:before,\n[data-icon-before]:before,\n[data-icon-after]:after,\n.error-view > .error-toggle:before,\n.error-view > .error:before,\na.link-external:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n[data-icon]:before {\n\tcontent: attr(data-icon);\n}\n[data-icon-before]:before {\n\tcontent: attr(data-icon-before) \"\\00a0\";\n}\n[data-icon-after]:after {\n\tcontent: \"\\00a0\" attr(data-icon-after);\n}\n.error-view > .error-toggle:before {\n\tcontent: \"\\e81a\";\n}\n.error-view > .error-toggle.enabled:before {\n\tcontent: \"\\e818\";\n}\n.error-view > .error:before {\n\tcontent: \"\\e80d\\00a0\\00a0\";\n}\na.link-external:after {\n\tcontent: \"\\00a0\\e80e\";\n}\n</style>\n<style id=\"style-core-display\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-display.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\n#story {\n\tz-index: 10;\n\tmargin: 2.5em;\n}\n@media screen and (max-width: 1136px) {\n\t#story {\n\t\tmargin-right: 1.5em;\n\t}\n}\n#passages {\n\tmax-width: 54em;\n\tmargin: 0 auto;\n}\n</style>\n<style id=\"style-core-passage\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-passage.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault appearance styles.\n*/\n.passage {\n\tline-height: 1.75;\n\ttext-align: left;\n\t-o-transition: opacity 400ms ease-in;\n\ttransition: opacity 400ms ease-in;\n}\n.passage-in {\n\topacity: 0;\n}\n.passage ul, .passage ol {\n\tmargin-left: 0.5em;\n\tpadding-left: 1.5em;\n}\n.passage table {\n\tmargin: 1em 0;\n\tborder-collapse: collapse;\n\tfont-size: 100%;\n}\n.passage tr, .passage th, .passage td, .passage caption {\n\tpadding: 3px;\n}\n</style>\n<style id=\"style-core-macro\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-macro.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault appearance styles.\n*/\n.macro-linkappend-insert,\n.macro-linkprepend-insert,\n.macro-linkreplace-insert,\n.macro-append-insert,\n.macro-prepend-insert,\n.macro-replace-insert,\n.macro-repeat-insert,\n.macro-timed-insert {\n\t-o-transition: opacity 400ms ease-in;\n\ttransition: opacity 400ms ease-in;\n}\n.macro-linkappend-in,\n.macro-linkprepend-in,\n.macro-linkreplace-in,\n.macro-append-in,\n.macro-prepend-in,\n.macro-replace-in,\n.macro-repeat-in,\n.macro-timed-in {\n\topacity: 0;\n}\n</style>\n<style id=\"style-ui-dialog\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-dialog.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tPatches to the core styles.\n*/\nhtml[data-dialog] body {\n\toverflow: hidden;\n}\n\n\n/*\n\tDefault structural styles.\n*/\n#ui-overlay.open {\n\tvisibility: visible;\n\t-o-transition: opacity 200ms ease-in;\n\ttransition: opacity 200ms ease-in;\n}\n#ui-overlay:not(.open) {\n\t-o-transition: visibility 200ms step-end, opacity 200ms ease-in;\n\ttransition: visibility 200ms step-end, opacity 200ms ease-in;\n}\n#ui-overlay {\n\tvisibility: hidden;\n\topacity: 0;\n\tz-index: 100000;\n\tposition: fixed;\n\t/*\n\ttop: -50vh;\n\tleft: -50vw;\n\theight: 200vh;\n\twidth: 200vw;\n\t*/\n\ttop: -50%;\n\tleft: -50%;\n\theight: 200%;\n\twidth: 200%;\n}\n#ui-dialog.open {\n\tdisplay: block;\n\t-o-transition: opacity 200ms ease-in;\n\ttransition: opacity 200ms ease-in;\n}\n/*\n\tWe do not animate `#ui-dialog:not(.open)` for various reasons.  Chief among\n\tthem, however, is so that the dialog isn't in the middle of its animation\n\twhen other page updates happen.\n\n\te.g. The restoration of `overflow` on `body` would cause the still animating\n\t     dialog to jump around a little if a scrollbar were to pop in.\n\n\t     Any dialog action which performs a task which has its own animations\n\t     (e.g. passage display) or causes the page to reload in addition to\n\t     closing the dialog could cause display shenanigans.\n*/\n#ui-dialog {\n\tdisplay: none;\n\topacity: 0;\n\tz-index: 100100;\n\tposition: fixed;\n\ttop: 50px;\n\tmargin: 0;\n\tpadding: 0;\n}\n#ui-dialog > * {\n\tbox-sizing: border-box;\n}\n#ui-dialog-titlebar {\n\tposition: relative;\n}\n#ui-dialog-close {\n\tdisplay: block;\n\tposition: absolute;\n\tright: 0;\n\ttop: 0;\n\twhite-space: nowrap;\n}\n#ui-dialog-body {\n\toverflow: auto;\n\tmin-width: 280px;\n\theight: 92%; /* fallback for browsers without support for calc() */\n\theight: calc(100% - 2.1em); /* parent - title(2.1em) */\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n#ui-overlay {\n\tbackground-color: #000;\n}\n#ui-overlay.open {\n\topacity: 0.8;\n}\n#ui-dialog {\n\tmax-width: 66em;\n}\n#ui-dialog.open {\n\topacity: 1;\n}\n#ui-dialog-titlebar {\n\tbackground-color: #444;\n\tmin-height: 24px;\n}\n#ui-dialog-title {\n\tmargin: 0;\n\tpadding: 0.2em 3.5em 0.2em 0.5em;\n\tfont-size: 1.5em;\n\ttext-align: center;\n\ttext-transform: uppercase;\n}\n#ui-dialog-close {\n\tcursor: pointer;\n\tfont-size: 120%;\n\tmargin: 0;\n\tpadding: 0;\n\twidth: 3.6em;\n\theight: 92%;\n\tbackground-color: transparent;\n\tborder: 1px solid transparent;\n\t-o-transition-duration: 200ms;\n\t   transition-duration: 200ms;\n}\n#ui-dialog-close:hover {\n\tbackground-color: #b44;\n\tborder-color: #d66;\n}\n#ui-dialog-body {\n\tbackground-color: #111;\n\tborder: 1px solid #444;\n\ttext-align: left;\n\tline-height: 1.5;\n\tpadding: 1em;\n}\n#ui-dialog-body > *:first-child {\n\tmargin-top: 0;\n}\n#ui-dialog-body hr {\n\tbackground-color: #444;\n}\n\n/* Default dialog button bar styling. */\n#ui-dialog-body ul.buttons {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n#ui-dialog-body ul.buttons li {\n\tdisplay: inline-block;\n\tmargin: 0;\n\tpadding: 0.4em 0.4em 0 0;\n}\n#ui-dialog-body ul.buttons > li + li > button {\n\tmargin-left: 1em;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-dialog-close {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-dialog-close {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n</style>\n<style id=\"style-ui\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\n/* Settings dialog styling. */\n#ui-dialog-body.settings [id|=\"setting-body\"] > div:first-child {\n\tdisplay: table;\n\twidth: 100%;\n}\n#ui-dialog-body.settings [id|=\"setting-label\"] {\n\tdisplay: table-cell;\n\tpadding: 0.4em 2em 0.4em 0;\n}\n#ui-dialog-body.settings [id|=\"setting-label\"] + div {\n\tdisplay: table-cell;\n\tmin-width: 8em;\n\ttext-align: right;\n\tvertical-align: middle;\n\twhite-space: nowrap;\n}\n\n\n/*\n\tBuilt-in dialog appearance styles.\n*/\n/* List-based dialog styling (primarily for the Jumpto & Share dialogs). */\n#ui-dialog-body.list {\n\tpadding: 0;\n}\n#ui-dialog-body.list ul {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n\tborder: 1px solid transparent;\n}\n#ui-dialog-body.list li {\n\tmargin: 0;\n}\n#ui-dialog-body.list li:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.list li a {\n\tdisplay: block;\n\tpadding: 0.25em 0.75em;\n\tborder: 1px solid transparent;\n\tcolor: #eee;\n\ttext-decoration: none;\n}\n#ui-dialog-body.list li a:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n\n/* Saves dialog styling. */\n#ui-dialog-body.saves {\n\tpadding: 0 0 1px; /* Webkit/Blink need 1px bottom padding or they'll trigger the scroll bar */\n}\n#ui-dialog-body.saves > *:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.saves table {\n\tborder-spacing: 0;\n\twidth: 100%;\n}\n#ui-dialog-body.saves tr:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.saves td {\n\tpadding: 0.33em 0.33em;\n}\n#ui-dialog-body.saves td:first-child {\n\tmin-width: 1.5em;\n\ttext-align: center;\n}\n#ui-dialog-body.saves td:nth-child(3) {\n\tline-height: 1.2;\n}\n#ui-dialog-body.saves td:last-child {\n\ttext-align: right;\n}\n#ui-dialog-body.saves .empty {\n\tcolor: #999;\n\tspeak: none;\n\ttext-align: center;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n#ui-dialog-body.saves .datestamp {\n\tfont-size: 75%;\n\tmargin-left: 1em;\n}\n#ui-dialog-body.saves ul.buttons li {\n\tpadding: 0.4em;\n}\n#ui-dialog-body.saves ul.buttons > li + li > button {\n\tmargin-left: 0.2em;\n}\n#ui-dialog-body.saves ul.buttons li:last-child {\n\t/*\n\t\tUsing `position:absolute;right:0;` here can produce poor results,\n\t\tso we use `float:right` instead.\n\t*/\n\tfloat: right;\n}\n\n/* Settings dialog styling. */\n#ui-dialog-body.settings div[id|=\"header-body\"] {\n\tmargin: 1em 0;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"]:first-child {\n\tmargin-top: 0;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"]:not(:first-child) {\n\tborder-top: 1px solid #444;\n\tpadding-top: 1em;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"] > * {\n\tmargin: 0;\n}\n#ui-dialog-body.settings h2[id|=\"header-heading\"] {\n\tfont-size: 1.375em;\n}\n#ui-dialog-body.settings p[id|=\"header-desc\"],\n#ui-dialog-body.settings p[id|=\"setting-desc\"] {\n\tfont-size: 87.5%;\n\tmargin: 0 0 0 0.5em;\n}\n#ui-dialog-body.settings div[id|=\"setting-body\"] + div[id|=\"setting-body\"] {\n\tmargin: 1em 0;\n}\n#ui-dialog-body.settings [id|=\"setting-control\"] {\n\twhite-space: nowrap;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"] {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tpadding: 0.4em;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"]:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled {\n\tbackground-color: #282;\n\tborder-color: #4a4;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:hover {\n\tbackground-color: #4a4;\n\tborder-color: #6c6;\n}\n#ui-dialog-body.settings input[type=\"range\"][id|=\"setting-control\"] {\n\tmax-width: 35vw;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-dialog-body.list a,\n#ui-dialog-body.settings span[id|=\"setting-input\"] {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-dialog-body.saves button[id=\"saves-export\"]:before,\n#ui-dialog-body.saves button[id=\"saves-import\"]:before,\n#ui-dialog-body.saves button[id=\"saves-clear\"]:before,\n#ui-dialog-body.settings button[id|=\"setting-control\"]:after,\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#ui-dialog-body.saves button[id=\"saves-export\"]:before {\n\tcontent: \"\\e829\\00a0\";\n}\n#ui-dialog-body.saves button[id=\"saves-import\"]:before {\n\tcontent: \"\\e82a\\00a0\";\n}\n#ui-dialog-body.saves button[id=\"saves-clear\"]:before {\n\tcontent: \"\\e827\\00a0\";\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"]:after {\n\tcontent: \"\\00a0\\00a0\\e830\";\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:after {\n\tcontent: \"\\00a0\\00a0\\e831\";\n}\n</style>\n<style id=\"style-ui-bar\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-bar.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tPatches to the core styles.\n*/\n#story {\n\tmargin-left: 20em;\n\t-o-transition: margin-left 200ms ease-in;\n\ttransition: margin-left 200ms ease-in;\n}\n#ui-bar.stowed ~ #story {\n\tmargin-left: 4.5em;\n}\n@media screen and (max-width: 1136px) {\n\t#story {\n\t\tmargin-left: 19em;\n\t}\n\t#ui-bar.stowed ~ #story {\n\t\tmargin-left: 3.5em;\n\t}\n}\n/*\n\tAt very narrow viewport widths, set `#story{margin-left}` equal to the value\n\tof `#ui-bar.stowed~#story{margin-left}`, so that `#ui-bar` will side over top\n\tof `#story` when unstowed, rather than shoving it over.\n*/\n@media screen and (max-width: 768px) {\n\t#story {\n\t\tmargin-left: 3.5em;\n\t}\n}\n\n\n/*\n\tDefault structural styles.\n*/\n#ui-bar {\n\tposition: fixed;\n\tz-index: 50;\n\ttop: 0;\n\tleft: 0;\n\twidth: 17.5em;\n\theight: 100%;\n\tmargin: 0;\n\tpadding: 0;\n\t-o-transition: left 200ms ease-in;\n\ttransition: left 200ms ease-in;\n}\n#ui-bar.stowed {\n\tleft: -15.5em;\n}\n#ui-bar-tray {\n\tposition: absolute;\n\ttop: 0.2em;\n\tleft: 0;\n\tright: 0;\n}\n#ui-bar-body {\n\theight: 90%; /* fallback for browsers without support for calc() */\n\theight: calc(100% - 2.5em);\n\tmargin: 2.5em 0;\n\tpadding: 0 1.5em;\n}\n#ui-bar.stowed #ui-bar-history,\n#ui-bar.stowed #ui-bar-body {\n\tvisibility: hidden;\n\t-o-transition: visibility 200ms step-end;\n\ttransition: visibility 200ms step-end;\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n#ui-bar {\n\tbackground-color: #222;\n\tborder-right: 1px solid #444;\n\ttext-align: center;\n}\n#ui-bar a {\n\ttext-decoration: none;\n}\n#ui-bar hr {\n\tborder-color: #444;\n}\n#ui-bar-toggle,\n#ui-bar-history [id|=\"history\"] {\n\tfont-size: 1.2em;\n\tline-height: inherit;\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n}\n#ui-bar-toggle {\n\tdisplay: block;\n\tposition: absolute;\n\ttop: 0;\n\tright: 0;\n\tborder-right: none;\n\tpadding: 0.3em 0.45em 0.25em;\n}\n#ui-bar.stowed #ui-bar-toggle {\n\tpadding: 0.3em 0.35em 0.25em 0.55em;\n}\n#ui-bar-toggle:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n#ui-bar-history {\n\tmargin: 0 auto;\n}\n#ui-bar-history [id|=\"history\"] {\n\tpadding: 0.2em 0.45em 0.35em;\n}\n#ui-bar-history #history-jumpto {\n\tpadding: 0.2em 0.665em 0.35em;\n}\n#ui-bar-history [id|=\"history\"]:not(:first-child) {\n\tmargin-left: 1.2em;\n}\n#ui-bar-history [id|=\"history\"]:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n#ui-bar-history [id|=\"history\"]:disabled {\n\tcolor: #444;\n\tbackground-color: transparent;\n\tborder-color: #444;\n}\n#ui-bar-body {\n\tline-height: 1.5;\n\toverflow: auto;\n}\n#ui-bar-body > :not(:first-child) {\n\tmargin-top: 2em;\n}\n#story-title {\n\tmargin: 0;\n\tfont-size: 162.5%;\n}\n#story-author {\n\tmargin-top: 2em;\n\tfont-weight: bold;\n}\n#menu ul {\n\tmargin: 1em 0 0;\n\tpadding: 0;\n\tlist-style: none;\n\tborder: 1px solid #444;\n}\n#menu ul:empty {\n\tdisplay: none;\n}\n#menu li {\n\tmargin: 0;\n}\n#menu li:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#menu li a {\n\tdisplay: block;\n\tpadding: 0.25em 0.75em;\n\tborder: 1px solid transparent;\n\tcolor: #eee;\n\ttext-transform: uppercase;\n}\n#menu li a:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-bar-history [id|=\"history\"],\n#ui-bar-toggle,\n#menu a {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-bar-toggle:before,\n#ui-bar-history [id|=\"history\"],\n#menu-core li[id|=\"menu-item\"] a:before {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#ui-bar-toggle:before {\n\tcontent: \"\\e81d\";\n}\n#ui-bar.stowed #ui-bar-toggle:before {\n\tcontent: \"\\e81e\";\n}\n#menu-item-saves a:before {\n\tcontent: \"\\e82b\\00a0\";\n}\n#menu-item-settings a:before {\n\tcontent: \"\\e82d\\00a0\";\n}\n#menu-item-restart a:before {\n\tcontent: \"\\e82c\\00a0\";\n}\n#menu-item-share a:before {\n\tcontent: \"\\e82f\\00a0\";\n}\n</style>\n<style id=\"style-ui-debug\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-debug.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault debug bar styles.\n*/\n#debug-bar {\n\tbackground-color: #222;\n\tborder-left: 1px solid #444;\n\tborder-top: 1px solid #444;\n\tbottom: 0;\n\tmargin: 0;\n\tmax-height: 75%;\n\t/* max-width: 28em;\n\tmin-width: 22em; */\n\tpadding: 0.5em;\n\tposition: fixed;\n\tright: 0;\n\tz-index: 99900;\n}\n#debug-bar > div:not([id]) + div {\n\tmargin-top: 0.5em;\n}\n#debug-bar > div > label {\n\tmargin-right: 0.5em;\n}\n#debug-bar > div > input[type=\"text\"] {\n\tmin-width: 0;\n\twidth: 8em;\n}\n#debug-bar > div > select {\n\twidth: 15em;\n}\n\n#debug-bar-toggle {\n\tcolor: #eee;\n\tbackground-color: #222;\n\tborder: 1px solid #444;\n\theight: 101%; /* fallback for browsers without support for calc() */\n\theight: calc(100% + 1px);\n\tleft: -2em; /* fallback for browsers without support for calc() */\n\tleft: calc(-2em - 1px);\n\tposition: absolute;\n\ttop: -1px;\n\twidth: 2em;\n}\n#debug-bar-toggle:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n\n#debug-bar-hint {\n\tbottom: 0.175em;\n\tfont-size: 4.5em;\n\topacity: 0.33;\n\tpointer-events: none;\n\tposition: fixed;\n\tright: 0.6em;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n\twhite-space: nowrap;\n}\n\n#debug-bar-watch {\n\tbackground-color: #222;\n\tborder-left: 1px solid #444;\n\tborder-top: 1px solid #444;\n\tbottom: 102%; /* fallback for browsers without support for calc() */\n\tbottom: calc(100% + 1px);\n\tfont-size: 0.9em;\n\tleft: -1px;\n\tmax-height: 650%; /* fallback for browsers without support for vh units */\n\tmax-height: 65vh;\n\tposition: absolute;\n\toverflow-x: hidden;\n\toverflow-y: scroll;\n\tright: 0;\n\tz-index: 99800;\n}\n#debug-bar-watch[hidden] {\n\tdisplay: none;\n}\n#debug-bar-watch div {\n\tcolor: #999;\n\tfont-style: italic;\n\tmargin: 1em auto;\n\ttext-align: center;\n}\n#debug-bar-watch table {\n\twidth: 100%;\n}\n#debug-bar-watch tr:nth-child(2n) {\n\tbackground-color: rgba(127, 127, 127, 0.15);\n}\n#debug-bar-watch td {\n\tpadding: 0.2em 0;\n}\n#debug-bar-watch td:first-child + td {\n\tpadding: 0.2em 0.3em 0.2em 0.1em;\n}\n#debug-bar-watch .watch-delete {\n\tbackground-color: transparent;\n\tborder: none;\n\tcolor: #c00;\n}\n#debug-bar-watch-all,\n#debug-bar-watch-none {\n\tmargin-left: 0.5em;\n}\n#debug-bar-watch-toggle,\n#debug-bar-views-toggle {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tmargin-right: 1em;\n\tpadding: 0.4em;\n}\n#debug-bar-watch-toggle:hover,\n#debug-bar-views-toggle:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle,\nhtml[data-debug-view] #debug-bar-views-toggle {\n\tbackground-color: #282;\n\tborder-color: #4a4;\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle:hover,\nhtml[data-debug-view] #debug-bar-views-toggle:hover {\n\tbackground-color: #4a4;\n\tborder-color: #6c6;\n}\n\n#debug-bar-toggle:before,\n#debug-bar-hint:after,\n#debug-bar-watch .watch-delete:before,\n#debug-bar-watch-add:before,\n#debug-bar-watch-all:before,\n#debug-bar-watch-none:before,\n#debug-bar-watch-toggle:after,\n#debug-bar-views-toggle:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#debug-bar-toggle:before {\n\tcontent: \"\\e838\";\n}\n#debug-bar-hint:after {\n\tcontent: \"\\e838\\202f\\e822\";\n}\n#debug-bar-watch .watch-delete:before {\n\tcontent: \"\\e804\";\n}\n#debug-bar-watch-add:before {\n\tcontent: \"\\e805\";\n}\n#debug-bar-watch-all:before {\n\tcontent: \"\\e83a\";\n}\n#debug-bar-watch-none:before {\n\tcontent: \"\\e827\";\n}\n#debug-bar-watch-toggle:after,\n#debug-bar-views-toggle:after {\n\tcontent: \"\\00a0\\00a0\\e830\";\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle:after,\nhtml[data-debug-view] #debug-bar-views-toggle:after {\n\tcontent: \"\\00a0\\00a0\\e831\";\n}\n\n\n/*\n\tDefault debug view styles.\n*/\nhtml[data-debug-view] .debug {\n\tpadding: 0.25em;\n\tbackground-color: #234; /* #541, #151 */\n}\nhtml[data-debug-view] .debug[title] {\n\tcursor: help;\n}\nhtml[data-debug-view] .debug.block {\n\tdisplay: inline-block;\n\tvertical-align: middle;\n}\nhtml[data-debug-view] .debug.invalid {\n\ttext-decoration: line-through;\n}\nhtml[data-debug-view] .debug.hidden,\nhtml[data-debug-view] .debug.hidden .debug {\n\tbackground-color: #555;\n}\nhtml:not([data-debug-view]) .debug.hidden {\n\tdisplay: none;\n}\n\nhtml[data-debug-view] .debug[data-name][data-type]:before,\nhtml[data-debug-view] .debug[data-name][data-type].nonvoid:after {\n\tbackground-color: rgba(0,0,0,0.25);\n\tfont-family: monospace, monospace;\n\twhite-space: pre;\n}\nhtml[data-debug-view] .debug[data-name][data-type]:before {\n\tcontent: attr(data-name);\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"macro\"]:before {\n\tcontent: \"<<\" attr(data-name) \">>\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"macro\"].nonvoid:after {\n\tcontent: \"<</\" attr(data-name) \">>\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"html\"]:before {\n\tcontent: \"<\" attr(data-name) \">\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"html\"].nonvoid:after {\n\tcontent: \"</\" attr(data-name) \">\";\n}\nhtml[data-debug-view] .debug[data-name][data-type]:not(:empty):before {\n\tmargin-right: 0.25em;\n}\nhtml[data-debug-view] .debug[data-name][data-type].nonvoid:not(:empty):after {\n\tmargin-left: 0.25em;\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"special\"],\nhtml[data-debug-view] .debug[data-name][data-type|=\"special\"]:before {\n\tdisplay: block;\n}\n</style>\n</head>\n<body>\n\t<div id=\"init-screen\">\n\t\t<div id=\"init-no-js\"><noscript>JavaScript is required. Please enable it to continue.</noscript></div>\n\t\t<div id=\"init-lacking\">Your browser lacks required capabilities. Please upgrade it or switch to another to continue.</div>\n\t\t<div id=\"init-loading\"><div>Loading&hellip;</div></div>\n\t</div>\n\t{{STORY_DATA}}\n\t<script id=\"script-sugarcube\" type=\"text/javascript\">\n\t/*! SugarCube JS */\n\tif(document.documentElement.getAttribute(\"data-init\")===\"loading\"){window.TWINE1=false;\nwindow.DEBUG=false;\n(function (window, document, jQuery, undefined) {\n\"use strict\";\n\n/***********************************************************************************************************************\n\n\tlib/alert.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tTODO: This regular expression should be elsewhere.\n\n\tError prologs by engine/browser: (ca. 2018)\n\t\tChrome, Opera, & Vivaldi → `Uncaught \\w*Error: …`\n\t\tEdge & IE                → `…`\n\t\tFirefox                  → `Error: …`\n\t\tOpera (Presto)           → `Uncaught exception: \\w*(?:Error|Exception): …`\n\t\tSafari (ca. v5.1)        → `\\w*(?:Error|_ERR): …`\n*/\nvar errorPrologRegExp = /^(?:(?:uncaught\\s+(?:exception:\\s+)?)?\\w*(?:error|exception|_err):\\s+)+/i; // eslint-disable-line no-unused-vars, no-var\n\nvar Alert = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tError Functions.\n\t*******************************************************************************************************************/\n\tfunction _alertMesg(type, where, what, error) {\n\t\tconst isFatal = type === 'fatal';\n\t\tlet mesg = `Apologies! ${isFatal ? 'A fatal' : 'An'} error has occurred.`;\n\n\t\tif (isFatal) {\n\t\t\tmesg += ' Aborting.';\n\t\t}\n\t\telse {\n\t\t\tmesg += ' You may be able to continue, but some parts may not work properly.';\n\t\t}\n\n\t\tif (where != null || what != null) { // lazy equality for null\n\t\t\tmesg += '\\n\\nError';\n\n\t\t\tif (where != null) { // lazy equality for null\n\t\t\t\tmesg += ` [${where}]`;\n\t\t\t}\n\n\t\t\tif (what != null) { // lazy equality for null\n\t\t\t\tmesg += `: ${what.replace(errorPrologRegExp, '')}.`;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tmesg += ': unknown error.';\n\t\t\t}\n\t\t}\n\n\t\tif (typeof error === 'object' && error !== null && error.stack) {\n\t\t\tmesg += `\\n\\nStack Trace:\\n${error.stack}`;\n\t\t}\n\n\t\twindow.alert(mesg); // eslint-disable-line no-alert\n\t}\n\n\tfunction alertError(where, what, error) {\n\t\t_alertMesg(null, where, what, error);\n\t}\n\n\tfunction alertFatal(where, what, error) {\n\t\t_alertMesg('fatal', where, what, error);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tError Event.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSet up a global error handler for uncaught exceptions.\n\t*/\n\t(origOnError => {\n\t\twindow.onerror = function (what, source, lineNum, colNum, error) {\n\t\t\t// Uncaught exceptions during play may be recoverable/ignorable.\n\t\t\tif (document.readyState === 'complete') {\n\t\t\t\talertError(null, what, error);\n\t\t\t}\n\n\t\t\t// Uncaught exceptions during startup should be fatal.\n\t\t\telse {\n\t\t\t\talertFatal(null, what, error);\n\t\t\t\twindow.onerror = origOnError;\n\n\t\t\t\tif (typeof window.onerror === 'function') {\n\t\t\t\t\twindow.onerror.apply(this, arguments);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t})(window.onerror);\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\terror : { value : alertError },\n\t\tfatal : { value : alertFatal }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/patterns.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tTODO: Move all markup patterns into here.\n*/\n\nvar Patterns = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tPatterns.\n\t*******************************************************************************************************************/\n\t/*\n\t\tWhitespace patterns.\n\n\t\tSpace class (equivalent to `\\s`):\n\t\t\t[\\u0020\\f\\n\\r\\t\\v\\u00a0\\u1680\\u180e\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000\\ufeff]\n\t\tSpace class, sans line terminators:\n\t\t\t[\\u0020\\f\\t\\v\\u00a0\\u1680\\u180e\\u2000-\\u200a\\u202f\\u205f\\u3000\\ufeff]\n\t\tLine Terminator class:\n\t\t\t[\\n\\r\\u2028\\u2029]\n\t*/\n\tconst space = (() => {\n\t\t/*\n\t\t\tSome browsers still supported by SugarCube have faulty space classes (`\\s`).\n\t\t\tWe check for that lossage here and, if necessary, build our own class from\n\t\t\tthe component pieces.\n\t\t*/\n\t\tconst wsMap = new Map([\n\t\t\t['\\u0020', '\\\\u0020'],\n\t\t\t['\\f', '\\\\f'],\n\t\t\t['\\n', '\\\\n'],\n\t\t\t['\\r', '\\\\r'],\n\t\t\t['\\t', '\\\\t'],\n\t\t\t['\\v', '\\\\v'],\n\t\t\t['\\u00a0', '\\\\u00a0'],\n\t\t\t['\\u1680', '\\\\u1680'],\n\t\t\t['\\u180e', '\\\\u180e'],\n\t\t\t['\\u2000', '\\\\u2000'],\n\t\t\t['\\u2001', '\\\\u2001'],\n\t\t\t['\\u2002', '\\\\u2002'],\n\t\t\t['\\u2003', '\\\\u2003'],\n\t\t\t['\\u2004', '\\\\u2004'],\n\t\t\t['\\u2005', '\\\\u2005'],\n\t\t\t['\\u2006', '\\\\u2006'],\n\t\t\t['\\u2007', '\\\\u2007'],\n\t\t\t['\\u2008', '\\\\u2008'],\n\t\t\t['\\u2009', '\\\\u2009'],\n\t\t\t['\\u200a', '\\\\u200a'],\n\t\t\t['\\u2028', '\\\\u2028'],\n\t\t\t['\\u2029', '\\\\u2029'],\n\t\t\t['\\u202f', '\\\\u202f'],\n\t\t\t['\\u205f', '\\\\u205f'],\n\t\t\t['\\u3000', '\\\\u3000'],\n\t\t\t['\\ufeff', '\\\\ufeff']\n\t\t]);\n\t\tconst wsRe = /^\\s$/;\n\t\tlet missing = '';\n\n\t\twsMap.forEach((pat, char) => {\n\t\t\tif (!wsRe.test(char)) {\n\t\t\t\tmissing += pat;\n\t\t\t}\n\t\t});\n\n\t\treturn missing ? `[\\\\s${missing}]` : '\\\\s';\n\t})();\n\tconst spaceNoTerminator = '[\\\\u0020\\\\f\\\\t\\\\v\\\\u00a0\\\\u1680\\\\u180e\\\\u2000-\\\\u200a\\\\u202f\\\\u205f\\\\u3000\\\\ufeff]';\n\tconst lineTerminator    = '[\\\\n\\\\r\\\\u2028\\\\u2029]';\n\tconst notSpace          = space === '\\\\s' ? '\\\\S' : space.replace(/^\\[/, '[^');\n\n\t/*\n\t\tCharacter patterns.\n\t*/\n\tconst anyChar = `(?:.|${lineTerminator})`;\n\n\t/*\n\t\tLetter patterns.\n\n\t\tFIXME:\n\t\t\t1. The existing set, which is a TiddlyWiki holdover, should probably\n\t\t\t   encompass a significantly greater range of BMP code points.\n\t\t\t2. Should we include the surrogate pair code units (\\uD800-\\uDBFF &\n\t\t\t   \\uDC00-\\uDFFF) to handle non-BMP code points?  Further, should we\n\t\t\t   simply be checking for the code units themselves or checking for\n\t\t\t   properly mated pairs?\n\t*/\n\tconst anyLetter       = '[0-9A-Z_a-z\\\\-\\\\u00c0-\\\\u00d6\\\\u00d8-\\\\u00f6\\\\u00f8-\\\\u00ff\\\\u0150\\\\u0170\\\\u0151\\\\u0171]';\n\tconst anyLetterStrict = anyLetter.replace('\\\\-', ''); // anyLetter sans hyphen\n\n\t/*\n\t\tIdentifier patterns.\n\n\t\tNOTE: Since JavaScript's RegExp syntax does not support Unicode character\n\t\tclasses, the correct regular expression to match a valid identifier name,\n\t\twithin the scope of our needs, would be on the order of approximately 5–6\n\t\tor 11–16 KiB, depending on how the pattern was built.  That being the case,\n\t\tfor the moment we restrict valid TwineScript identifiers to US-ASCII.\n\n\t\tFIXME: Fix this to, at least, approximate the correct range.\n\t*/\n\tconst identifierFirstChar = '[$A-Z_a-z]';\n\tconst identifierNextChar  = '[$0-9A-Z_a-z]';\n\tconst identifier          = `${identifierFirstChar}${identifierNextChar}*`;\n\n\t// Variable patterns.\n\tconst variableSigil = '[$_]';\n\tconst variable      = variableSigil + identifier;\n\n\t// Macro name pattern.\n\tconst macroName = '[A-Za-z][\\\\w-]*|[=-]';\n\n\t// Template name pattern.\n\tconst templateName = '[A-Za-z][\\\\w-]*';\n\n\t// CSS ID or class sigil pattern.\n\tconst cssIdOrClassSigil = '[#.]';\n\n\t// CSS image transclusion template pattern.\n\t//\n\t// NOTE: The alignment syntax isn't supported, but removing it might break uses\n\t// of the template in the wild, so we leave it alone for now.\n\tconst cssImage = '\\\\[[<>]?[Ii][Mm][Gg]\\\\[(?:\\\\s|\\\\S)*?\\\\]\\\\]+';\n\n\t// Inline CSS pattern.\n\tconst inlineCss = (() => {\n\t\t/* legacy */\n\t\tconst twStyle   = `(${anyLetter}+)\\\\(([^\\\\)\\\\|\\\\n]+)\\\\):`;\n\t\t/* /legacy */\n\t\tconst cssStyle  = `${spaceNoTerminator}*(${anyLetter}+)${spaceNoTerminator}*:([^;\\\\|\\\\n]+);`;\n\t\tconst idOrClass = `${spaceNoTerminator}*((?:${cssIdOrClassSigil}${anyLetter}+${spaceNoTerminator}*)+);`;\n\n\t\t// [1,2] = style(value):\n\t\t// [3,4] = style:value;\n\t\t// [5]   = #id.className;\n\t\treturn `${twStyle}|${cssStyle}|${idOrClass}`;\n\t})();\n\n\t// URL pattern.\n\tconst url = '(?:file|https?|mailto|ftp|javascript|irc|news|data):[^\\\\s\\'\"]+';\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze({\n\t\tspace,\n\t\tspaceNoTerminator,\n\t\tlineTerminator,\n\t\tnotSpace,\n\t\tanyChar,\n\t\tanyLetter,\n\t\tanyLetterStrict,\n\t\tidentifierFirstChar,\n\t\tidentifierNextChar,\n\t\tidentifier,\n\t\tvariableSigil,\n\t\tvariable,\n\t\tmacroName,\n\t\ttemplateName,\n\t\tcssIdOrClassSigil,\n\t\tcssImage,\n\t\tinlineCss,\n\t\turl\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/extensions.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns */\n\n/*\n\tJavaScript Polyfills.\n\n\tNOTE: The ES5 and ES6 polyfills come from the vendored `es5-shim.js` and `es6-shim.js` libraries.\n*/\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tTrims whitespace from either the start or end of the given string.\n\t*/\n\tconst _trimString = (() => {\n\t\t// Whitespace regular expressions.\n\t\tconst startWSRe = new RegExp(`^${Patterns.space}${Patterns.space}*`);\n\t\tconst endWSRe   = new RegExp(`${Patterns.space}${Patterns.space}*$`);\n\n\t\tfunction trimString(str, where) {\n\t\t\tconst val = String(str);\n\n\t\t\tif (!val) {\n\t\t\t\treturn val;\n\t\t\t}\n\n\t\t\tswitch (where) {\n\t\t\tcase 'start':\n\t\t\t\treturn startWSRe.test(val) ? val.replace(startWSRe, '') : val;\n\n\t\t\tcase 'end':\n\t\t\t\treturn endWSRe.test(val) ? val.replace(endWSRe, '') : val;\n\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`_trimString called with incorrect where parameter value: \"${where}\"`);\n\t\t\t}\n\t\t}\n\n\t\treturn trimString;\n\t})();\n\n\t/*\n\t\tGenerates a pad string based upon the given string and length.\n\t*/\n\tfunction _createPadString(length, padding) {\n\t\tconst targetLength = Number.parseInt(length, 10) || 0;\n\n\t\tif (targetLength < 1) {\n\t\t\treturn '';\n\t\t}\n\n\t\tlet padString = typeof padding === 'undefined' ? '' : String(padding);\n\n\t\tif (padString === '') {\n\t\t\tpadString = ' ';\n\t\t}\n\n\t\twhile (padString.length < targetLength) {\n\t\t\tconst curPadLength    = padString.length;\n\t\t\tconst remainingLength = targetLength - curPadLength;\n\n\t\t\tpadString += curPadLength > remainingLength\n\t\t\t\t? padString.slice(0, remainingLength)\n\t\t\t\t: padString;\n\t\t}\n\n\t\tif (padString.length > targetLength) {\n\t\t\tpadString = padString.slice(0, targetLength);\n\t\t}\n\n\t\treturn padString;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPolyfills.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[ES2019] Returns a new array consisting of the source array with all sub-array elements\n\t\tconcatenated into it recursively up to the given depth.\n\t*/\n\tif (!Array.prototype.flat) {\n\t\tObject.defineProperty(Array.prototype, 'flat', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\t\t\tvalue        : (() => {\n\t\t\t\tfunction flat(/* depth */) {\n\t\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\t\tthrow new TypeError('Array.prototype.flat called on null or undefined');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst depth = arguments.length === 0 ? 1 : Number(arguments[0]) || 0;\n\n\t\t\t\t\tif (depth < 1) {\n\t\t\t\t\t\treturn Array.prototype.slice.call(this);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn Array.prototype.reduce.call(\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\t(acc, cur) => {\n\t\t\t\t\t\t\tif (cur instanceof Array) {\n\t\t\t\t\t\t\t\t// acc.push.apply(acc, flat.call(cur, depth - 1));\n\t\t\t\t\t\t\t\tacc.push(...flat.call(cur, depth - 1));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tacc.push(cur);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn acc;\n\t\t\t\t\t\t},\n\t\t\t\t\t\t[]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn flat;\n\t\t\t})()\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a new array consisting of the result of calling the given mapping function\n\t\ton every element in the source array and then concatenating all sub-array elements into it\n\t\trecursively up to a depth of `1`.  Identical to calling `<Array>.map(fn).flat()`.\n\t*/\n\tif (!Array.prototype.flatMap) {\n\t\tObject.defineProperty(Array.prototype, 'flatMap', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(/* callback [, thisArg] */) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Array.prototype.flatMap called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.map.apply(this, arguments).flat();\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2016] Returns whether the given element was found within the array.\n\t*/\n\tif (!Array.prototype.includes) {\n\t\tObject.defineProperty(Array.prototype, 'includes', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Array.prototype.includes called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tif (arguments.length === 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst length = this.length >>> 0;\n\n\t\t\t\tif (length === 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst needle = arguments[0];\n\t\t\t\tlet i = Number(arguments[1]) || 0;\n\n\t\t\t\tif (i < 0) {\n\t\t\t\t\ti = Math.max(0, length + i);\n\t\t\t\t}\n\n\t\t\t\tfor (/* empty */; i < length; ++i) {\n\t\t\t\t\tconst value = this[i];\n\n\t\t\t\t\tif (value === needle || value !== value && needle !== needle) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a new array consisting of the given object's own enumerable property/value\n\t\tpairs as `[key, value]` arrays.\n\t*/\n\tif (!Object.entries) {\n\t\tObject.defineProperty(Object, 'entries', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (typeof obj !== 'object' || obj === null) {\n\t\t\t\t\tthrow new TypeError('Object.entries object parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\treturn Object.keys(obj).map(key => [key, obj[key]]);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a new generic object consisting of the given list's key/value pairs.\n\t*/\n\tif (!Object.fromEntries) {\n\t\tObject.defineProperty(Object, 'fromEntries', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(iter) {\n\t\t\t\treturn Array.from(iter).reduce(\n\t\t\t\t\t(acc, pair) => {\n\t\t\t\t\t\tif (Object(pair) !== pair) {\n\t\t\t\t\t\t\tthrow new TypeError('Object.fromEntries iterable parameter must yield objects');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (pair[0] in acc) {\n\t\t\t\t\t\t\tObject.defineProperty(acc, pair[0], {\n\t\t\t\t\t\t\t\tconfigurable : true,\n\t\t\t\t\t\t\t\tenumerable   : true,\n\t\t\t\t\t\t\t\twritable     : true,\n\t\t\t\t\t\t\t\tvalue        : pair[1]\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tacc[pair[0]] = pair[1]; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{}\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns all own property descriptors of the given object.\n\t*/\n\tif (!Object.getOwnPropertyDescriptors) {\n\t\tObject.defineProperty(Object, 'getOwnPropertyDescriptors', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (obj == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Object.getOwnPropertyDescriptors object parameter is null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst O = Object(obj);\n\n\t\t\t\treturn Reflect.ownKeys(O).reduce(\n\t\t\t\t\t(acc, key) => {\n\t\t\t\t\t\tconst desc = Object.getOwnPropertyDescriptor(O, key);\n\n\t\t\t\t\t\tif (typeof desc !== 'undefined') {\n\t\t\t\t\t\t\tif (key in acc) {\n\t\t\t\t\t\t\t\tObject.defineProperty(acc, key, {\n\t\t\t\t\t\t\t\t\tconfigurable : true,\n\t\t\t\t\t\t\t\t\tenumerable   : true,\n\t\t\t\t\t\t\t\t\twritable     : true,\n\t\t\t\t\t\t\t\t\tvalue        : desc\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tacc[key] = desc; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{}\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a new array consisting of the given object's own enumerable property values.\n\t*/\n\tif (!Object.values) {\n\t\tObject.defineProperty(Object, 'values', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (typeof obj !== 'object' || obj === null) {\n\t\t\t\t\tthrow new TypeError('Object.values object parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\treturn Object.keys(obj).map(key => obj[key]);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a string based on concatenating the given padding, repeated as necessary,\n\t\tto the start of the string so that the given length is reached.\n\n\t\tNOTE: This pads based upon Unicode code units, rather than code points.\n\t*/\n\tif (!String.prototype.padStart) {\n\t\tObject.defineProperty(String.prototype, 'padStart', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(length, padding) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.padStart called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst baseString   = String(this);\n\t\t\t\tconst baseLength   = baseString.length;\n\t\t\t\tconst targetLength = Number.parseInt(length, 10);\n\n\t\t\t\tif (targetLength <= baseLength) {\n\t\t\t\t\treturn baseString;\n\t\t\t\t}\n\n\t\t\t\treturn _createPadString(targetLength - baseLength, padding) + baseString;\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a string based on concatenating the given padding, repeated as necessary,\n\t\tto the end of the string so that the given length is reached.\n\n\t\tNOTE: This pads based upon Unicode code units, rather than code points.\n\t*/\n\tif (!String.prototype.padEnd) {\n\t\tObject.defineProperty(String.prototype, 'padEnd', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(length, padding) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.padEnd called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst baseString   = String(this);\n\t\t\t\tconst baseLength   = baseString.length;\n\t\t\t\tconst targetLength = Number.parseInt(length, 10);\n\n\t\t\t\tif (targetLength <= baseLength) {\n\t\t\t\t\treturn baseString;\n\t\t\t\t}\n\n\t\t\t\treturn baseString + _createPadString(targetLength - baseLength, padding);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a string with all whitespace removed from the start of the string.\n\t*/\n\tif (!String.prototype.trimStart) {\n\t\tObject.defineProperty(String.prototype, 'trimStart', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimStart called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'start');\n\t\t\t}\n\t\t});\n\t}\n\n\tif (!String.prototype.trimLeft) {\n\t\tObject.defineProperty(String.prototype, 'trimLeft', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimLeft called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'start');\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a string with all whitespace removed from the end of the string.\n\t*/\n\tif (!String.prototype.trimEnd) {\n\t\tObject.defineProperty(String.prototype, 'trimEnd', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimEnd called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'end');\n\t\t\t}\n\t\t});\n\t}\n\n\tif (!String.prototype.trimRight) {\n\t\tObject.defineProperty(String.prototype, 'trimRight', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimRight called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'end');\n\t\t\t}\n\t\t});\n\t}\n})();\n\n\n/*\n\tJavaScript Extensions.\n*/\n(() => {\n\t'use strict';\n\n\tconst _nativeMathRandom = Math.random;\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a pseudo-random whole number (integer) within the given bounds.\n\t*/\n\tfunction _random(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('_random called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = arguments[0];\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = arguments[0];\n\t\t\tmax = arguments[1];\n\t\t\tbreak;\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn Math.floor(_nativeMathRandom() * (max - min + 1)) + min;\n\t}\n\n\t/*\n\t\tReturns a randomly selected index within the given length and bounds.\n\t\tBounds may be negative.\n\t*/\n\tfunction _randomIndex(length, boundsArgs) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (boundsArgs.length) {\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = length - 1;\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tmin = 0;\n\t\t\tmax = Math.trunc(boundsArgs[1]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Math.trunc(boundsArgs[1]);\n\t\t\tmax = Math.trunc(boundsArgs[2]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (Number.isNaN(min)) {\n\t\t\tmin = 0;\n\t\t}\n\t\telse if (!Number.isFinite(min) || min >= length) {\n\t\t\tmin = length - 1;\n\t\t}\n\t\telse if (min < 0) {\n\t\t\tmin = length + min;\n\n\t\t\tif (min < 0) {\n\t\t\t\tmin = 0;\n\t\t\t}\n\t\t}\n\n\t\tif (Number.isNaN(max)) {\n\t\t\tmax = 0;\n\t\t}\n\t\telse if (!Number.isFinite(max) || max >= length) {\n\t\t\tmax = length - 1;\n\t\t}\n\t\telse if (max < 0) {\n\t\t\tmax = length + max;\n\n\t\t\tif (max < 0) {\n\t\t\t\tmax = length - 1;\n\t\t\t}\n\t\t}\n\n\t\treturn _random(min, max);\n\t}\n\n\t/*\n\t\tReturns an object (`{ char, start, end }`) containing the Unicode character at\n\t\tposition `pos`, its starting position, and its ending position—surrogate pairs\n\t\tare properly handled.  If `pos` is out-of-bounds, returns an object containing\n\t\tthe empty string and start/end positions of `-1`.\n\n\t\tThis function is necessary because JavaScript strings are sequences of UTF-16\n\t\tcode units, so surrogate pairs are exposed and thus must be handled.  While the\n\t\tES6/2015 standard does improve the situation somewhat, it does not alleviate\n\t\tthe need for this function.\n\n\t\tNOTE: Will throw exceptions on invalid surrogate pairs.\n\n\t\tIDEA: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt\n\t*/\n\tfunction _getCodePointStartAndEnd(str, pos) {\n\t\tconst code = str.charCodeAt(pos);\n\n\t\t// Given position was out-of-bounds.\n\t\tif (Number.isNaN(code)) {\n\t\t\treturn { char : '', start : -1, end : -1 };\n\t\t}\n\n\t\t// Code unit is not a UTF-16 surrogate.\n\t\tif (code < 0xD800 || code > 0xDFFF) {\n\t\t\treturn {\n\t\t\t\tchar  : str.charAt(pos),\n\t\t\t\tstart : pos,\n\t\t\t\tend   : pos\n\t\t\t};\n\t\t}\n\n\t\t// Code unit is a high surrogate (D800–DBFF).\n\t\tif (code >= 0xD800 && code <= 0xDBFF) {\n\t\t\tconst nextPos = pos + 1;\n\n\t\t\t// End of string.\n\t\t\tif (nextPos >= str.length) {\n\t\t\t\tthrow new Error('high surrogate without trailing low surrogate');\n\t\t\t}\n\n\t\t\tconst nextCode = str.charCodeAt(nextPos);\n\n\t\t\t// Next code unit is not a low surrogate (DC00–DFFF).\n\t\t\tif (nextCode < 0xDC00 || nextCode > 0xDFFF) {\n\t\t\t\tthrow new Error('high surrogate without trailing low surrogate');\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tchar  : str.charAt(pos) + str.charAt(nextPos),\n\t\t\t\tstart : pos,\n\t\t\t\tend   : nextPos\n\t\t\t};\n\t\t}\n\n\t\t// Code unit is a low surrogate (DC00–DFFF) in the first position.\n\t\tif (pos === 0) {\n\t\t\tthrow new Error('low surrogate without leading high surrogate');\n\t\t}\n\n\t\tconst prevPos  = pos - 1;\n\t\tconst prevCode = str.charCodeAt(prevPos);\n\n\t\t// Previous code unit is not a high surrogate (D800–DBFF).\n\t\tif (prevCode < 0xD800 || prevCode > 0xDBFF) {\n\t\t\tthrow new Error('low surrogate without leading high surrogate');\n\t\t}\n\n\t\treturn {\n\t\t\tchar  : str.charAt(prevPos) + str.charAt(pos),\n\t\t\tstart : prevPos,\n\t\t\tend   : pos\n\t\t};\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, General.\n\t*******************************************************************************************************************/\n\t/*\n\t\tRandomly selects an element from the given array, or array-like object, and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array, 'random', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(array /* DEPRECATED: [, [min ,] max] */) {\n\t\t\tif (\n\t\t\t\t   typeof array !== 'object'\n\t\t\t\t|| array === null\n\t\t\t\t|| !Object.prototype.hasOwnProperty.call(array, 'length')\n\t\t\t) {\n\t\t\t\tthrow new TypeError('Array.random array parameter must be an array or array-lke object');\n\t\t\t}\n\n\t\t\tconst length = array.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, Array.prototype.slice.call(arguments, 1));\n\n\t\t\treturn array[index];\n\t\t}\n\t});\n\n\t/*\n\t\tConcatenates one or more unique elements to the end of the base array\n\t\tand returns the result as a new array.  Elements which are arrays will\n\t\tbe merged—i.e. their elements will be concatenated, rather than the\n\t\tarray itself.\n\t*/\n\tObject.defineProperty(Array.prototype, 'concatUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.concatUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst result = Array.from(this);\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tconst items   = Array.prototype.reduce.call(arguments, (prev, cur) => prev.concat(cur), []);\n\t\t\tconst addSize = items.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst push    = Array.prototype.push;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = items[i];\n\n\t\t\t\tif (indexOf.call(result, value) === -1) {\n\t\t\t\t\tpush.call(result, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number of times the given element was found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'count', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex ] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.count called on null or undefined');\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst needle  = arguments[0];\n\t\t\tlet pos   = Number(arguments[1]) || 0;\n\t\t\tlet count = 0;\n\n\t\t\twhile ((pos = indexOf.call(this, needle, pos)) !== -1) {\n\t\t\t\t++count;\n\t\t\t\t++pos;\n\t\t\t}\n\n\t\t\treturn count;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the given elements from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'delete', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.delete called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst needles       = Array.prototype.concat.apply([], arguments);\n\t\t\tconst needlesLength = needles.length;\n\t\t\tconst indices       = [];\n\n\t\t\tfor (let i = 0; i < length; ++i) {\n\t\t\t\tconst value = this[i];\n\n\t\t\t\tfor (let j = 0; j < needlesLength; ++j) {\n\t\t\t\t\tconst needle = needles[j];\n\n\t\t\t\t\tif (value === needle || value !== value && needle !== needle) {\n\t\t\t\t\t\tindices.push(i);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst result = [];\n\n\t\t\t// Copy the elements (in original order).\n\t\t\tfor (let i = 0, iend = indices.length; i < iend; ++i) {\n\t\t\t\tresult[i] = this[indices[i]];\n\t\t\t}\n\n\t\t\tconst splice = Array.prototype.splice;\n\n\t\t\t// Delete the elements (in reverse order).\n\t\t\tfor (let i = indices.length - 1; i >= 0; --i) {\n\t\t\t\tsplice.call(this, indices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the elements at the given indices from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'deleteAt', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* indices */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.deleteAt called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst splice     = Array.prototype.splice;\n\t\t\tconst cpyIndices = [\n\t\t\t\t...(new Set(\n\t\t\t\t\tArray.prototype.concat.apply([], arguments)\n\t\t\t\t\t\t// Map negative indices to their positive counterparts,\n\t\t\t\t\t\t// so the Set can properly filter out duplicates.\n\t\t\t\t\t\t.map(x => x < 0 ? Math.max(0, length + x) : x)\n\t\t\t\t)).values()\n\t\t\t];\n\t\t\tconst delIndices = [...cpyIndices].sort((a, b) => b - a);\n\t\t\tconst result     = [];\n\n\t\t\t// Copy the elements (in originally specified order).\n\t\t\tfor (let i = 0, iend = cpyIndices.length; i < iend; ++i) {\n\t\t\t\tresult[i] = this[cpyIndices[i]];\n\t\t\t}\n\n\t\t\t// Delete the elements (in descending numeric order).\n\t\t\tfor (let i = 0, iend = delIndices.length; i < iend; ++i) {\n\t\t\t\tsplice.call(this, delIndices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the elements that pass the test implemented\n\t\tby the given predicate function from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'deleteWith', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(predicate, thisArg) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.deleteWith called on null or undefined');\n\t\t\t}\n\t\t\tif (typeof predicate !== 'function') {\n\t\t\t\tthrow new Error('Array.prototype.deleteWith predicate parameter must be a function');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst splice  = Array.prototype.splice;\n\t\t\tconst indices = [];\n\t\t\tconst result  = [];\n\n\t\t\t// Copy the elements (in original order).\n\t\t\tfor (let i = 0; i < length; ++i) {\n\t\t\t\tif (predicate.call(thisArg, this[i], i, this)) {\n\t\t\t\t\tresult.push(this[i]);\n\t\t\t\t\tindices.push(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Delete the elements (in reverse order).\n\t\t\tfor (let i = indices.length - 1; i >= 0; --i) {\n\t\t\t\tsplice.call(this, indices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the first element from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'first', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.first called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn this[0];\n\t\t}\n\t});\n\n\t/*\n\t\tReturns whether all of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'includesAll', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.includesAll called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 1) {\n\t\t\t\tif (Array.isArray(arguments[0])) {\n\t\t\t\t\treturn Array.prototype.includesAll.apply(this, arguments[0]);\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = arguments.length; i < iend; ++i) {\n\t\t\t\tif (\n\t\t\t\t\t!Array.prototype.some.call(this, function (val) {\n\t\t\t\t\t\treturn val === this.val || val !== val && this.val !== this.val;\n\t\t\t\t\t}, { val : arguments[i] })\n\t\t\t\t) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns whether any of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'includesAny', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.includesAny called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 1) {\n\t\t\t\tif (Array.isArray(arguments[0])) {\n\t\t\t\t\treturn Array.prototype.includesAny.apply(this, arguments[0]);\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = arguments.length; i < iend; ++i) {\n\t\t\t\tif (\n\t\t\t\t\tArray.prototype.some.call(this, function (val) {\n\t\t\t\t\t\treturn val === this.val || val !== val && this.val !== this.val;\n\t\t\t\t\t}, { val : arguments[i] })\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the last element from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'last', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.last called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn this[length - 1];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly removes an element from the base array and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pluck', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* DEPRECATED: [min ,] max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pluck called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, [...arguments]);\n\n\t\t\treturn Array.prototype.splice.call(this, index, 1)[0];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly removes the given number of unique elements from the base array\n\t\tand returns the removed elements as a new array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pluckMany', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(wantSize) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pluckMany called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tlet want = Math.trunc(wantSize);\n\n\t\t\tif (!Number.isInteger(want)) {\n\t\t\t\tthrow new Error('Array.prototype.pluckMany want parameter must be an integer');\n\t\t\t}\n\n\t\t\tif (want < 1) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif (want > length) {\n\t\t\t\twant = length;\n\t\t\t}\n\n\t\t\tconst splice = Array.prototype.splice;\n\t\t\tconst result = [];\n\t\t\tlet max = length - 1;\n\n\t\t\tdo {\n\t\t\t\tresult.push(splice.call(this, _random(0, max--), 1)[0]);\n\t\t\t} while (result.length < want);\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tAppends one or more unique elements to the end of the base array and\n\t\treturns its new length.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pushUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pushUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst addSize = arguments.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn this.length >>> 0;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst push    = Array.prototype.push;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = arguments[i];\n\n\t\t\t\tif (indexOf.call(this, value) === -1) {\n\t\t\t\t\tpush.call(this, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.length >>> 0;\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly selects an element from the base array and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array.prototype, 'random', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* DEPRECATED: [min ,] max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.random called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, [...arguments]);\n\n\t\t\treturn this[index];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly selects the given number of unique elements from the base array\n\t\tand returns the selected elements as a new array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'randomMany', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(wantSize) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.randomMany called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tlet want = Math.trunc(wantSize);\n\n\t\t\tif (!Number.isInteger(want)) {\n\t\t\t\tthrow new Error('Array.prototype.randomMany want parameter must be an integer');\n\t\t\t}\n\n\t\t\tif (want < 1) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif (want > length) {\n\t\t\t\twant = length;\n\t\t\t}\n\n\t\t\tconst picked = new Map();\n\t\t\tconst result = [];\n\t\t\tconst max    = length - 1;\n\n\t\t\tdo {\n\t\t\t\tlet i;\n\t\t\t\tdo {\n\t\t\t\t\ti = _random(0, max);\n\t\t\t\t} while (picked.has(i));\n\t\t\t\tpicked.set(i, true);\n\t\t\t\tresult.push(this[i]);\n\t\t\t} while (result.length < want);\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly shuffles the array and returns it.\n\t*/\n\tObject.defineProperty(Array.prototype, 'shuffle', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.shuffle called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tfor (let i = length - 1; i > 0; --i) {\n\t\t\t\tconst j = Math.floor(_nativeMathRandom() * (i + 1));\n\n\t\t\t\tif (i === j) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// [this[i], this[j]] = [this[j], this[i]];\n\t\t\t\tconst swap = this[i];\n\t\t\t\tthis[i] = this[j];\n\t\t\t\tthis[j] = swap;\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\t});\n\n\t/*\n\t\tPrepends one or more unique elements to the beginning of the base array\n\t\tand returns its new length.\n\t*/\n\tObject.defineProperty(Array.prototype, 'unshiftUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.unshiftUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst addSize = arguments.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn this.length >>> 0;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst unshift = Array.prototype.unshift;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = arguments[i];\n\n\t\t\t\tif (indexOf.call(this, value) === -1) {\n\t\t\t\t\tunshift.call(this, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.length >>> 0;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a bound function that supplies the given arguments to the base\n\t\tfunction, followed by the arguments are supplied to the bound function,\n\t\twhenever it is called.\n\t*/\n\tObject.defineProperty(Function.prototype, 'partial', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Function.prototype.partial called on null or undefined');\n\t\t\t}\n\n\t\t\tconst slice = Array.prototype.slice;\n\t\t\tconst fn    = this;\n\t\t\tconst bound = slice.call(arguments, 0);\n\n\t\t\treturn function () {\n\t\t\t\tconst applied = [];\n\t\t\t\tlet argc = 0;\n\n\t\t\t\tfor (let i = 0; i < bound.length; ++i) {\n\t\t\t\t\tapplied.push(bound[i] === undefined ? arguments[argc++] : bound[i]);\n\t\t\t\t}\n\n\t\t\t\treturn fn.apply(this, applied.concat(slice.call(arguments, argc)));\n\t\t\t};\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the given numerical clamped to the specified bounds.\n\t*/\n\tObject.defineProperty(Math, 'clamp', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(num, min, max) {\n\t\t\tconst value = Number(num);\n\t\t\treturn Number.isNaN(value) ? NaN : value.clamp(min, max);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a decimal number eased from 0 to 1.\n\n\t\tNOTE: The magnitude of the returned value decreases if num < 0.5 or increases if num > 0.5.\n\t*/\n\tObject.defineProperty(Math, 'easeInOut', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(num) {\n\t\t\treturn 1 - (Math.cos(Number(num) * Math.PI) + 1) / 2;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number clamped to the specified bounds.\n\t*/\n\tObject.defineProperty(Number.prototype, 'clamp', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* min, max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Number.prototype.clamp called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length !== 2) {\n\t\t\t\tthrow new Error('Number.prototype.clamp called with an incorrect number of parameters');\n\t\t\t}\n\n\t\t\tlet min = Number(arguments[0]);\n\t\t\tlet max = Number(arguments[1]);\n\n\t\t\tif (min > max) {\n\t\t\t\t[min, max] = [max, min];\n\t\t\t}\n\n\t\t\treturn Math.min(Math.max(this, min), max);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the given string with all RegExp metacharacters escaped.\n\t*/\n\tif (!RegExp.escape) {\n\t\t(() => {\n\t\t\tconst _regExpMetaCharsRe    = /[\\\\^$*+?.()|[\\]{}]/g;\n\t\t\tconst _hasRegExpMetaCharsRe = new RegExp(_regExpMetaCharsRe.source); // to drop the global flag\n\n\t\t\tObject.defineProperty(RegExp, 'escape', {\n\t\t\t\tconfigurable : true,\n\t\t\t\twritable     : true,\n\n\t\t\t\tvalue(str) {\n\t\t\t\t\tconst val = String(str);\n\t\t\t\t\treturn val && _hasRegExpMetaCharsRe.test(val)\n\t\t\t\t\t\t? val.replace(_regExpMetaCharsRe, '\\\\$&')\n\t\t\t\t\t\t: val;\n\t\t\t\t}\n\t\t\t});\n\t\t})();\n\t}\n\n\t/*\n\t\tReturns a formatted string, after replacing each format item in the given\n\t\tformat string with the text equivalent of the corresponding argument's value.\n\t*/\n\t(() => {\n\t\tconst _formatRegExp    = /{(\\d+)(?:,([+-]?\\d+))?}/g;\n\t\tconst _hasFormatRegExp = new RegExp(_formatRegExp.source); // to drop the global flag\n\n\t\tObject.defineProperty(String, 'format', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(format) {\n\t\t\t\tfunction padString(str, align, pad) {\n\t\t\t\t\tif (!align) {\n\t\t\t\t\t\treturn str;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst plen = Math.abs(align) - str.length;\n\n\t\t\t\t\tif (plen < 1) {\n\t\t\t\t\t\treturn str;\n\t\t\t\t\t}\n\n\t\t\t\t\t// const padding = Array(plen + 1).join(pad);\n\t\t\t\t\tconst padding = String(pad).repeat(plen);\n\t\t\t\t\treturn align < 0 ? str + padding : padding + str;\n\t\t\t\t}\n\n\t\t\t\tif (arguments.length < 2) {\n\t\t\t\t\treturn arguments.length === 0 ? '' : format;\n\t\t\t\t}\n\n\t\t\t\tconst args = arguments.length === 2 && Array.isArray(arguments[1])\n\t\t\t\t\t? [...arguments[1]]\n\t\t\t\t\t: Array.prototype.slice.call(arguments, 1);\n\n\t\t\t\tif (args.length === 0) {\n\t\t\t\t\treturn format;\n\t\t\t\t}\n\n\t\t\t\tif (!_hasFormatRegExp.test(format)) {\n\t\t\t\t\treturn format;\n\t\t\t\t}\n\n\t\t\t\t// Possibly required by some old buggy browsers.\n\t\t\t\t_formatRegExp.lastIndex = 0;\n\n\t\t\t\treturn format.replace(_formatRegExp, (match, index, align) => {\n\t\t\t\t\tlet retval = args[index];\n\n\t\t\t\t\tif (retval == null) { // lazy equality for null\n\t\t\t\t\t\treturn '';\n\t\t\t\t\t}\n\n\t\t\t\t\twhile (typeof retval === 'function') {\n\t\t\t\t\t\tretval = retval();\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (typeof retval) {\n\t\t\t\t\tcase 'string': /* no-op */ break;\n\t\t\t\t\tcase 'object': retval = JSON.stringify(retval); break;\n\t\t\t\t\tdefault:       retval = String(retval); break;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn padString(retval, !align ? 0 : Number.parseInt(align, 10), ' ');\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t})();\n\n\t/*\n\t\tReturns whether the given string was found within the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'contains', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.contains called on null or undefined');\n\t\t\t}\n\n\t\t\treturn String.prototype.indexOf.apply(this, arguments) !== -1;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number of times the given substring was found within the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'count', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex ] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.count called on null or undefined');\n\t\t\t}\n\n\t\t\tconst needle = String(arguments[0] || '');\n\n\t\t\tif (needle === '') {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tconst indexOf = String.prototype.indexOf;\n\t\t\tconst step    = needle.length;\n\t\t\tlet pos     = Number(arguments[1]) || 0;\n\t\t\tlet count   = 0;\n\n\t\t\twhile ((pos = indexOf.call(this, needle, pos)) !== -1) {\n\t\t\t\t++count;\n\t\t\t\tpos += step;\n\t\t\t}\n\n\t\t\treturn count;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the first Unicode code point from the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'first', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.first called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn char;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the last Unicode code point from the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'last', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.last called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the last code point—may be one or two code units—and its end position.\n\t\t\tconst { char } = _getCodePointStartAndEnd(str, str.length - 1);\n\n\t\t\treturn char;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with `delCount` characters replaced with\n\t\t`replacement`, starting at `startAt`.\n\t*/\n\tObject.defineProperty(String.prototype, 'splice', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(startAt, delCount, replacement) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.splice called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tlet start = Number(startAt);\n\n\t\t\tif (!Number.isSafeInteger(start)) {\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t\telse if (start < 0) {\n\t\t\t\tstart += length;\n\n\t\t\t\tif (start < 0) {\n\t\t\t\t\tstart = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (start > length) {\n\t\t\t\tstart = length;\n\t\t\t}\n\n\t\t\tlet count = Number(delCount);\n\n\t\t\tif (!Number.isSafeInteger(count) || count < 0) {\n\t\t\t\tcount = 0;\n\t\t\t}\n\n\t\t\tlet res = this.slice(0, start);\n\n\t\t\tif (typeof replacement !== 'undefined') {\n\t\t\t\tres += replacement;\n\t\t\t}\n\n\t\t\tif (start + count < length) {\n\t\t\t\tres += this.slice(start + count);\n\t\t\t}\n\n\t\t\treturn res;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns an array of strings, split from the string, or an empty array if the\n\t\tstring is empty.\n\t*/\n\tObject.defineProperty(String.prototype, 'splitOrEmpty', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* [ separator [, limit ]] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.splitOrEmpty called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tif (String(this) === '') {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\treturn String.prototype.split.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with the first Unicode code point uppercased,\n\t\taccording to any locale-specific rules.\n\t*/\n\tObject.defineProperty(String.prototype, 'toLocaleUpperFirst', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.toLocaleUpperFirst called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char, end } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn end === -1 ? '' : char.toLocaleUpperCase() + str.slice(end + 1);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with the first Unicode code point uppercased.\n\t*/\n\tObject.defineProperty(String.prototype, 'toUpperFirst', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.toUpperFirst called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char, end } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn end === -1 ? '' : char.toUpperCase() + str.slice(end + 1);\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, JSON.\n\t*******************************************************************************************************************/\n\t/*\n\t\tDefine `toJSON()` methods on each prototype we wish to support.\n\t*/\n\tObject.defineProperty(Date.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:date)', this.toISOString()];\n\t\t}\n\t});\n\tObject.defineProperty(Function.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\t/*\n\t\t\t\tThe enclosing parenthesis here are necessary to force the function expression code\n\t\t\t\tstring, returned by `this.toString()`, to be evaluated as an expression during\n\t\t\t\trevival.  Without them, the function expression, which is likely nameless, will be\n\t\t\t\tevaluated as a function definition—which will throw a syntax error exception, since\n\t\t\t\tfunction definitions must have a name.\n\t\t\t*/\n\t\t\treturn ['(revive:eval)', `(${this.toString()})`];\n\t\t}\n\t});\n\tObject.defineProperty(Map.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:map)', [...this]];\n\t\t}\n\t});\n\tObject.defineProperty(RegExp.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:eval)', this.toString()];\n\t\t}\n\t});\n\tObject.defineProperty(Set.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:set)', [...this]];\n\t\t}\n\t});\n\n\t/*\n\t\tUtility method to allow users to easily wrap their code in the revive wrapper.\n\t*/\n\tObject.defineProperty(JSON, 'reviveWrapper', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(code, data) {\n\t\t\tif (typeof code !== 'string') {\n\t\t\t\tthrow new TypeError('JSON.reviveWrapper code parameter must be a string');\n\t\t\t}\n\n\t\t\treturn ['(revive:eval)', [code, data]];\n\t\t}\n\t});\n\n\t/*\n\t\tBackup the original `JSON.parse()` and replace it with a revive wrapper aware version.\n\t*/\n\tObject.defineProperty(JSON, '_real_parse', {\n\t\tvalue : JSON.parse\n\t});\n\tObject.defineProperty(JSON, 'parse', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(text, reviver) {\n\t\t\treturn JSON._real_parse(text, (key, val) => {\n\t\t\t\tlet value = val;\n\n\t\t\t\t/*\n\t\t\t\t\tAttempt to revive wrapped values.\n\t\t\t\t*/\n\t\t\t\tif (Array.isArray(value) && value.length === 2) {\n\t\t\t\t\tswitch (value[0]) {\n\t\t\t\t\tcase '(revive:set)':\n\t\t\t\t\t\tvalue = new Set(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:map)':\n\t\t\t\t\t\tvalue = new Map(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:date)':\n\t\t\t\t\t\tvalue = new Date(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:eval)':\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t/* eslint-disable no-eval */\n\t\t\t\t\t\t\t// For post-v2.9.0 `JSON.reviveWrapper()`.\n\t\t\t\t\t\t\tif (Array.isArray(value[1])) {\n\t\t\t\t\t\t\t\tconst $ReviveData$ = value[1][1]; // eslint-disable-line no-unused-vars\n\t\t\t\t\t\t\t\tvalue = eval(value[1][0]);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// For regular expressions, functions, and pre-v2.9.0 `JSON.reviveWrapper()`.\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tvalue = eval(value[1]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/* eslint-enable no-eval */\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* legacy */\n\t\t\t\telse if (typeof value === 'string' && value.slice(0, 10) === '@@revive@@') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvalue = eval(value.slice(10)); // eslint-disable-line no-eval\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t}\n\t\t\t\t/* /legacy */\n\n\t\t\t\t/*\n\t\t\t\t\tCall the custom reviver, if specified.\n\t\t\t\t*/\n\t\t\t\tif (typeof reviver === 'function') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvalue = reviver(key, value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t}\n\n\t\t\t\treturn value;\n\t\t\t});\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, Deprecated.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Returns whether the given element was found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'contains', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.contains called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns whether all of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'containsAll', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.containsAll called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includesAll.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns whether any of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'containsAny', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.containsAny called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includesAny.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns a new array consisting of the flattened source array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'flatten', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.flatten called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.flat.call(this, Infinity);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns an array of link titles, parsed from the string.\n\n\t\tNOTE: Unused in SugarCube, only included for compatibility.\n\t*/\n\tObject.defineProperty(String.prototype, 'readBracketedList', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.readBracketedList called on null or undefined');\n\t\t\t}\n\n\t\t\t// RegExp groups: Double-square-bracket quoted | Unquoted.\n\t\t\tconst re    = new RegExp('(?:\\\\[\\\\[((?:\\\\s|\\\\S)*?)\\\\]\\\\])|([^\"\\'\\\\s]\\\\S*)', 'gm');\n\t\t\tconst names = [];\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this)) !== null) {\n\t\t\t\tif (match[1]) { // double-square-bracket quoted\n\t\t\t\t\tnames.push(match[1]);\n\t\t\t\t}\n\t\t\t\telse if (match[2]) { // unquoted\n\t\t\t\t\tnames.push(match[2]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn names;\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/browser.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar Browser = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/* eslint-disable max-len */\n\tconst userAgent = navigator.userAgent.toLowerCase();\n\n\tconst winPhone = userAgent.includes('windows phone');\n\tconst isMobile = Object.freeze({\n\t\tAndroid    : !winPhone && userAgent.includes('android'),\n\t\tBlackBerry : /blackberry|bb10/.test(userAgent),\n\t\tiOS        : !winPhone && /ip(?:hone|ad|od)/.test(userAgent),\n\t\tOpera      : !winPhone && (typeof window.operamini === 'object' || userAgent.includes('opera mini')),\n\t\tWindows    : winPhone || /iemobile|wpdesktop/.test(userAgent),\n\n\t\tany() {\n\t\t\treturn isMobile.Android || isMobile.BlackBerry || isMobile.iOS || isMobile.Opera || isMobile.Windows;\n\t\t}\n\t});\n\n\tconst isGecko = !isMobile.Windows && !/khtml|trident|edge/.test(userAgent) && userAgent.includes('gecko');\n\n\tconst isIE      = !userAgent.includes('opera') && /msie|trident/.test(userAgent);\n\tconst ieVersion = isIE\n\t\t? (() => {\n\t\t\tconst ver = /(?:msie\\s+|rv:)(\\d+\\.\\d)/.exec(userAgent);\n\t\t\treturn ver ? Number(ver[1]) : 0;\n\t\t})()\n\t\t: null;\n\n\t// opera <= 12: \"opera/9.80 (windows nt 6.1; wow64) presto/2.12.388 version/12.16\"\n\t// opera >= 15: \"mozilla/5.0 (windows nt 6.1; wow64) applewebkit/537.36 (khtml, like gecko) chrome/28.0.1500.52 safari/537.36 opr/15.0.1147.130\"\n\tconst isOpera      = userAgent.includes('opera') || userAgent.includes(' opr/');\n\tconst operaVersion = isOpera\n\t\t? (() => {\n\t\t\tconst re  = new RegExp(`${/khtml|chrome/.test(userAgent) ? 'opr' : 'version'}\\\\/(\\\\d+\\\\.\\\\d+)`);\n\t\t\tconst ver = re.exec(userAgent);\n\t\t\treturn ver ? Number(ver[1]) : 0;\n\t\t})()\n\t\t: null;\n\n\tconst isVivaldi = userAgent.includes('vivaldi');\n\t/* eslint-enable max-len */\n\n\t// Module Exports.\n\treturn Object.freeze({\n\t\tuserAgent,\n\t\tisMobile,\n\t\tisGecko,\n\t\tisIE,\n\t\tieVersion,\n\t\tisOpera,\n\t\toperaVersion,\n\t\tisVivaldi\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/has.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser */\n\nvar Has = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tNOTE: The aggressive try/catch feature tests are necessitated by implementation\n\t\tbugs in various browsers.\n\t*/\n\n\t// Is the `HTMLAudioElement` API available?\n\tconst hasAudioElement = (() => {\n\t\ttry {\n\t\t\treturn typeof document.createElement('audio').canPlayType === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `File` API available?\n\tconst hasFile = (() => {\n\t\ttry {\n\t\t\treturn 'Blob' in window &&\n\t\t\t\t'File' in window &&\n\t\t\t\t'FileList' in window &&\n\t\t\t\t'FileReader' in window &&\n\t\t\t\t!Browser.isMobile.any() &&\n\t\t\t\t(!Browser.isOpera || Browser.operaVersion >= 15);\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `geolocation` API available?\n\tconst hasGeolocation = (() => {\n\t\ttry {\n\t\t\treturn 'geolocation' in navigator &&\n\t\t\t\ttypeof navigator.geolocation.getCurrentPosition === 'function' &&\n\t\t\t\ttypeof navigator.geolocation.watchPosition === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `MutationObserver` API available?\n\tconst hasMutationObserver = (() => {\n\t\ttry {\n\t\t\treturn 'MutationObserver' in window &&\n\t\t\t\ttypeof window.MutationObserver === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `performance` API available?\n\tconst hasPerformance = (() => {\n\t\ttry {\n\t\t\treturn 'performance' in window &&\n\t\t\t\ttypeof window.performance.now === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the platform a touch device?\n\tconst hasTouch = (() => {\n\t\ttry {\n\t\t\treturn 'ontouchstart' in window ||\n\t\t\t\t!!window.DocumentTouch &&\n\t\t\t\tdocument instanceof window.DocumentTouch ||\n\t\t\t\t!!navigator.maxTouchPoints ||\n\t\t\t\t!!navigator.msMaxTouchPoints;\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the transition end event available and by what name?\n\tconst hasTransitionEndEvent = (() => {\n\t\ttry {\n\t\t\tconst teMap = new Map([\n\t\t\t\t['transition',       'transitionend'],\n\t\t\t\t['MSTransition',     'msTransitionEnd'],\n\t\t\t\t['WebkitTransition', 'webkitTransitionEnd'],\n\t\t\t\t['MozTransition',    'transitionend']\n\t\t\t]);\n\t\t\tconst teKeys = [...teMap.keys()];\n\t\t\tconst el     = document.createElement('div');\n\n\t\t\tfor (let i = 0; i < teKeys.length; ++i) {\n\t\t\t\tif (el.style[teKeys[i]] !== undefined) {\n\t\t\t\t\treturn teMap.get(teKeys[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Module Exports.\n\treturn Object.freeze({\n\t\taudio              : hasAudioElement,\n\t\tfileAPI            : hasFile,\n\t\tgeolocation        : hasGeolocation,\n\t\tmutationObserver   : hasMutationObserver,\n\t\tperformance        : hasPerformance,\n\t\ttouch              : hasTouch,\n\t\ttransitionEndEvent : hasTransitionEndEvent\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/visibility.js\n\n\tCopyright © 2018–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar Visibility = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tThere are two versions of the Page Visibility API: First Edition and, the current,\n\t\tSecond Edition (i.e. \"Level 2\").  First Edition is mentioned here only because some\n\t\tolder browsers implement it, rather than the current specification.\n\n\t\tSEE:\n\t\t\tSecond Edition : https://www.w3.org/TR/page-visibility/\n\t\t\tFirst Edition  : https://www.w3.org/TR/2013/REC-page-visibility-20130514/\n\n\t\tNOTE: Generally, all supported browsers change the visibility state when either switching tabs\n\t\twithin the browser or minimizing the browser window.  Exceptions are noted below:\n\t\t\t* IE 9 doesn't support either version of the Page Visibility API.\n\t\t\t* Opera 12 (Presto) doesn't change the visibility state when the browser is minimized.\n\t*/\n\n\t// Vendor properties object.\n\tconst vendor = (() => {\n\t\ttry {\n\t\t\treturn Object.freeze([\n\t\t\t\t// Specification.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'hidden',          // boolean; historical in 2nd edition\n\t\t\t\t\tstateProperty  : 'visibilityState', // string, values: 'hidden', 'visible'; 1st edition had more values\n\t\t\t\t\tchangeEvent    : 'visibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `webkit` prefixed: old Blink & WebKit.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'webkitHidden',\n\t\t\t\t\tstateProperty  : 'webkitVisibilityState',\n\t\t\t\t\tchangeEvent    : 'webkitvisibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `moz` prefixed: old Gecko, maybe Seamonkey.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'mozHidden',\n\t\t\t\t\tstateProperty  : 'mozVisibilityState',\n\t\t\t\t\tchangeEvent    : 'mozvisibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `ms` prefixed: IE 10.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'msHidden',\n\t\t\t\t\tstateProperty  : 'msVisibilityState',\n\t\t\t\t\tchangeEvent    : 'msvisibilitychange'\n\t\t\t\t}\n\t\t\t].find(vnd => vnd.hiddenProperty in document));\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn undefined;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tAPI Functions.\n\t*******************************************************************************/\n\n\tfunction getVendor() {\n\t\treturn vendor;\n\t}\n\n\tfunction getVisibility() {\n\t\treturn vendor && document[vendor.stateProperty] || 'visible';\n\t}\n\n\tfunction isEnabled() {\n\t\treturn Boolean(vendor);\n\t}\n\n\tfunction isHidden() {\n\t\t// return Boolean(vendor && document[vendor.stateProperty] === 'hidden');\n\t\treturn Boolean(vendor && document[vendor.hiddenProperty]); // NOTE: Historical, but probably better for 1st edition.\n\t}\n\n\n\t/*******************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Functions.\n\t\tvendor    : { get : getVendor },\n\t\tstate     : { get : getVisibility },\n\t\tisEnabled : { value : isEnabled },\n\t\tisHidden  : { value : isHidden },\n\n\t\t// Properties.\n\t\thiddenProperty : { value : vendor && vendor.hiddenProperty },\n\t\tstateProperty  : { value : vendor && vendor.stateProperty },\n\t\tchangeEvent    : { value : vendor && vendor.changeEvent }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/fullscreen.js\n\n\tCopyright © 2018–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser */\n\nvar Fullscreen = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tSEE:\n\t\t\thttps://fullscreen.spec.whatwg.org\n\t\t\thttps://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API\n\t*/\n\n\t// Vendor properties object.\n\tconst vendor = (() => {\n\t\ttry {\n\t\t\treturn Object.freeze([\n\t\t\t\t// Specification.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'fullscreenEnabled',\n\t\t\t\t\telement     : 'fullscreenElement',\n\t\t\t\t\trequestFn   : 'requestFullscreen',\n\t\t\t\t\texitFn      : 'exitFullscreen',\n\t\t\t\t\tchangeEvent : 'fullscreenchange', // prop: onfullscreenchange\n\t\t\t\t\terrorEvent  : 'fullscreenerror'   // prop: onfullscreenerror\n\t\t\t\t},\n\n\t\t\t\t// `webkit` prefixed: old Blink, WebKit, & Edge.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'webkitFullscreenEnabled',\n\t\t\t\t\telement     : 'webkitFullscreenElement',\n\t\t\t\t\trequestFn   : 'webkitRequestFullscreen',\n\t\t\t\t\texitFn      : 'webkitExitFullscreen',\n\t\t\t\t\tchangeEvent : 'webkitfullscreenchange',\n\t\t\t\t\terrorEvent  : 'webkitfullscreenerror'\n\t\t\t\t},\n\n\t\t\t\t// `moz` prefixed: old Gecko, maybe Seamonkey.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'mozFullScreenEnabled',\n\t\t\t\t\telement     : 'mozFullScreenElement',\n\t\t\t\t\trequestFn   : 'mozRequestFullScreen',\n\t\t\t\t\texitFn      : 'mozCancelFullScreen',\n\t\t\t\t\tchangeEvent : 'mozfullscreenchange',\n\t\t\t\t\terrorEvent  : 'mozfullscreenerror'\n\t\t\t\t},\n\n\t\t\t\t// `ms` prefixed: IE 11.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'msFullscreenEnabled',\n\t\t\t\t\telement     : 'msFullscreenElement',\n\t\t\t\t\trequestFn   : 'msRequestFullscreen',\n\t\t\t\t\texitFn      : 'msExitFullscreen',\n\t\t\t\t\tchangeEvent : 'MSFullscreenChange',\n\t\t\t\t\terrorEvent  : 'MSFullscreenError'\n\t\t\t\t}\n\t\t\t].find(vnd => vnd.isEnabled in document));\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn undefined;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tFeature Detection Functions.\n\t*******************************************************************************/\n\n\t// Return whether the request and exit fullscreen methods return a `Promise`.\n\t//\n\t// NOTE: The initial result is cached for future calls.\n\tconst _returnsPromise = (function () {\n\t\t// Cache of whether the request and exit methods return a `Promise`.\n\t\tlet _hasPromise = null;\n\n\t\tfunction _returnsPromise() {\n\t\t\tif (_hasPromise !== null) {\n\t\t\t\treturn _hasPromise;\n\t\t\t}\n\n\t\t\t_hasPromise = false;\n\n\t\t\tif (vendor) {\n\t\t\t\ttry {\n\t\t\t\t\tconst value = document.exitFullscreen();\n\n\t\t\t\t\t// Silence \"Uncaught (in promise)\" console errors from Blink.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: Swallowing errors is generally bad, but in this case we know there's\n\t\t\t\t\t// going to be an error regardless, since we shouldn't be in fullscreen yet,\n\t\t\t\t\t// and we don't actually care about the error, since we just want the return\n\t\t\t\t\t// value, so we consign it to the bit bucket.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: We don't ensure that the return value is not `undefined` here because\n\t\t\t\t\t// having the attempted call to `<Promise>.catch()` on an `undefined` value throw\n\t\t\t\t\t// is acceptable, since it will be caught and `false` eventually returned.\n\t\t\t\t\tvalue.catch(() => { /* no-op */ });\n\n\t\t\t\t\t_hasPromise = value instanceof Promise;\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t}\n\n\t\t\treturn _hasPromise;\n\t\t}\n\n\t\treturn _returnsPromise;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************/\n\n\tfunction _selectElement(requestedEl) {\n\t\tlet selectedEl = requestedEl || document.documentElement;\n\n\t\t// Document element scrolling workaround for older browsers.\n\t\tif (\n\t\t\t   selectedEl === document.documentElement\n\t\t\t&& (\n\t\t\t\t   vendor.requestFn === 'msRequestFullscreen'   // IE 11\n\t\t\t\t|| Browser.isOpera && Browser.operaVersion < 15 // Opera 12 (Presto)\n\t\t\t)\n\t\t) {\n\t\t\tselectedEl = document.body;\n\t\t}\n\n\t\treturn selectedEl;\n\t}\n\n\n\t/*******************************************************************************\n\t\tAPI Functions.\n\t*******************************************************************************/\n\n\tfunction getVendor() {\n\t\treturn vendor;\n\t}\n\n\tfunction getElement() {\n\t\treturn (vendor || null) && document[vendor.element];\n\t}\n\n\tfunction isEnabled() {\n\t\treturn Boolean(vendor && document[vendor.isEnabled]);\n\t}\n\n\tfunction isFullscreen() {\n\t\treturn Boolean(vendor && document[vendor.element]);\n\t}\n\n\tfunction requestFullscreen(options, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn Promise.reject(new Error('fullscreen not supported'));\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (typeof element[vendor.requestFn] !== 'function') {\n\t\t\treturn Promise.reject(new Error('fullscreen not supported'));\n\t\t}\n\t\tif (isFullscreen()) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tif (_returnsPromise()) {\n\t\t\treturn element[vendor.requestFn](options);\n\t\t}\n\t\telse { // eslint-disable-line no-else-return\n\t\t\tconst namespace = '.Fullscreen_requestFullscreen';\n\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tjQuery(element)\n\t\t\t\t\t.off(namespace)\n\t\t\t\t\t.one(`${vendor.errorEvent}${namespace} ${vendor.changeEvent}${namespace}`, ev => {\n\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\tif (ev.type === vendor.errorEvent) {\n\t\t\t\t\t\t\treject(new Error('unknown fullscreen request error'));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\telement[vendor.requestFn](options);\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction exitFullscreen() {\n\t\tif (!vendor || typeof document[vendor.exitFn] !== 'function') {\n\t\t\treturn Promise.reject(new TypeError('fullscreen not supported'));\n\t\t}\n\t\tif (!isFullscreen()) {\n\t\t\treturn Promise.reject(new TypeError('fullscreen mode not active'));\n\t\t}\n\n\t\tif (_returnsPromise()) {\n\t\t\treturn document[vendor.exitFn]();\n\t\t}\n\t\telse { // eslint-disable-line no-else-return\n\t\t\tconst namespace = '.Fullscreen_exitFullscreen';\n\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tjQuery(document)\n\t\t\t\t\t.off(namespace)\n\t\t\t\t\t.one(`${vendor.errorEvent}${namespace} ${vendor.changeEvent}${namespace}`, ev => {\n\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\tif (ev.type === vendor.errorEvent) {\n\t\t\t\t\t\t\treject(new Error('unknown fullscreen exit error'));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tdocument[vendor.exitFn]();\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction toggleFullscreen(options, requestedEl) {\n\t\treturn isFullscreen() ? exitFullscreen() : requestFullscreen(options, requestedEl);\n\t}\n\n\tfunction onChange(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\t$(element).on(vendor.changeEvent, handlerFn);\n\t}\n\n\tfunction offChange(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (handlerFn) {\n\t\t\t$(element).off(vendor.changeEvent, handlerFn);\n\t\t}\n\t\telse {\n\t\t\t$(element).off(vendor.changeEvent);\n\t\t}\n\t}\n\n\tfunction onError(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\t$(element).on(vendor.errorEvent, handlerFn);\n\t}\n\n\tfunction offError(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (handlerFn) {\n\t\t\t$(element).off(vendor.errorEvent, handlerFn);\n\t\t}\n\t\telse {\n\t\t\t$(element).off(vendor.errorEvent);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tvendor       : { get : getVendor },\n\t\telement      : { get : getElement },\n\t\tisEnabled    : { value : isEnabled },\n\t\tisFullscreen : { value : isFullscreen },\n\t\trequest      : { value : requestFullscreen },\n\t\texit         : { value : exitFullscreen },\n\t\ttoggle       : { value : toggleFullscreen },\n\t\tonChange     : { value : onChange },\n\t\toffChange    : { value : offChange },\n\t\tonError      : { value : onError },\n\t\toffError     : { value : offError }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/helpers.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, L10n, State, Story, Util, Wikifier */\n\nvar { // eslint-disable-line no-var\n\t/* eslint-disable no-unused-vars */\n\tclone,\n\tconvertBreaks,\n\tsafeActiveElement,\n\tsetDisplayTitle,\n\tsetPageElement,\n\tthrowError,\n\ttoStringOrDefault\n\t/* eslint-enable no-unused-vars */\n} = (() => {\n\t'use strict';\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _getTextContent(source) {\n\t\tconst copy = source.cloneNode(true);\n\t\tconst frag = document.createDocumentFragment();\n\t\tlet node;\n\n\t\twhile ((node = copy.firstChild) !== null) {\n\t\t\t// Insert spaces before various elements.\n\t\t\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tswitch (node.nodeName.toUpperCase()) {\n\t\t\t\tcase 'BR':\n\t\t\t\tcase 'DIV':\n\t\t\t\tcase 'P':\n\t\t\t\t\tfrag.appendChild(document.createTextNode(' '));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfrag.appendChild(node);\n\t\t}\n\n\t\treturn frag.textContent;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tHelper Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a deep copy of the given object.\n\n\t\tNOTE:\n\t\t\t1. `clone()` does not clone functions, however, since function definitions\n\t\t\t   are immutable, the only issues are with expando properties and scope.\n\t\t\t   The former really should not be done.  The latter is problematic either\n\t\t\t   way—damned if you do, damned if you don't.\n\t\t\t2. `clone()` does not maintain referential relationships—e.g. multiple\n\t\t\t   references to the same object will, post-cloning, refer to different\n\t\t\t   equivalent objects; i.e. each reference will receive its own clone\n\t\t\t   of the original object.\n\t*/\n\tfunction clone(orig) {\n\t\t/*\n\t\t\tImmediately return the primitives and functions.\n\t\t*/\n\t\tif (typeof orig !== 'object' || orig === null) {\n\t\t\treturn orig;\n\t\t}\n\n\t\t/*\n\t\t\tUnbox instances of the primitive exemplar objects.\n\t\t*/\n\t\tif (orig instanceof String) {\n\t\t\treturn String(orig);\n\t\t}\n\t\tif (orig instanceof Number) {\n\t\t\treturn Number(orig);\n\t\t}\n\t\tif (orig instanceof Boolean) {\n\t\t\treturn Boolean(orig);\n\t\t}\n\n\t\t/*\n\t\t\tHonor native clone methods.\n\t\t*/\n\t\tif (typeof orig.clone === 'function') {\n\t\t\treturn orig.clone(true);\n\t\t}\n\t\tif (orig.nodeType && typeof orig.cloneNode === 'function') {\n\t\t\treturn orig.cloneNode(true);\n\t\t}\n\n\t\t/*\n\t\t\tCreate a copy of the original object.\n\n\t\t\tNOTE: Each non-generic object that we wish to support must be\n\t\t\texplicitly handled below.\n\t\t*/\n\t\tlet copy;\n\n\t\t// Handle instances of the core supported object types.\n\t\tif (orig instanceof Array) {\n\t\t\tcopy = new Array(orig.length);\n\t\t}\n\t\telse if (orig instanceof Date) {\n\t\t\tcopy = new Date(orig.getTime());\n\t\t}\n\t\telse if (orig instanceof Map) {\n\t\t\tcopy = new Map();\n\t\t\torig.forEach((val, key) => copy.set(key, clone(val)));\n\t\t}\n\t\telse if (orig instanceof RegExp) {\n\t\t\tcopy = new RegExp(orig);\n\t\t}\n\t\telse if (orig instanceof Set) {\n\t\t\tcopy = new Set();\n\t\t\torig.forEach(val => copy.add(clone(val)));\n\t\t}\n\n\t\t// Handle instances of unknown or generic objects.\n\t\telse {\n\t\t\t// We try to ensure that the returned copy has the same prototype as\n\t\t\t// the original, but this will probably produce less than satisfactory\n\t\t\t// results on non-generics.\n\t\t\tcopy = Object.create(Object.getPrototypeOf(orig));\n\t\t}\n\n\t\t/*\n\t\t\tDuplicate the original object's own enumerable properties, which will\n\t\t\tinclude expando properties on non-generic objects.\n\n\t\t\tNOTE: This preserves neither symbol properties nor ES5 property attributes.\n\t\t\tNeither does the delta coding or serialization code, however, so it's not\n\t\t\treally an issue at the moment.\n\t\t*/\n\t\tObject.keys(orig).forEach(name => copy[name] = clone(orig[name]));\n\n\t\treturn copy;\n\t}\n\n\t/*\n\t\tConverts <br> elements to <p> elements within the given node tree.\n\t*/\n\tfunction convertBreaks(source) {\n\t\tconst output = document.createDocumentFragment();\n\t\tlet para = document.createElement('p');\n\t\tlet node;\n\n\t\twhile ((node = source.firstChild) !== null) {\n\t\t\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tconst tagName = node.nodeName.toUpperCase();\n\n\t\t\t\tswitch (tagName) {\n\t\t\t\tcase 'BR':\n\t\t\t\t\tif (\n\t\t\t\t\t\t   node.nextSibling !== null\n\t\t\t\t\t\t&& node.nextSibling.nodeType === Node.ELEMENT_NODE\n\t\t\t\t\t\t&& node.nextSibling.nodeName.toUpperCase() === 'BR'\n\t\t\t\t\t) {\n\t\t\t\t\t\tsource.removeChild(node.nextSibling);\n\t\t\t\t\t\tsource.removeChild(node);\n\t\t\t\t\t\toutput.appendChild(para);\n\t\t\t\t\t\tpara = document.createElement('p');\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\telse if (!para.hasChildNodes()) {\n\t\t\t\t\t\tsource.removeChild(node);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'ADDRESS':\n\t\t\t\tcase 'ARTICLE':\n\t\t\t\tcase 'ASIDE':\n\t\t\t\tcase 'BLOCKQUOTE':\n\t\t\t\tcase 'CENTER':\n\t\t\t\tcase 'DIV':\n\t\t\t\tcase 'DL':\n\t\t\t\tcase 'FIGURE':\n\t\t\t\tcase 'FOOTER':\n\t\t\t\tcase 'FORM':\n\t\t\t\tcase 'H1':\n\t\t\t\tcase 'H2':\n\t\t\t\tcase 'H3':\n\t\t\t\tcase 'H4':\n\t\t\t\tcase 'H5':\n\t\t\t\tcase 'H6':\n\t\t\t\tcase 'HEADER':\n\t\t\t\tcase 'HR':\n\t\t\t\tcase 'MAIN':\n\t\t\t\tcase 'NAV':\n\t\t\t\tcase 'OL':\n\t\t\t\tcase 'P':\n\t\t\t\tcase 'PRE':\n\t\t\t\tcase 'SECTION':\n\t\t\t\tcase 'TABLE':\n\t\t\t\tcase 'UL':\n\t\t\t\t\tif (para.hasChildNodes()) {\n\t\t\t\t\t\toutput.appendChild(para);\n\t\t\t\t\t\tpara = document.createElement('p');\n\t\t\t\t\t}\n\n\t\t\t\t\toutput.appendChild(node);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpara.appendChild(node);\n\t\t}\n\n\t\tif (para.hasChildNodes()) {\n\t\t\toutput.appendChild(para);\n\t\t}\n\n\t\tsource.appendChild(output);\n\t}\n\n\t/*\n\t\tReturns `document.activeElement` or `null`.\n\t*/\n\tfunction safeActiveElement() {\n\t\t/*\n\t\t\tIE9 contains a bug where trying to access the active element of an iframe's\n\t\t\tparent document (i.e. `window.parent.document.activeElement`) will throw an\n\t\t\texception, so we must allow for an exception to be thrown.\n\n\t\t\tWe could simply return `undefined` here, but since the API's default behavior\n\t\t\tshould be to return `document.body` or `null` when there is no selection, we\n\t\t\tchoose to return `null` in all non-element cases (i.e. whether it returns\n\t\t\t`null` or throws an exception).  Just a bit of normalization.\n\t\t*/\n\t\ttry {\n\t\t\treturn document.activeElement || null;\n\t\t}\n\t\tcatch (ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/*\n\t\tSets the display title.\n\t*/\n\tfunction setDisplayTitle(title) {\n\t\tif (typeof title !== 'string') {\n\t\t\tthrow new TypeError(`story display title must be a string (received: ${Util.getType(title)})`);\n\t\t}\n\n\t\tconst render = document.createDocumentFragment();\n\t\tnew Wikifier(render, title);\n\n\t\tconst text = _getTextContent(render).trim();\n\n\t\t// if (text === '') {\n\t\t// \tthrow new Error('story display title must not render to an empty string or consist solely of whitespace');\n\t\t// }\n\n\t\tdocument.title = Config.passages.displayTitles && State.passage !== '' && State.passage !== Config.passages.start\n\t\t\t? `${State.passage} | ${text}`\n\t\t\t: text;\n\n\t\tconst storyTitle = document.getElementById('story-title');\n\n\t\tif (storyTitle !== null) {\n\t\t\tjQuery(storyTitle).empty().append(render);\n\t\t}\n\t}\n\n\t/*\n\t\tWikifies a passage into a DOM element corresponding to the passed ID and returns the element.\n\t*/\n\tfunction setPageElement(idOrElement, titles, defaultText) {\n\t\tconst el = typeof idOrElement === 'object'\n\t\t\t? idOrElement\n\t\t\t: document.getElementById(idOrElement);\n\n\t\tif (el == null) { // lazy equality for null\n\t\t\treturn null;\n\t\t}\n\n\t\tconst ids = Array.isArray(titles) ? titles : [titles];\n\n\t\tjQuery(el).empty();\n\n\t\tfor (let i = 0, iend = ids.length; i < iend; ++i) {\n\t\t\tif (Story.has(ids[i])) {\n\t\t\t\tnew Wikifier(el, Story.get(ids[i]).processText().trim());\n\t\t\t\treturn el;\n\t\t\t}\n\t\t}\n\n\t\tif (defaultText != null) { // lazy equality for null\n\t\t\tconst text = String(defaultText).trim();\n\n\t\t\tif (text !== '') {\n\t\t\t\tnew Wikifier(el, text);\n\t\t\t}\n\t\t}\n\n\t\treturn el;\n\t}\n\n\t/*\n\t\tAppends an error view to the passed DOM element.\n\t*/\n\tfunction throwError(place, message, source, stack) {\n\t\tconst $wrapper = jQuery(document.createElement('div'));\n\t\tconst $toggle  = jQuery(document.createElement('button'));\n\t\tconst $source  = jQuery(document.createElement('pre'));\n\t\tconst mesg     = `${L10n.get('errorTitle')}: ${message || 'unknown error'}`;\n\n\t\t$toggle\n\t\t\t.addClass('error-toggle')\n\t\t\t.ariaClick({\n\t\t\t\tlabel : L10n.get('errorToggle')\n\t\t\t}, () => {\n\t\t\t\tif ($toggle.hasClass('enabled')) {\n\t\t\t\t\t$toggle.removeClass('enabled');\n\t\t\t\t\t$source.attr({\n\t\t\t\t\t\t'aria-hidden' : true,\n\t\t\t\t\t\thidden        : 'hidden'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$toggle.addClass('enabled');\n\t\t\t\t\t$source.removeAttr('aria-hidden hidden');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.appendTo($wrapper);\n\t\tjQuery(document.createElement('span'))\n\t\t\t.addClass('error')\n\t\t\t.text(mesg)\n\t\t\t.appendTo($wrapper);\n\t\tjQuery(document.createElement('code'))\n\t\t\t.text(source)\n\t\t\t.appendTo($source);\n\t\t$source\n\t\t\t.addClass('error-source')\n\t\t\t.attr({\n\t\t\t\t'aria-hidden' : true,\n\t\t\t\thidden        : 'hidden'\n\t\t\t})\n\t\t\t.appendTo($wrapper);\n\t\tif (stack) {\n\t\t\tconst lines = stack.split('\\n');\n\t\t\tfor (const ll of lines) {\n\t\t\t\tconst div = document.createElement('div');\n\t\t\t\tdiv.append(ll.replace(/file:.*\\//, '<path>/'));\n\t\t\t\t$source.append(div);\n\t\t\t}\n\t\t}\n\t\t$wrapper\n\t\t\t.addClass('error-view')\n\t\t\t.appendTo(place);\n\n\t\tconsole.warn(`${mesg}\\n\\t${source.replace(/\\n/g, '\\n\\t')}`);\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tReturns the simple string representation of the passed value or, if there is none,\n\t\tthe passed default value.\n\t*/\n\tfunction toStringOrDefault(value, defValue) {\n\t\tconst tSOD = toStringOrDefault;\n\n\t\tswitch (typeof value) {\n\t\tcase 'number':\n\t\t\t// TODO: Perhaps NaN should be printed instead?\n\t\t\tif (Number.isNaN(value)) {\n\t\t\t\treturn defValue;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\tif (value === null) {\n\t\t\t\treturn defValue;\n\t\t\t}\n\t\t\telse if (Array.isArray(value)) {\n\t\t\t\treturn value.map(val => tSOD(val, defValue)).join(', ');\n\t\t\t}\n\t\t\telse if (value instanceof Set) {\n\t\t\t\treturn [...value].map(val => tSOD(val, defValue)).join(', ');\n\t\t\t}\n\t\t\telse if (value instanceof Map) {\n\t\t\t\tconst result = [...value].map(([key, val]) => `${tSOD(key, defValue)} \\u2192 ${tSOD(val, defValue)}`);\n\t\t\t\treturn `{\\u202F${result.join(', ')}\\u202F}`;\n\t\t\t}\n\t\t\telse if (value instanceof Date) {\n\t\t\t\treturn value.toLocaleString();\n\t\t\t}\n\t\t\telse if (typeof value.toString === 'function') {\n\t\t\t\treturn value.toString();\n\t\t\t}\n\t\t\treturn Object.prototype.toString.call(value);\n\n\t\tcase 'function':\n\t\tcase 'undefined':\n\t\t\treturn defValue;\n\t\t}\n\n\t\treturn String(value);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tclone             : { value : clone },\n\t\tconvertBreaks     : { value : convertBreaks },\n\t\tsafeActiveElement : { value : safeActiveElement },\n\t\tsetDisplayTitle   : { value : setDisplayTitle },\n\t\tsetPageElement    : { value : setPageElement },\n\t\tthrowError        : { value : throwError },\n\t\ttoStringOrDefault : { value : toStringOrDefault }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/jquery-plugins.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Wikifier, errorPrologRegExp, safeActiveElement */\n\n/*\n\tWAI-ARIA methods plugin.\n\n\t`<jQuery>.ariaClick([options,] handler)`\n\t    Makes the target element(s) WAI-ARIA compatible clickables.\n\n\t`<jQuery>.ariaDisabled(state)`\n\t    Changes the disabled state of the target WAI-ARIA-compatible clickable element(s).\n\n\t`<jQuery>.ariaIsDisabled()`\n\t    Checks the disabled status of the target WAI-ARIA-compatible clickable element(s).\n*/\n(() => {\n\t'use strict';\n\n\t/*\n\t\tEvent handler & utility functions.\n\n\t\tNOTE: Do not replace the anonymous functions herein with arrow functions.\n\t*/\n\tfunction onKeypressFn(ev) {\n\t\t// 13 is Enter/Return, 32 is Space.\n\t\tif (ev.which === 13 || ev.which === 32) {\n\t\t\tev.preventDefault();\n\n\t\t\t// To allow delegation, attempt to trigger the event on `document.activeElement`,\n\t\t\t// if possible, elsewise on `this`.\n\t\t\tjQuery(safeActiveElement() || this).trigger('click');\n\t\t}\n\t}\n\n\tfunction onClickFnWrapper(fn) {\n\t\treturn function () {\n\t\t\tconst $this = jQuery(this);\n\n\t\t\tconst dataPassage = $this.attr('data-passage');\n\t\t\tconst initialDataPassage = window && window.SugarCube && window.SugarCube.State && window.SugarCube.State.passage;\n\t\t\tconst savedYOffset = window.pageYOffset;\n\n\t\t\t// Toggle \"aria-pressed\" status, if the attribute exists.\n\t\t\tif ($this.is('[aria-pressed]')) {\n\t\t\t\t$this.attr('aria-pressed', $this.attr('aria-pressed') === 'true' ? 'false' : 'true');\n\t\t\t}\n\n\t\t\t// Call the true handler.\n\t\t\tfn.apply(this, arguments);\n\n\t\t\tconst doJump = function(){ window.scrollTo(0, savedYOffset); }\n\t\t\tif ( dataPassage && (window.lastDataPassageLink === dataPassage || initialDataPassage === dataPassage))\n\t\t\t\tdoJump();\n\t\t\twindow.lastDataPassageLink = dataPassage;\n\t\t};\n\t}\n\n\tfunction oneClickFnWrapper(fn) {\n\t\treturn onClickFnWrapper(function () {\n\t\t\t// Remove both event handlers (keypress & click) and the other components.\n\t\t\tjQuery(this)\n\t\t\t\t.off('.aria-clickable')\n\t\t\t\t.removeAttr('tabindex aria-controls aria-pressed')\n\t\t\t\t.not('a,button')\n\t\t\t\t.removeAttr('role')\n\t\t\t\t.end()\n\t\t\t\t.filter('button')\n\t\t\t\t.prop('disabled', true);\n\n\t\t\t// Call the true handler.\n\t\t\tfn.apply(this, arguments);\n\t\t});\n\t}\n\n\tjQuery.fn.extend({\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaClick()` method.\n\t\t*/\n\t\tariaClick(options, handler) {\n\t\t\t// Bail out if there are no target element(s) or parameters.\n\t\t\tif (this.length === 0 || arguments.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tlet opts = options;\n\t\t\tlet fn   = handler;\n\n\t\t\tif (fn == null) { // lazy equality for null\n\t\t\t\tfn   = opts;\n\t\t\t\topts = undefined;\n\t\t\t}\n\n\t\t\topts = jQuery.extend({\n\t\t\t\tnamespace : undefined,\n\t\t\t\tone       : false,\n\t\t\t\tselector  : undefined,\n\t\t\t\tdata      : undefined,\n\t\t\t\tcontrols  : undefined,\n\t\t\t\tpressed   : undefined,\n\t\t\t\tlabel     : undefined\n\t\t\t}, opts);\n\n\t\t\tif (typeof opts.namespace !== 'string') {\n\t\t\t\topts.namespace = '';\n\t\t\t}\n\t\t\telse if (opts.namespace[0] !== '.') {\n\t\t\t\topts.namespace = `.${opts.namespace}`;\n\t\t\t}\n\n\t\t\tif (typeof opts.pressed === 'boolean') {\n\t\t\t\topts.pressed = opts.pressed ? 'true' : 'false';\n\t\t\t}\n\n\t\t\t// Set `type` to `button` to suppress \"submit\" semantics, for <button> elements.\n\t\t\tthis.filter('button').prop('type', 'button');\n\n\t\t\t// Set `role` to `button`, for non-<a>/-<button> elements.\n\t\t\tthis.not('a,button').attr('role', 'button');\n\n\t\t\t// Set `tabindex` to `0` to make them focusable (unnecessary on <button> elements, but it doesn't hurt).\n\t\t\tthis.attr('tabindex', 0);\n\n\t\t\t// Set `aria-controls`.\n\t\t\tif (opts.controls != null) { // lazy equality for null\n\t\t\t\tthis.attr('aria-controls', opts.controls);\n\t\t\t}\n\n\t\t\t// Set `aria-pressed`.\n\t\t\tif (opts.pressed != null) { // lazy equality for null\n\t\t\t\tthis.attr('aria-pressed', opts.pressed);\n\t\t\t}\n\n\t\t\t// Set `aria-label` and `title`.\n\t\t\tif (opts.label != null) { // lazy equality for null\n\t\t\t\tthis.attr({\n\t\t\t\t\t'aria-label' : opts.label,\n\t\t\t\t\ttitle        : opts.label\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Set the keypress handlers, for non-<button> elements.\n\t\t\t// NOTE: For the single-use case, the click handler will also remove this handler.\n\t\t\tthis.not('button').on(\n\t\t\t\t`keypress.aria-clickable${opts.namespace}`,\n\t\t\t\topts.selector,\n\t\t\t\tonKeypressFn\n\t\t\t);\n\n\t\t\t// Set the click handlers.\n\t\t\t// NOTE: To ensure both handlers are properly removed, `one()` must not be used here.\n\t\t\tthis.on(\n\t\t\t\t`click.aria-clickable${opts.namespace}`,\n\t\t\t\topts.selector,\n\t\t\t\topts.data,\n\t\t\t\topts.one ? oneClickFnWrapper(fn) : onClickFnWrapper(fn)\n\t\t\t);\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaDisabled()` method.\n\t\t*/\n\t\tariaDisabled(disable) {\n\t\t\t// Bail out if there are no target element(s) or parameters.\n\t\t\tif (this.length === 0 || arguments.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tNOTE: We use `<jQuery>.each()` callbacks to invoke the `<Element>.setAttribute()`\n\t\t\t\tmethods in the following because the `<jQuery>.attr()` method does not allow you\n\t\t\t\tto set a content attribute without a value, which is recommended for boolean\n\t\t\t\tcontent attributes by the HTML specification.\n\t\t\t*/\n\n\t\t\tconst $nonDisableable = this.not('button,fieldset,input,menuitem,optgroup,option,select,textarea');\n\t\t\tconst $disableable    = this.filter('button,fieldset,input,menuitem,optgroup,option,select,textarea');\n\n\t\t\tif (disable) {\n\t\t\t\t// Add boolean content attribute `disabled` and set non-boolean content attribute\n\t\t\t\t// `aria-disabled` to `'true'`, for non-disableable elements.\n\t\t\t\t$nonDisableable.each(function () {\n\t\t\t\t\tthis.setAttribute('disabled', '');\n\t\t\t\t\tthis.setAttribute('aria-disabled', 'true');\n\t\t\t\t});\n\n\t\t\t\t// Set IDL attribute `disabled` to `true` and set non-boolean content attribute\n\t\t\t\t// `aria-disabled` to `'true'`, for disableable elements.\n\t\t\t\t$disableable.each(function () {\n\t\t\t\t\tthis.disabled = true;\n\t\t\t\t\tthis.setAttribute('aria-disabled', 'true');\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Remove content attributes `disabled` and `aria-disabled`, for non-disableable elements.\n\t\t\t\t$nonDisableable.each(function () {\n\t\t\t\t\tthis.removeAttribute('disabled');\n\t\t\t\t\tthis.removeAttribute('aria-disabled');\n\t\t\t\t});\n\n\t\t\t\t// Set IDL attribute `disabled` to `false` and remove content attribute `aria-disabled`,\n\t\t\t\t// for disableable elements.\n\t\t\t\t$disableable.each(function () {\n\t\t\t\t\tthis.disabled = false;\n\t\t\t\t\tthis.removeAttribute('aria-disabled');\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaIsDisabled()` method.\n\t\t*/\n\t\tariaIsDisabled() {\n\t\t\t// Check content attribute `disabled`.\n\t\t\t//\n\t\t\t// NOTE: We simply check the `disabled` content attribute for all elements\n\t\t\t// since we have to check it for non-disableable elements and it may also\n\t\t\t// be used for disableable elements since their `disabled` IDL attribute\n\t\t\t// is required to reflect the status of their `disabled` content attribute,\n\t\t\t// and vice versa, by the HTML specification.\n\t\t\t// return this.toArray().some(el => el.hasAttribute('disabled'));\n\t\t\treturn this.is('[disabled]');\n\t\t}\n\t});\n})();\n\n/*\n\tWikifier methods plugin.\n\n\t`jQuery.wikiWithOptions(options, sources…)`\n\t    Wikifies the given content source(s), as directed by the given options.\n\n\t`jQuery.wiki(sources…)`\n\t    Wikifies the given content source(s).\n\n\t`<jQuery>.wikiWithOptions(options, sources…)`\n\t    Wikifies the given content source(s) and appends the result to the target\n\t    element(s), as directed by the given options.\n\n\t`<jQuery>.wiki(sources…)`\n\t    Wikifies the given content source(s) and appends the result to the target\n\t    element(s).\n*/\n(() => {\n\t'use strict';\n\n\tjQuery.extend({\n\t\t/*\n\t\t\tExtend jQuery's static methods with a `wikiWithOptions()` method.\n\t\t*/\n\t\twikiWithOptions(options, ...sources) {\n\t\t\t// Bail out, if there are no content sources.\n\t\t\tif (sources.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Wikify the content sources into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tsources.forEach(content => new Wikifier(frag, content, options));\n\n\t\t\t// Gather the text of any error elements within the fragment…\n\t\t\tconst errors = [...frag.querySelectorAll('.error')]\n\t\t\t\t.map(errEl => errEl.textContent.replace(errorPrologRegExp, ''));\n\n\t\t\t// …and throw an exception, if there were any errors.\n\t\t\tif (errors.length > 0) {\n\t\t\t\tthrow new Error(errors.join('; '));\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's static methods with a `wiki()` method.\n\t\t*/\n\t\twiki(...sources) {\n\t\t\tthis.wikiWithOptions(undefined, ...sources);\n\t\t}\n\t});\n\n\tjQuery.fn.extend({\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with a `wikiWithOptions()` method.\n\t\t*/\n\t\twikiWithOptions(options, ...sources) {\n\t\t\t// Bail out if there are no target element(s) or content sources.\n\t\t\tif (this.length === 0 || sources.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t// Wikify the content sources into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tsources.forEach(content => new Wikifier(frag, content, options));\n\n\t\t\t// Append the fragment to the target element(s).\n\t\t\tthis.append(frag);\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with a `wiki()` method.\n\t\t*/\n\t\twiki(...sources) {\n\t\t\treturn this.wikiWithOptions(undefined, ...sources);\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/util.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Has, Scripting */\n\nvar Util = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tType Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the value yielded by `typeof` (for primitives), the `@@toStringTag`\n\t\tinternal property (for objects), and `'null'` for `null`.\n\n\t\tNOTE: In ≤ES5, returns the value of the `[[Class]]` internal slot for objects.\n\t*/\n\tfunction utilGetType(obj) {\n\t\tif (obj === null) { return 'null'; }\n\n\t\tconst baseType = typeof obj;\n\t\treturn baseType === 'object'\n\t\t\t? Object.prototype.toString.call(obj).slice(8, -1)\n\t\t\t: baseType;\n\t}\n\n\t/*\n\t\tReturns whether the passed value is a boolean or one of the strings \"true\"\n\t\tor \"false\".\n\t*/\n\tfunction utilIsBoolean(obj) {\n\t\treturn typeof obj === 'boolean' || typeof obj === 'string' && (obj === 'true' || obj === 'false');\n\t}\n\n\t/*\n\t\tReturns whether the passed value is iterable.\n\t*/\n\tfunction utilIsIterable(obj) {\n\t\treturn obj != null && typeof obj[Symbol.iterator] === 'function'; // lazy equality for null\n\t}\n\n\t/*\n\t\tReturns whether the passed value is a finite number or a numeric string which\n\t\tyields a finite number when parsed.\n\t*/\n\tfunction utilIsNumeric(obj) {\n\t\tlet num;\n\n\t\tswitch (typeof obj) {\n\t\tcase 'number':\n\t\t\tnum = obj;\n\t\t\tbreak;\n\n\t\tcase 'string':\n\t\t\tnum = Number(obj);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !Number.isNaN(num) && Number.isFinite(num);\n\t}\n\n\t/*\n\t\tReturns whether the passed values pass a SameValueZero comparison.\n\n\t\tSEE: http://ecma-international.org/ecma-262/8.0/#sec-samevaluezero\n\t*/\n\tfunction utilSameValueZero(a, b) {\n\t\t/*\n\t\t\tNOTE: This comparison could also be implemented thus:\n\n\t\t\t\t```\n\t\t\t\ta === b ||\n\t\t\t\ttypeof a === 'number' && typeof b === 'number' &&\n\t\t\t\tNumber.isNaN(a) && Number.isNaN(b)\n\t\t\t\t```\n\n\t\t\tThat's needlessly verbose, however, as `NaN` is the only value in\n\t\t\tthe language which is not reflexive.\n\t\t*/\n\t\treturn a === b || a !== a && b !== b;\n\t}\n\n\t/*\n\t\tReturns a pseudo-enumeration created from the given Array, Map, Set, or generic object.\n\t*/\n\tfunction utilToEnum(obj) {\n\t\tconst pEnum = Object.create(null);\n\n\t\tif (obj instanceof Array) {\n\t\t\tobj.forEach((val, i) => pEnum[String(val)] = i);\n\t\t}\n\t\telse if (obj instanceof Set) {\n\t\t\t// NOTE: Use `<Array>.forEach()` here rather than `<Set>.forEach()`\n\t\t\t// as the latter does not provide the indices we require.\n\t\t\tArray.from(obj).forEach((val, i) => pEnum[String(val)] = i);\n\t\t}\n\t\telse if (obj instanceof Map) {\n\t\t\tobj.forEach((val, key) => pEnum[String(key)] = val);\n\t\t}\n\t\telse if (\n\t\t\t   typeof obj === 'object'\n\t\t\t&& obj !== null\n\t\t\t&& Object.getPrototypeOf(obj) === Object.prototype\n\t\t) {\n\t\t\tObject.assign(pEnum, obj);\n\t\t}\n\t\telse {\n\t\t\tthrow new TypeError('Util.toEnum obj parameter must be an Array, Map, Set, or generic object');\n\t\t}\n\n\t\treturn Object.freeze(pEnum);\n\t}\n\n\t/*\n\t\tReturns the value of the `@@toStringTag` property of the given object.\n\n\t\tNOTE: In ≤ES5, returns the value of the `[[Class]]` internal slot.\n\t*/\n\tfunction utilToStringTag(obj) {\n\t\treturn Object.prototype.toString.call(obj).slice(8, -1);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tString Encoding Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a trimmed and encoded slug of the passed string that should be safe\n\t\tfor use as a DOM ID or class name.\n\n\t\tNOTE: The range of illegal characters consists of: C0 controls, space, exclamation,\n\t\tdouble quote, number, dollar, percent, ampersand, single quote, left paren, right\n\t\tparen, asterisk, plus, comma, hyphen, period, forward slash, colon, semi-colon,\n\t\tless-than, equals, greater-than, question, at, left bracket, backslash, right\n\t\tbracket, caret, backquote/grave, left brace, pipe/vertical-bar, right brace, tilde,\n\t\tdelete, C1 controls.\n\t*/\n\tconst _illegalSlugCharsRe = /[\\x00-\\x20!-/:-@[-^`{-\\x9f]+/g; // eslint-disable-line no-control-regex\n\t/* legacy */\n\tconst _isInvalidSlugRe = /^-*$/; // Matches the empty string or one comprised solely of hyphens.\n\t/* /legacy */\n\n\tfunction utilSlugify(str) {\n\t\tconst base = String(str).trim();\n\n\t\t/* legacy */\n\t\tconst _legacy = base\n\t\t\t.replace(/[^\\w\\s\\u2013\\u2014-]+/g, '')\n\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-')\n\t\t\t.toLocaleLowerCase();\n\n\t\tif (!_isInvalidSlugRe.test(_legacy)) {\n\t\t\treturn _legacy;\n\t\t}\n\t\t/* /legacy */\n\n\t\treturn base\n\t\t\t.replace(_illegalSlugCharsRe, '')\n\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-');\n\n\t\t// For v3.\n\t\t// return base.replace(_illegalSlugCharsRe, '-');\n\t}\n\n\t/*\n\t\tReturns an entity encoded version of the passed string.\n\n\t\tNOTE: Only escapes the five primary special characters and the backquote.\n\t*/\n\tconst _htmlCharsRe    = /[&<>\"'`]/g;\n\tconst _hasHtmlCharsRe = new RegExp(_htmlCharsRe.source); // to drop the global flag\n\tconst _htmlCharsMap   = Object.freeze({\n\t\t'&' : '&amp;',\n\t\t'<' : '&lt;',\n\t\t'>' : '&gt;',\n\t\t'\"' : '&quot;',\n\t\t\"'\" : '&#39;',\n\t\t'`' : '&#96;'\n\t});\n\n\tfunction utilEscape(str) {\n\t\tif (str == null) { // lazy equality for null\n\t\t\treturn '';\n\t\t}\n\n\t\tconst val = String(str);\n\t\treturn val && _hasHtmlCharsRe.test(val)\n\t\t\t? val.replace(_htmlCharsRe, ch => _htmlCharsMap[ch])\n\t\t\t: val;\n\t}\n\n\t/*\n\t\tReturns a decoded version of the passed entity encoded string.\n\n\t\tNOTE: The extended replacement set here, in contrast to `utilEscape()`,\n\t\tis required due to observed stupidity from various sources.\n\t*/\n\tconst _escapedHtmlRe    = /&(?:amp|#38|#x26|lt|#60|#x3c|gt|#62|#x3e|quot|#34|#x22|apos|#39|#x27|#96|#x60);/gi;\n\tconst _hasEscapedHtmlRe = new RegExp(_escapedHtmlRe.source, 'i'); // to drop the global flag\n\tconst _escapedHtmlMap   = Object.freeze({\n\t\t'&amp;'  : '&', // ampersand (HTML character entity, XML predefined entity)\n\t\t'&#38;'  : '&', // ampersand (decimal numeric character reference)\n\t\t'&#x26;' : '&', // ampersand (hexadecimal numeric character reference)\n\t\t'&lt;'   : '<', // less-than (HTML character entity, XML predefined entity)\n\t\t'&#60;'  : '<', // less-than (decimal numeric character reference)\n\t\t'&#x3c;' : '<', // less-than (hexadecimal numeric character reference)\n\t\t'&gt;'   : '>', // greater-than (HTML character entity, XML predefined entity)\n\t\t'&#62;'  : '>', // greater-than (decimal numeric character reference)\n\t\t'&#x3e;' : '>', // greater-than (hexadecimal numeric character reference)\n\t\t'&quot;' : '\"', // double quote (HTML character entity, XML predefined entity)\n\t\t'&#34;'  : '\"', // double quote (decimal numeric character reference)\n\t\t'&#x22;' : '\"', // double quote (hexadecimal numeric character reference)\n\t\t'&apos;' : \"'\", // apostrophe (XML predefined entity)\n\t\t'&#39;'  : \"'\", // apostrophe (decimal numeric character reference)\n\t\t'&#x27;' : \"'\", // apostrophe (hexadecimal numeric character reference)\n\t\t'&#96;'  : '`', // backquote (decimal numeric character reference)\n\t\t'&#x60;' : '`'  // backquote (hexadecimal numeric character reference)\n\t});\n\n\tfunction utilUnescape(str) {\n\t\tif (str == null) { // lazy equality for null\n\t\t\treturn '';\n\t\t}\n\n\t\tconst val = String(str);\n\t\treturn val && _hasEscapedHtmlRe.test(val)\n\t\t\t? val.replace(_escapedHtmlRe, entity => _escapedHtmlMap[entity.toLowerCase()])\n\t\t\t: val;\n\t}\n\n\t/*\n\t\tReturns an object (`{ char, start, end }`) containing the Unicode character at\n\t\tposition `pos`, its starting position, and its ending position—surrogate pairs\n\t\tare properly handled.  If `pos` is out-of-bounds, returns an object containing\n\t\tthe empty string and start/end positions of `-1`.\n\n\t\tThis function is necessary because JavaScript strings are sequences of UTF-16\n\t\tcode units, so surrogate pairs are exposed and thus must be handled.  While the\n\t\tES6/2015 standard does improve the situation somewhat, it does not alleviate\n\t\tthe need for this function.\n\n\t\tNOTE: Returns the individual code units of invalid surrogate pairs as-is.\n\n\t\tIDEA: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt\n\t*/\n\tfunction utilCharAndPosAt(text, position) {\n\t\tconst str  = String(text);\n\t\tconst pos  = Math.trunc(position);\n\t\tconst code = str.charCodeAt(pos);\n\n\t\t// Given position was out-of-bounds.\n\t\tif (Number.isNaN(code)) {\n\t\t\treturn { char : '', start : -1, end : -1 };\n\t\t}\n\n\t\tconst retval = {\n\t\t\tchar  : str.charAt(pos),\n\t\t\tstart : pos,\n\t\t\tend   : pos\n\t\t};\n\n\t\t// Code unit is not a UTF-16 surrogate.\n\t\tif (code < 0xD800 || code > 0xDFFF) {\n\t\t\treturn retval;\n\t\t}\n\n\t\t// Code unit is a high surrogate (D800–DBFF).\n\t\tif (code >= 0xD800 && code <= 0xDBFF) {\n\t\t\tconst nextPos = pos + 1;\n\n\t\t\t// End of string.\n\t\t\tif (nextPos >= str.length) {\n\t\t\t\treturn retval;\n\t\t\t}\n\n\t\t\tconst nextCode = str.charCodeAt(nextPos);\n\n\t\t\t// Next code unit is not a low surrogate (DC00–DFFF).\n\t\t\tif (nextCode < 0xDC00 || nextCode > 0xDFFF) {\n\t\t\t\treturn retval;\n\t\t\t}\n\n\t\t\tretval.char = retval.char + str.charAt(nextPos);\n\t\t\tretval.end = nextPos;\n\t\t\treturn retval;\n\t\t}\n\n\t\t// Code unit is a low surrogate (DC00–DFFF) in the first position.\n\t\tif (pos === 0) {\n\t\t\treturn retval;\n\t\t}\n\n\t\tconst prevPos  = pos - 1;\n\t\tconst prevCode = str.charCodeAt(prevPos);\n\n\t\t// Previous code unit is not a high surrogate (D800–DBFF).\n\t\tif (prevCode < 0xD800 || prevCode > 0xDBFF) {\n\t\t\treturn retval;\n\t\t}\n\n\t\tretval.char = str.charAt(prevPos) + retval.char;\n\t\tretval.start = prevPos;\n\t\treturn retval;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTime Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the number of milliseconds elapsed since a reference epoch.\n\n\t\tNOTE: Use the Performance API, if available, elsewise use Date as a\n\t\tfailover.  The Performance API is preferred for its monotonic clock—\n\t\tmeaning, it's not subject to the vagaries of timezone changes and leap\n\t\tperiods, as is Date.\n\t*/\n\tconst _nowSource = Has.performance ? performance : Date;\n\n\tfunction utilNow() {\n\t\treturn _nowSource.now();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tConversion Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the number of miliseconds represented by the passed CSS time string.\n\t*/\n\tconst _cssTimeRe = /^([+-]?(?:\\d*\\.)?\\d+)([Mm]?[Ss])$/;\n\n\tfunction utilFromCssTime(cssTime) {\n\t\tconst match = _cssTimeRe.exec(String(cssTime));\n\n\t\tif (match === null) {\n\t\t\tthrow new SyntaxError(`invalid time value syntax: \"${cssTime}\"`);\n\t\t}\n\n\t\tlet msec = Number(match[1]);\n\n\t\tif (match[2].length === 1) {\n\t\t\tmsec *= 1000;\n\t\t}\n\n\t\tif (Number.isNaN(msec) || !Number.isFinite(msec)) {\n\t\t\tthrow new RangeError(`invalid time value: \"${cssTime}\"`);\n\t\t}\n\n\t\treturn msec;\n\t}\n\n\t/*\n\t\tReturns the CSS time string represented by the passed number of milliseconds.\n\t*/\n\tfunction utilToCssTime(msec) {\n\t\tif (typeof msec !== 'number' || Number.isNaN(msec) || !Number.isFinite(msec)) {\n\t\t\tlet what;\n\n\t\t\tswitch (typeof msec) {\n\t\t\tcase 'string':\n\t\t\t\twhat = `\"${msec}\"`;\n\t\t\t\tbreak;\n\n\t\t\tcase 'number':\n\t\t\t\twhat = String(msec);\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\twhat = utilToStringTag(msec);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tthrow new Error(`invalid milliseconds: ${what}`);\n\t\t}\n\n\t\treturn `${msec}ms`;\n\t}\n\n\t/*\n\t\tReturns the DOM property name represented by the passed CSS property name.\n\t*/\n\tfunction utilFromCssProperty(cssName) {\n\t\tif (!cssName.includes('-')) {\n\t\t\tswitch (cssName) {\n\t\t\tcase 'bgcolor': return 'backgroundColor';\n\t\t\tcase 'float':   return 'cssFloat';\n\t\t\tdefault:        return cssName;\n\t\t\t}\n\t\t}\n\n\t\t// Strip the leading hyphen from the `-ms-` vendor prefix, so it stays lowercased.\n\t\tconst normalized = cssName.slice(0, 4) === '-ms-' ? cssName.slice(1) : cssName;\n\n\t\treturn normalized\n\t\t\t.split('-')\n\t\t\t.map((part, i) => i === 0 ? part : part.toUpperFirst())\n\t\t\t.join('');\n\t}\n\n\t/*\n\t\tReturns an object containing the component properties parsed from the passed URL.\n\t*/\n\tfunction utilParseUrl(url) {\n\t\tconst el       = document.createElement('a');\n\t\tconst queryObj = Object.create(null);\n\n\t\t// Let the `<a>` element parse the URL.\n\t\tel.href = url;\n\n\t\t// Populate the `queryObj` object with the query string attributes.\n\t\tif (el.search) {\n\t\t\tel.search\n\t\t\t\t.replace(/^\\?/, '')\n\t\t\t\t.splitOrEmpty(/(?:&(?:amp;)?|;)/)\n\t\t\t\t.forEach(query => {\n\t\t\t\t\tconst [key, value] = query.split('=');\n\t\t\t\t\tqueryObj[key] = value;\n\t\t\t\t});\n\t\t}\n\n\t\t/*\n\t\t\tCaveats by browser:\n\t\t\t\tEdge and Internet Explorer (≥8) do not support authentication\n\t\t\t\tinformation within a URL at all and will throw a security exception\n\t\t\t\ton *any* property access if it's included.\n\n\t\t\t\tInternet Explorer does not include the leading forward slash on\n\t\t\t\t`pathname` when required.\n\n\t\t\t\tOpera (Presto) strips the authentication information from `href`\n\t\t\t\tand does not supply `username` or `password`.\n\n\t\t\t\tSafari (ca. v5.1.x) does not supply `username` or `password` and\n\t\t\t\tpeforms URI decoding on `pathname`.\n\t\t*/\n\n\t\t// Patch for IE not including the leading slash on `pathname` when required.\n\t\tconst pathname = el.host && el.pathname[0] !== '/' ? `/${el.pathname}` : el.pathname;\n\n\t\treturn {\n\t\t\t// The full URL that was originally parsed.\n\t\t\thref : el.href,\n\n\t\t\t// The request protocol, lowercased.\n\t\t\tprotocol : el.protocol,\n\n\t\t\t// // The full authentication information.\n\t\t\t// auth : el.username || el.password // eslint-disable-line no-nested-ternary\n\t\t\t// \t? `${el.username}:${el.password}`\n\t\t\t// \t: typeof el.username === 'string' ? '' : undefined,\n\t\t\t//\n\t\t\t// // The username portion of the auth info.\n\t\t\t// username : el.username,\n\t\t\t//\n\t\t\t// // The password portion of the auth info.\n\t\t\t// password : el.password,\n\n\t\t\t// The full host information, including port number, lowercased.\n\t\t\thost : el.host,\n\n\t\t\t// The hostname portion of the host info, lowercased.\n\t\t\thostname : el.hostname,\n\n\t\t\t// The port number portion of the host info.\n\t\t\tport : el.port,\n\n\t\t\t// The full path information, including query info.\n\t\t\tpath : `${pathname}${el.search}`,\n\n\t\t\t// The pathname portion of the path info.\n\t\t\tpathname,\n\n\t\t\t// The query string portion of the path info, including the leading question mark.\n\t\t\tquery  : el.search,\n\t\t\tsearch : el.search,\n\n\t\t\t// The attributes portion of the query string, parsed into an object.\n\t\t\tqueries  : queryObj,\n\t\t\tsearches : queryObj,\n\n\t\t\t// The fragment string, including the leading hash/pound sign.\n\t\t\thash : el.hash\n\t\t};\n\t}\n\n\t/*\n\t\tReturns a new exception based on the given exception.\n\n\t\tNOTE: Mostly useful for making a standard JavaScript exception type copy\n\t\tof a host exception type—e.g. `DOMException` → `Error`.\n\t*/\n\tfunction utilNewExceptionFrom(original, exceptionType, override) {\n\t\tif (typeof original !== 'object' || original === null) {\n\t\t\tthrow new Error('Util.newExceptionFrom original parameter must be an object');\n\t\t}\n\t\tif (typeof exceptionType !== 'function') {\n\t\t\tthrow new Error('Util.newExceptionFrom exceptionType parameter must be an error type constructor');\n\t\t}\n\n\t\tconst ex = new exceptionType(original.message); // eslint-disable-line new-cap\n\n\t\tif (typeof original.name !== 'undefined') {\n\t\t\tex.name = original.name;\n\t\t}\n\t\tif (typeof original.code !== 'undefined') {\n\t\t\tex.code = original.code;\n\t\t}\n\t\tif (typeof original.columnNumber !== 'undefined') {\n\t\t\tex.columnNumber = original.columnNumber;\n\t\t}\n\t\tif (typeof original.description !== 'undefined') {\n\t\t\tex.description = original.description;\n\t\t}\n\t\tif (typeof original.fileName !== 'undefined') {\n\t\t\tex.fileName = original.fileName;\n\t\t}\n\t\tif (typeof original.lineNumber !== 'undefined') {\n\t\t\tex.lineNumber = original.lineNumber;\n\t\t}\n\t\tif (typeof original.number !== 'undefined') {\n\t\t\tex.number = original.number;\n\t\t}\n\t\tif (typeof original.stack !== 'undefined') {\n\t\t\tex.stack = original.stack;\n\t\t}\n\n\t\tconst overrideType = typeof override;\n\n\t\tif (overrideType !== 'undefined') {\n\t\t\tif (overrideType === 'object' && override !== null) {\n\t\t\t\tObject.assign(ex, override);\n\t\t\t}\n\t\t\telse if (overrideType === 'string') {\n\t\t\t\tex.message = override;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('Util.newExceptionFrom override parameter must be an object or string');\n\t\t\t}\n\t\t}\n\n\t\treturn ex;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tType Functions.\n\t\t*/\n\t\tgetType       : { value : utilGetType },\n\t\tisBoolean     : { value : utilIsBoolean },\n\t\tisIterable    : { value : utilIsIterable },\n\t\tisNumeric     : { value : utilIsNumeric },\n\t\tsameValueZero : { value : utilSameValueZero },\n\t\ttoEnum        : { value : utilToEnum },\n\t\ttoStringTag   : { value : utilToStringTag },\n\n\t\t/*\n\t\t\tString Encoding Functions.\n\t\t*/\n\t\tslugify      : { value : utilSlugify },\n\t\tescape       : { value : utilEscape },\n\t\tunescape     : { value : utilUnescape },\n\t\tcharAndPosAt : { value : utilCharAndPosAt },\n\n\t\t/*\n\t\t\tConversion Functions.\n\t\t*/\n\t\tfromCssTime      : { value : utilFromCssTime },\n\t\ttoCssTime        : { value : utilToCssTime },\n\t\tfromCssProperty  : { value : utilFromCssProperty },\n\t\tparseUrl         : { value : utilParseUrl },\n\t\tnewExceptionFrom : { value : utilNewExceptionFrom },\n\n\t\t/*\n\t\t\tTime Functions.\n\t\t*/\n\t\tnow : { value : utilNow },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\trandom         : { value : Math.random },\n\t\tentityEncode   : { value : utilEscape },\n\t\tentityDecode   : { value : utilUnescape },\n\t\tevalExpression : { value : (...args) => Scripting.evalJavaScript(...args) }, // SEE: `markup/scripting.js`.\n\t\tevalStatements : { value : (...args) => Scripting.evalJavaScript(...args) }  // SEE: `markup/scripting.js`.\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/simplestore.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar SimpleStore = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// In-order list of database adapters.\n\tconst _adapters = [];\n\n\t// The initialized adapter.\n\tlet _initialized = null;\n\n\n\t/*******************************************************************************************************************\n\t\tSimpleStore Functions.\n\t*******************************************************************************************************************/\n\tfunction storeCreate(storageId, persistent) {\n\t\tif (_initialized) {\n\t\t\treturn _initialized.create(storageId, persistent);\n\t\t}\n\n\t\t// Return the first adapter which successfully initializes, elsewise throw an exception.\n\t\tfor (let i = 0; i < _adapters.length; ++i) {\n\t\t\tif (_adapters[i].init(storageId, persistent)) {\n\t\t\t\t_initialized = _adapters[i];\n\t\t\t\treturn _initialized.create(storageId, persistent);\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error('no valid storage adapters found');\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tAdapters List.\n\n\t\t\tTODO: This should probably have a getter, rather than being exported directly.\n\t\t*/\n\t\tadapters : { value : _adapters },\n\n\t\t/*\n\t\t\tCore Functions.\n\t\t*/\n\t\tcreate : { value : storeCreate }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/FCHost.Storage.js\n\n\tCopyright © 2013–2019 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_FCHostStorageAdapter Class.\n        Note that FCHost is only intended for a single document, so we ignore both prefixing and storageID\n\t*******************************************************************************************************************/\n\tclass _FCHostStorageAdapter {\n\t\tconstructor(persistent) {\n\t\t\tlet engine = null;\n\t\t\tlet name   = null;\n\n\t\t\tif (persistent) {\n\t\t\t\tengine = window.FCHostPersistent;\n\t\t\t\tname   = 'FCHostPersistent';\n\t\t\t}\n\t\t\telse {\n\t\t\t    engine = window.FCHostSession;\n\t\t\t\tname   = 'FCHostSession';\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_engine : {\n\t\t\t\t\tvalue : engine\n\t\t\t\t},\n                \n\t\t\t\tname : {\n\t\t\t\t\tvalue : name\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\treturn this._engine.size();\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\treturn this._engine.size();\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\treturn this._engine.keys();\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn this._engine.has(key);\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = this._engine.get(key);\n\n\t\t\treturn value == null ? null : _FCHostStorageAdapter._deserialize(value); // lazy equality for null\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.set(key, _FCHostStorageAdapter._serialize(value));\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.remove(key);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tthis._engine.clear();\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn JSON.stringify(obj);\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse(str);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit() {\n\t\t// FCHost feature test.\n\t\tfunction hasFCHostStorage() {\n\t\t\ttry {\n\t\t\t    if (typeof window.FCHostPersistent !== 'undefined')\n\t\t\t        return true;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn false;\n\t\t}\n\n\t\t_ok = hasFCHostStorage();\n\t\t\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _FCHostStorageAdapter(persistent);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/webstorage.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_WebStorageAdapter Class.\n\t*******************************************************************************************************************/\n\tclass _WebStorageAdapter {\n\t\tconstructor(storageId, persistent) {\n\t\t\tconst prefix = `${storageId}.`;\n\t\t\tlet engine = null;\n\t\t\tlet name   = null;\n\n\t\t\tif (persistent) {\n\t\t\t\tengine = window.localStorage;\n\t\t\t\tname   = 'localStorage';\n\t\t\t}\n\t\t\telse {\n\t\t\t\tengine = window.sessionStorage;\n\t\t\t\tname   = 'sessionStorage';\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_engine : {\n\t\t\t\t\tvalue : engine\n\t\t\t\t},\n\n\t\t\t\t_prefix : {\n\t\t\t\t\tvalue : prefix\n\t\t\t\t},\n\n\t\t\t\t_prefixRe : {\n\t\t\t\t\tvalue : new RegExp(`^${RegExp.escape(prefix)}`)\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : name\n\t\t\t\t},\n\n\t\t\t\tid : {\n\t\t\t\t\tvalue : storageId\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\t/*\n\t\t\t\tNOTE: DO NOT do something like `return this._engine.length;` here,\n\t\t\t\tas that will return the length of the entire store, rather than\n\t\t\t\tjust our prefixed keys.\n\t\t\t*/\n\t\t\treturn this.keys().length;\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\t/*\n\t\t\t\tNOTE: DO NOT do something like `return this._engine.length;` here,\n\t\t\t\tas that will return the length of the entire store, rather than\n\t\t\t\tjust our prefixed keys.\n\t\t\t*/\n\t\t\treturn this.keys().length;\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\tconst keys = [];\n\n\t\t\tfor (let i = 0; i < this._engine.length; ++i) {\n\t\t\t\tconst key = this._engine.key(i);\n\n\t\t\t\tif (this._prefixRe.test(key)) {\n\t\t\t\t\tkeys.push(key.replace(this._prefixRe, ''));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn keys;\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// // FIXME: This method should probably check for the key, rather than comparing its value.\n\t\t\t// return this._engine.getItem(this._prefix + key) != null; // lazy equality for null\n\n\t\t\treturn this._engine.hasOwnProperty(this._prefix + key);\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = this._engine.getItem(this._prefix + key);\n\n\t\t\treturn value == null ? null : _WebStorageAdapter._deserialize(value); // lazy equality for null\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tthis._engine.setItem(this._prefix + key, _WebStorageAdapter._serialize(value));\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t/*\n\t\t\t\t\tIf the exception is a quota exceeded error, massage it into something\n\t\t\t\t\ta bit nicer for the player.\n\n\t\t\t\t\tNOTE: Ideally, we could simply do something like checking `ex.code`, but\n\t\t\t\t\tit's a non-standard property and not supported in all browsers.  Thus,\n\t\t\t\t\twe have to resort to pattern matching the name and message—the latter being\n\t\t\t\t\trequired by Opera (Presto).  I hate the parties responsible for this snafu\n\t\t\t\t\tso much.\n\t\t\t\t*/\n\t\t\t\tif (/quota.?(?:exceeded|reached)/i.test(ex.name + ex.message)) {\n\t\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `${this.name} quota exceeded`);\n\t\t\t\t}\n\n\t\t\t\tthrow ex;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.removeItem(this._prefix + key);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tconst keys = this.keys();\n\n\t\t\tfor (let i = 0, iend = keys.length; i < iend; ++i) {\n\t\t\t\tif (DEBUG) { console.log('\\tdeleting key:', keys[i]); }\n\n\t\t\t\tthis.delete(keys[i]);\n\t\t\t}\n\n\t\t\t// return this.keys().forEach(key => {\n\t\t\t// \tif (DEBUG) { console.log('\\tdeleting key:', key); }\n\t\t\t//\n\t\t\t// \tthis.delete(key);\n\t\t\t// });\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn JSON.stringify(obj);\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse((!str || str[0] == \"{\") ? str : LZString.decompressFromUTF16(str));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit() {\n\t\t// Web Storage feature test.\n\t\tfunction hasWebStorage(storeId) {\n\t\t\ttry {\n\t\t\t\tconst store = window[storeId];\n\t\t\t\tconst tid   = `_sc_${String(Date.now())}`;\n\t\t\t\tstore.setItem(tid, tid);\n\t\t\t\tconst result = store.getItem(tid) === tid;\n\t\t\t\tstore.removeItem(tid);\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn false;\n\t\t}\n\n\t\t/*\n\t\t\tJust to be safe, we feature test for both `localStorage` and `sessionStorage`,\n\t\t\tas you never know what browser implementation bugs you're going to run into.\n\t\t*/\n\t\t_ok = hasWebStorage('localStorage') && hasWebStorage('sessionStorage');\n\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _WebStorageAdapter(storageId, persistent);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/cookie.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Expiry constants.\n\tconst _MAX_EXPIRY = 'Tue, 19 Jan 2038 03:14:07 GMT'; // (new Date((Math.pow(2, 31) - 1) * 1000)).toUTCString()\n\tconst _MIN_EXPIRY = 'Thu, 01 Jan 1970 00:00:00 GMT'; // (new Date(0)).toUTCString()\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_CookieAdapter Class.\n\t*******************************************************************************************************************/\n\tclass _CookieAdapter {\n\t\tconstructor(storageId, persistent) {\n\t\t\tconst prefix = `${storageId}${persistent ? '!' : '*'}.`;\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_prefix : {\n\t\t\t\t\tvalue : prefix\n\t\t\t\t},\n\n\t\t\t\t_prefixRe : {\n\t\t\t\t\tvalue : new RegExp(`^${RegExp.escape(prefix)}`)\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : 'cookie'\n\t\t\t\t},\n\n\t\t\t\tid : {\n\t\t\t\t\tvalue : storageId\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\treturn this.keys().length;\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\treturn this.keys().length;\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\tif (document.cookie === '') {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst cookies = document.cookie.split(/;\\s*/);\n\t\t\tconst keys    = [];\n\n\t\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\t\tif (this._prefixRe.test(key)) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\t\tnot a serialized empty string, so we should omit such pairs.\n\t\t\t\t\t*/\n\t\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\t\tif (value !== '') {\n\t\t\t\t\t\tkeys.push(key.replace(this._prefixRe, ''));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn keys;\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn _CookieAdapter._getCookie(this._prefix + key) !== null;\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = _CookieAdapter._getCookie(this._prefix + key);\n\n\t\t\treturn value === null ? null : _CookieAdapter._deserialize(value);\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\tthis._prefix + key,\n\t\t\t\t\t_CookieAdapter._serialize(value),\n\n\t\t\t\t\t// An undefined expiry denotes a session cookie.\n\t\t\t\t\tthis.persistent ? _MAX_EXPIRY : undefined\n\t\t\t\t);\n\n\t\t\t\tif (!this.has(key)) {\n\t\t\t\t\tthrow new Error('unknown validation error during set');\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t// Massage the cookie exception into something a bit nicer for the player.\n\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `cookie error: ${ex.message}`);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\t/*\n\t\t\t\tAttempting to delete a cookie implies setting it, so we test for its existence\n\t\t\t\tbeforehand, to avoid creating it in the event that it does not already exist.\n\t\t\t*/\n\t\t\tif (typeof key !== 'string' || !key || !this.has(key)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\tthis._prefix + key,\n\n\t\t\t\t\t// Use `undefined` as the value.\n\t\t\t\t\tundefined,\n\n\t\t\t\t\t// Use the epoch as the expiry.\n\t\t\t\t\t_MIN_EXPIRY\n\t\t\t\t);\n\n\t\t\t\tif (this.has(key)) {\n\t\t\t\t\tthrow new Error('unknown validation error during delete');\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t// Massage the cookie exception into something a bit nicer for the player.\n\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `cookie error: ${ex.message}`);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tconst keys = this.keys();\n\n\t\t\tfor (let i = 0, iend = keys.length; i < iend; ++i) {\n\t\t\t\tif (DEBUG) { console.log('\\tdeleting key:', keys[i]); }\n\n\t\t\t\tthis.delete(keys[i]);\n\t\t\t}\n\n\t\t\t// this.keys().forEach(key => {\n\t\t\t// \tif (DEBUG) { console.log('\\tdeleting key:', key); }\n\t\t\t//\n\t\t\t// \tthis.delete(key);\n\t\t\t// });\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _getCookie(prefixedKey) {\n\t\t\tif (!prefixedKey || document.cookie === '') {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst cookies = document.cookie.split(/;\\s*/);\n\n\t\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\t\tif (prefixedKey === key) {\n\t\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\t\tnot a serialized empty string, so we should yield `null` for such pairs.\n\t\t\t\t\t*/\n\t\t\t\t\treturn value || null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tstatic _setCookie(prefixedKey, value, expiry) {\n\t\t\tif (!prefixedKey) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet payload = `${encodeURIComponent(prefixedKey)}=`;\n\n\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\tpayload += encodeURIComponent(value);\n\t\t\t}\n\n\t\t\tif (expiry != null) { // lazy equality for null\n\t\t\t\tpayload += `; expires=${expiry}`;\n\t\t\t}\n\n\t\t\tpayload += '; path=/';\n\t\t\tdocument.cookie = payload;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn LZString.compressToBase64(JSON.stringify(obj));\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse(LZString.decompressFromBase64(str));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit(\n\t\t// Only used for stores updates.\n\t\tstorageId\n\t) {\n\t\t// Cookie feature test.\n\t\ttry {\n\t\t\tconst tid = `_sc_${String(Date.now())}`;\n\n\t\t\t// We only test a session cookie as that should suffice.\n\t\t\t_CookieAdapter._setCookie(tid, _CookieAdapter._serialize(tid), undefined);\n\t\t\t_ok = _CookieAdapter._deserialize(_CookieAdapter._getCookie(tid)) === tid;\n\t\t\t_CookieAdapter._setCookie(tid, undefined, _MIN_EXPIRY);\n\t\t}\n\t\tcatch (ex) {\n\t\t\t_ok = false;\n\t\t}\n\n\t\t/* legacy */\n\t\t// Attempt to update the cookie stores, if necessary.  This should happen only during initialization.\n\t\tif (_ok) {\n\t\t\t_updateCookieStores(storageId);\n\t\t}\n\t\t/* /legacy */\n\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _CookieAdapter(storageId, persistent);\n\t}\n\n\t/* legacy */\n\t// Updates old non-segmented cookie stores into segmented stores.\n\tfunction _updateCookieStores(storageId) {\n\t\tif (document.cookie === '') {\n\t\t\treturn;\n\t\t}\n\n\t\tconst oldPrefix     = `${storageId}.`;\n\t\tconst oldPrefixRe   = new RegExp(`^${RegExp.escape(oldPrefix)}`);\n\t\tconst persistPrefix = `${storageId}!.`;\n\t\tconst sessionPrefix = `${storageId}*.`;\n\t\tconst sessionTestRe = /\\.(?:state|rcWarn)$/;\n\t\tconst cookies       = document.cookie.split(/;\\s*/);\n\n\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\tif (oldPrefixRe.test(key)) {\n\t\t\t\t/*\n\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\tnot a serialized empty string, so we should skip processing such pairs.\n\t\t\t\t*/\n\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\tif (value !== '') {\n\t\t\t\t\tconst persist = !sessionTestRe.test(key);\n\n\t\t\t\t\t// Delete the old k/v pair.\n\t\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t_MIN_EXPIRY\n\t\t\t\t\t);\n\n\t\t\t\t\t// Set the new k/v pair.\n\t\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\t\tkey.replace(oldPrefixRe, () => persist ? persistPrefix : sessionPrefix),\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tpersist ? _MAX_EXPIRY : undefined\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t/* /legacy */\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/debugview.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tTODO: Make this use jQuery throughout.\n*/\nvar DebugView = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tDebugView Class.\n\t*******************************************************************************************************************/\n\tclass DebugView {\n\t\tconstructor(parent, type, name, title) {\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tparent : {\n\t\t\t\t\tvalue : parent\n\t\t\t\t},\n\n\t\t\t\tview : {\n\t\t\t\t\tvalue : document.createElement('span')\n\t\t\t\t},\n\n\t\t\t\tbreak : {\n\t\t\t\t\tvalue : document.createElement('wbr')\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Set up the wrapper (`<span>`) element.\n\t\t\tjQuery(this.view)\n\t\t\t\t.attr({\n\t\t\t\t\ttitle,\n\t\t\t\t\t'aria-label' : title,\n\t\t\t\t\t'data-type'  : type != null ? type : '', // lazy equality for null\n\t\t\t\t\t'data-name'  : name != null ? name : ''  // lazy equality for null\n\t\t\t\t})\n\t\t\t\t.addClass('debug');\n\n\t\t\t// Set up the word break (`<wbr>`) element.\n\t\t\tjQuery(this.break).addClass('debug hidden');\n\n\t\t\t// Add the wrapper (`<span>`) and word break (`<wbr>`) elements to the `parent` element.\n\t\t\tthis.parent.appendChild(this.view);\n\t\t\tthis.parent.appendChild(this.break);\n\t\t}\n\n\t\tget output() {\n\t\t\treturn this.view;\n\t\t}\n\n\t\tget type() {\n\t\t\treturn this.view.getAttribute('data-type');\n\t\t}\n\t\tset type(type) {\n\t\t\tthis.view.setAttribute('data-type', type != null ? type : ''); // lazy equality for null\n\t\t}\n\n\t\tget name() {\n\t\t\treturn this.view.getAttribute('data-name');\n\t\t}\n\t\tset name(name) {\n\t\t\tthis.view.setAttribute('data-name', name != null ? name : ''); // lazy equality for null\n\t\t}\n\n\t\tget title() {\n\t\t\treturn this.view.title;\n\t\t}\n\t\tset title(title) {\n\t\t\tthis.view.title = title;\n\t\t}\n\n\t\tappend(el) {\n\t\t\tjQuery(this.view).append(el);\n\t\t\treturn this;\n\t\t}\n\n\t\tmodes(options) {\n\t\t\tif (options == null) { // lazy equality for null\n\t\t\t\tconst current = {};\n\n\t\t\t\tthis.view.className.splitOrEmpty(/\\s+/).forEach(name => {\n\t\t\t\t\tif (name !== 'debug') {\n\t\t\t\t\t\tcurrent[name] = true;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\treturn current;\n\t\t\t}\n\t\t\telse if (typeof options === 'object') {\n\t\t\t\tObject.keys(options).forEach(function (name) {\n\t\t\t\t\tthis[options[name] ? 'addClass' : 'removeClass'](name);\n\t\t\t\t}, jQuery(this.view));\n\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tthrow new Error('DebugView.prototype.modes options parameter must be an object or null/undefined');\n\t\t}\n\n\t\tremove() {\n\t\t\tconst $view = jQuery(this.view);\n\n\t\t\tif (this.view.hasChildNodes()) {\n\t\t\t\t$view.contents().appendTo(this.parent);\n\t\t\t}\n\n\t\t\t$view.remove();\n\t\t\tjQuery(this.break).remove();\n\t\t}\n\n\t\tstatic isEnabled() {\n\t\t\treturn jQuery(document.documentElement).attr('data-debug-view') === 'enabled';\n\t\t}\n\n\t\tstatic enable() {\n\t\t\tjQuery(document.documentElement).attr('data-debug-view', 'enabled');\n\t\t\tjQuery.event.trigger(':debugviewupdate');\n\t\t}\n\n\t\tstatic disable() {\n\t\t\tjQuery(document.documentElement).removeAttr('data-debug-view');\n\t\t\tjQuery.event.trigger(':debugviewupdate');\n\t\t}\n\n\t\tstatic toggle() {\n\t\t\tif (jQuery(document.documentElement).attr('data-debug-view') === 'enabled') {\n\t\t\t\tDebugView.disable();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tDebugView.enable();\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn DebugView;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/prngwrapper.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar PRNGWrapper = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tPRNGWrapper Class.\n\t*******************************************************************************************************************/\n\tclass PRNGWrapper {\n\t\tconstructor(seed, useEntropy) {\n\t\t\t/* eslint-disable new-cap */\n\t\t\tObject.defineProperties(this, new Math.seedrandom(seed, useEntropy, (prng, seed) => ({\n\t\t\t\t_prng : {\n\t\t\t\t\tvalue : prng\n\t\t\t\t},\n\n\t\t\t\tseed : {\n\t\t\t\t\t/*\n\t\t\t\t\t\tTODO: Make this non-writable.\n\t\t\t\t\t*/\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : seed\n\t\t\t\t},\n\n\t\t\t\tpull : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\trandom : {\n\t\t\t\t\tvalue() {\n\t\t\t\t\t\t++this.pull;\n\t\t\t\t\t\treturn this._prng();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})));\n\t\t\t/* eslint-enable new-cap */\n\t\t}\n\n\t\tstatic marshal(prng) {\n\t\t\tif (!prng || !prng.hasOwnProperty('seed') || !prng.hasOwnProperty('pull')) {\n\t\t\t\tthrow new Error('PRNG is missing required data');\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tseed : prng.seed,\n\t\t\t\tpull : prng.pull\n\t\t\t};\n\t\t}\n\n\t\tstatic unmarshal(prngObj) {\n\t\t\tif (!prngObj || !prngObj.hasOwnProperty('seed') || !prngObj.hasOwnProperty('pull')) {\n\t\t\t\tthrow new Error('PRNG object is missing required data');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tCreate a new PRNG using the original seed and pull values from it until it\n\t\t\t\thas reached the original pull count.\n\t\t\t*/\n\t\t\tconst prng = new PRNGWrapper(prngObj.seed, false);\n\n\t\t\tfor (let i = prngObj.pull; i > 0; --i) {\n\t\t\t\tprng.random();\n\t\t\t}\n\n\t\t\treturn prng;\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn PRNGWrapper;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/stylewrapper.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns, Story, Wikifier */\n\nvar StyleWrapper = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tconst _imageMarkupRe    = new RegExp(Patterns.cssImage, 'g');\n\tconst _hasImageMarkupRe = new RegExp(Patterns.cssImage);\n\n\n\t/*******************************************************************************************************************\n\t\tStyleWrapper Class.\n\t*******************************************************************************************************************/\n\tclass StyleWrapper {\n\t\tconstructor(style) {\n\t\t\tif (style == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('StyleWrapper style parameter must be an HTMLStyleElement object');\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tstyle : {\n\t\t\t\t\tvalue : style\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tisEmpty() {\n\t\t\t// This should work in all supported browsers.\n\t\t\treturn this.style.cssRules.length === 0;\n\t\t}\n\n\t\tset(rawCss) {\n\t\t\tthis.clear();\n\t\t\tthis.add(rawCss);\n\t\t}\n\n\t\tadd(rawCss) {\n\t\t\tlet css = rawCss;\n\n\t\t\t// Check for wiki image transclusion.\n\t\t\tif (_hasImageMarkupRe.test(css)) {\n\t\t\t\t/*\n\t\t\t\t\tThe JavaScript specifications, since at least ES3, say that `<String>.replace()`\n\t\t\t\t\tshould reset a global-flagged regular expression's `lastIndex` property to `0`\n\t\t\t\t\tupon invocation.  Buggy browser versions exist, however, which do not reset\n\t\t\t\t\t`lastIndex`, so we should do so manually to support those browsers.\n\n\t\t\t\t\tNOTE: I do not think this is actually necessary, since `_imageMarkupRe` is\n\t\t\t\t\tscoped to this module—meaning users should not be able to access it.  That\n\t\t\t\t\tbeing the case, and since we search to exhaustion which should also cause\n\t\t\t\t\t`lastIndex` to be reset, there should never be an instance where we invoke\n\t\t\t\t\t`css.replace()` and `_imageMarkupRe.lastIndex` is not already `0`.  Still,\n\t\t\t\t\tconsidering the other bug, better safe than sorry.\n\t\t\t\t*/\n\t\t\t\t_imageMarkupRe.lastIndex = 0;\n\n\t\t\t\tcss = css.replace(_imageMarkupRe, wikiImage => {\n\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\tsource     : wikiImage,\n\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t});\n\n\t\t\t\t\tif (markup.hasOwnProperty('error') || markup.pos < wikiImage.length) {\n\t\t\t\t\t\treturn wikiImage;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet source = markup.source;\n\n\t\t\t\t\t// Handle image passage transclusion.\n\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\tsource = passage.text.trim();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tThe source may be URI- or Base64-encoded, so we cannot use `encodeURIComponent()`\n\t\t\t\t\t\there.  Instead, we simply encode any double quotes, since the URI will be\n\t\t\t\t\t\tdelimited by them.\n\t\t\t\t\t*/\n\t\t\t\t\treturn `url(\"${source.replace(/\"/g, '%22')}\")`;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// For IE ≤ 10.\n\t\t\tif (this.style.styleSheet) {\n\t\t\t\tthis.style.styleSheet.cssText += css;\n\t\t\t}\n\n\t\t\t// For all other browsers (incl. IE ≥ 11).\n\t\t\telse {\n\t\t\t\tthis.style.appendChild(document.createTextNode(css));\n\t\t\t}\n\t\t}\n\n\t\tclear() {\n\t\t\t// For IE ≤10.\n\t\t\tif (this.style.styleSheet) {\n\t\t\t\tthis.style.styleSheet.cssText = '';\n\t\t\t}\n\n\t\t\t// For all other browsers (incl. IE ≥11).\n\t\t\telse {\n\t\t\t\tjQuery(this.style).empty();\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn StyleWrapper;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/diff.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util, clone */\n\nvar Diff = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tDiff Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tDiff operations object (pseudo-enumeration).\n\t*/\n\tconst Op = Util.toEnum({\n\t\tDelete      : 0,\n\t\tSpliceArray : 1,\n\t\tCopy        : 2,\n\t\tCopyDate    : 3\n\t});\n\n\t/*\n\t\tReturns a difference object generated from comparing the the orig and dest objects.\n\t*/\n\tfunction diff(orig, dest) /* diff object */ {\n\t\tconst objToString = Object.prototype.toString;\n\t\tconst origIsArray = orig instanceof Array;\n\t\tconst keys        = []\n\t\t\t.concat(Object.keys(orig), Object.keys(dest))\n\t\t\t.sort()\n\t\t\t.filter((val, i, arr) => i === 0 || arr[i - 1] !== val);\n\t\tconst diffed      = {};\n\t\tlet aOpRef;\n\n\t\tconst keyIsAOpRef = key => key === aOpRef;\n\n\t\t/* eslint-disable max-depth */\n\t\tfor (let i = 0, klen = keys.length; i < klen; ++i) {\n\t\t\tconst key   = keys[i];\n\t\t\tconst origP = orig[key];\n\t\t\tconst destP = dest[key];\n\n\t\t\tif (orig.hasOwnProperty(key)) {\n\t\t\t\t// Key exists in both.\n\t\t\t\tif (dest.hasOwnProperty(key)) {\n\t\t\t\t\t// Values are exactly the same, so do nothing.\n\t\t\t\t\tif (origP === destP) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Values are of the same basic type.\n\t\t\t\t\tif (typeof origP === typeof destP) { // eslint-disable-line valid-typeof\n\t\t\t\t\t\t// Values are functions.\n\t\t\t\t\t\tif (typeof origP === 'function') {\n\t\t\t\t\t\t\t/* diffed[key] = [Op.Copy, destP]; */\n\t\t\t\t\t\t\tif (origP.toString() !== destP.toString()) {\n\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, destP];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Values are primitives.\n\t\t\t\t\t\telse if (typeof origP !== 'object' || origP === null) {\n\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, destP];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Values are objects.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst origPType = objToString.call(origP);\n\t\t\t\t\t\t\tconst destPType = objToString.call(destP);\n\n\t\t\t\t\t\t\t// Values are objects of the same reported type.\n\t\t\t\t\t\t\tif (origPType === destPType) {\n\t\t\t\t\t\t\t\t// Various special cases to handle supported non-generic objects.\n\t\t\t\t\t\t\t\tif (origP instanceof Date) {\n\t\t\t\t\t\t\t\t\tif (Number(origP) !== Number(destP)) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof Map) {\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof RegExp) {\n\t\t\t\t\t\t\t\t\tif (origP.toString() !== destP.toString()) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof Set) {\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Unknown non-generic objects (custom or unsupported natives).\n\t\t\t\t\t\t\t\telse if (origPType !== '[object Object]') {\n\t\t\t\t\t\t\t\t\t// We cannot know how to process these objects,\n\t\t\t\t\t\t\t\t\t// so we simply accept them as-is.\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Generic objects.\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tconst recurse = diff(origP, destP);\n\n\t\t\t\t\t\t\t\t\tif (recurse !== null) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = recurse;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Values are objects of different reported types.\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Values are of different types.\n\t\t\t\t\telse {\n\t\t\t\t\t\tdiffed[key] = [\n\t\t\t\t\t\t\tOp.Copy,\n\t\t\t\t\t\t\ttypeof destP !== 'object' || destP === null ? destP : clone(destP)\n\t\t\t\t\t\t];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Key only exists in orig.\n\t\t\t\telse {\n\t\t\t\t\tif (origIsArray && Util.isNumeric(key)) {\n\t\t\t\t\t\tconst nKey = Number(key);\n\n\t\t\t\t\t\tif (!aOpRef) {\n\t\t\t\t\t\t\taOpRef = '';\n\n\t\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\t\taOpRef += '~';\n\t\t\t\t\t\t\t} while (keys.some(keyIsAOpRef));\n\n\t\t\t\t\t\t\tdiffed[aOpRef] = [Op.SpliceArray, nKey, nKey];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (nKey < diffed[aOpRef][1]) {\n\t\t\t\t\t\t\tdiffed[aOpRef][1] = nKey;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (nKey > diffed[aOpRef][2]) {\n\t\t\t\t\t\t\tdiffed[aOpRef][2] = nKey;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdiffed[key] = Op.Delete;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Key only exists in dest.\n\t\t\telse {\n\t\t\t\tdiffed[key] = [\n\t\t\t\t\tOp.Copy,\n\t\t\t\t\ttypeof destP !== 'object' || destP === null ? destP : clone(destP)\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\t\t/* eslint-enable max-depth */\n\n\t\treturn Object.keys(diffed).length > 0 ? diffed : null;\n\t}\n\n\t/*\n\t\tReturns the object resulting from updating the orig object with the diffed object.\n\t*/\n\tfunction patch(orig, diffed) /* patched object */ {\n\t\tconst keys    = Object.keys(diffed || {});\n\t\tconst patched = clone(orig);\n\n\t\tfor (let i = 0, klen = keys.length; i < klen; ++i) {\n\t\t\tconst key     = keys[i];\n\t\t\tconst diffedP = diffed[key];\n\n\t\t\tif (diffedP === Op.Delete) {\n\t\t\t\tdelete patched[key];\n\t\t\t}\n\t\t\telse if (diffedP instanceof Array) {\n\t\t\t\tswitch (diffedP[0]) {\n\t\t\t\tcase Op.SpliceArray:\n\t\t\t\t\tpatched.splice(diffedP[1], 1 + (diffedP[2] - diffedP[1]));\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase Op.Copy:\n\t\t\t\t\tpatched[key] = clone(diffedP[1]);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase Op.CopyDate:\n\t\t\t\t\tpatched[key] = new Date(diffedP[1]);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tpatched[key] = patch(patched[key], diffedP);\n\t\t\t}\n\t\t}\n\n\t\treturn patched;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tOp    : { value : Op },\n\t\tdiff  : { value : diff },\n\t\tpatch : { value : patch }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tl10n/l10n.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global l10nStrings, strings */\n\nvar L10n = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Replacement pattern regular expressions.\n\tconst _patternRe    = /\\{\\w+\\}/g;\n\tconst _hasPatternRe = new RegExp(_patternRe.source); // to drop the global flag\n\n\n\t/*******************************************************************************************************************\n\t\tLocalization Functions.\n\t*******************************************************************************************************************/\n\tfunction l10nInit() {\n\t\t/* legacy */\n\t\t_mapStringsToL10nStrings();\n\t\t/* /legacy */\n\t}\n\n\t/*******************************************************************************************************************\n\t\tLocalized String Functions.\n\t*******************************************************************************************************************/\n\tfunction l10nGet(ids, overrides) {\n\t\tif (!ids) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst id = (idList => {\n\t\t\tlet selectedId;\n\t\t\tidList.some(id => {\n\t\t\t\tif (l10nStrings.hasOwnProperty(id)) {\n\t\t\t\t\tselectedId = id;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\treturn selectedId;\n\t\t})(Array.isArray(ids) ? ids : [ids]);\n\n\t\tif (!id) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst maxIterations = 50;\n\t\tlet processed = l10nStrings[id];\n\t\tlet iteration = 0;\n\n\t\twhile (_hasPatternRe.test(processed)) {\n\t\t\tif (++iteration > maxIterations) {\n\t\t\t\tthrow new Error('L10n.get exceeded maximum replacement iterations, probable infinite loop');\n\t\t\t}\n\n\t\t\t// Possibly required by some old buggy browsers.\n\t\t\t_patternRe.lastIndex = 0;\n\n\t\t\tprocessed = processed.replace(_patternRe, pat => {\n\t\t\t\tconst subId = pat.slice(1, -1);\n\n\t\t\t\tif (overrides && overrides.hasOwnProperty(subId)) {\n\t\t\t\t\treturn overrides[subId];\n\t\t\t\t}\n\t\t\t\telse if (l10nStrings.hasOwnProperty(subId)) {\n\t\t\t\t\treturn l10nStrings[subId];\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treturn processed;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tLegacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tAttempt to map legacy `strings` object properties to the `l10nStrings` object.\n\t*/\n\tfunction _mapStringsToL10nStrings() {\n\t\tif (strings && Object.keys(strings).length > 0) {\n\t\t\tObject.keys(l10nStrings).forEach(id => {\n\t\t\t\ttry {\n\t\t\t\t\tlet value;\n\n\t\t\t\t\tswitch (id) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tGeneral.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'identity': value = strings.identity; break;\n\t\t\t\t\tcase 'aborting': value = strings.aborting; break;\n\t\t\t\t\tcase 'cancel':   value = strings.cancel; break;\n\t\t\t\t\tcase 'close':    value = strings.close; break;\n\t\t\t\t\tcase 'ok':       value = strings.ok; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tErrors.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'errorTitle':              value = strings.errors.title; break;\n\t\t\t\t\tcase 'errorNonexistentPassage': value = strings.errors.nonexistentPassage; break;\n\t\t\t\t\tcase 'errorSaveMissingData':    value = strings.errors.saveMissingData; break;\n\t\t\t\t\tcase 'errorSaveIdMismatch':     value = strings.errors.saveIdMismatch; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tWarnings.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'warningDegraded': value = strings.warnings.degraded; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tDebug View.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'debugViewTitle':  value = strings.debugView.title; break;\n\t\t\t\t\tcase 'debugViewToggle': value = strings.debugView.toggle; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tUI bar.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'uiBarToggle':   value = strings.uiBar.toggle; break;\n\t\t\t\t\tcase 'uiBarBackward': value = strings.uiBar.backward; break;\n\t\t\t\t\tcase 'uiBarForward':  value = strings.uiBar.forward; break;\n\t\t\t\t\tcase 'uiBarJumpto':   value = strings.uiBar.jumpto; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tJump To.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'jumptoTitle':       value = strings.jumpto.title; break;\n\t\t\t\t\tcase 'jumptoTurn':        value = strings.jumpto.turn; break;\n\t\t\t\t\tcase 'jumptoUnavailable': value = strings.jumpto.unavailable; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tSaves.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'savesTitle':       value = strings.saves.title; break;\n\t\t\t\t\tcase 'savesDisallowed':  value = strings.saves.disallowed; break;\n\t\t\t\t\tcase 'savesIncapable':   value = strings.saves.incapable; break;\n\t\t\t\t\tcase 'savesLabelAuto':   value = strings.saves.labelAuto; break;\n\t\t\t\t\tcase 'savesLabelDelete': value = strings.saves.labelDelete; break;\n\t\t\t\t\tcase 'savesLabelExport': value = strings.saves.labelExport; break;\n\t\t\t\t\tcase 'savesLabelImport': value = strings.saves.labelImport; break;\n\t\t\t\t\tcase 'savesLabelLoad':   value = strings.saves.labelLoad; break;\n\t\t\t\t\tcase 'savesLabelClear':  value = strings.saves.labelClear; break;\n\t\t\t\t\tcase 'savesLabelSave':   value = strings.saves.labelSave; break;\n\t\t\t\t\tcase 'savesLabelSlot':   value = strings.saves.labelSlot; break;\n\t\t\t\t\tcase 'savesUnavailable': value = strings.saves.unavailable; break;\n\t\t\t\t\tcase 'savesUnknownDate': value = strings.saves.unknownDate; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tSettings.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'settingsTitle': value = strings.settings.title; break;\n\t\t\t\t\tcase 'settingsOff':   value = strings.settings.off; break;\n\t\t\t\t\tcase 'settingsOn':    value = strings.settings.on; break;\n\t\t\t\t\tcase 'settingsReset': value = strings.settings.reset; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tRestart.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'restartTitle':  value = strings.restart.title; break;\n\t\t\t\t\tcase 'restartPrompt': value = strings.restart.prompt; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tShare.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'shareTitle': value = strings.share.title; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAlert.\n\t\t\t\t\t*/\n\t\t\t\t\t/* none */\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAutoload.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'autoloadTitle':  value = strings.autoload.title; break;\n\t\t\t\t\tcase 'autoloadCancel': value = strings.autoload.cancel; break;\n\t\t\t\t\tcase 'autoloadOk':     value = strings.autoload.ok; break;\n\t\t\t\t\tcase 'autoloadPrompt': value = strings.autoload.prompt; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tMacros.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'macroBackText':   value = strings.macros.back.text; break;\n\t\t\t\t\tcase 'macroReturnText': value = strings.macros.return.text; break;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (value) {\n\t\t\t\t\t\tl10nStrings[id] = value.replace(/%\\w+%/g, pat => `{${pat.slice(1, -1)}}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t});\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tLocalization Functions.\n\t\t*/\n\t\tinit : { value : l10nInit },\n\n\t\t/*\n\t\t\tLocalized String Functions.\n\t\t*/\n\t\tget : { value : l10nGet }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tl10n/legacy.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\t[DEPRECATED] The `strings` object is deprecated and should no longer be used.\n\tAll new or updated translations should be based upon the `l10nStrings` object\n\t(see: `l10n/strings.js`).\n\n\tLegacy/existing uses of the `strings` object will be mapped to the `l10nStrings`\n\tobject after user script evaluation.\n*/\nvar strings = { // eslint-disable-line no-unused-vars, no-var\n\terrors    : {},\n\twarnings  : {},\n\tdebugView : {},\n\tuiBar     : {},\n\tjumpto    : {},\n\tsaves     : {},\n\tsettings  : {},\n\trestart   : {},\n\tshare     : {},\n\tautoload  : {},\n\tmacros    : {\n\t\tback   : {},\n\t\treturn : {}\n\t}\n};\n\n/***********************************************************************************************************************\n\n\tl10n/strings.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* eslint-disable max-len, prefer-template */\n\n/*\n\tATTENTION TRANSLATORS\n\n\tPlease use the `locale/l10n-template.js` file, from the root of the repository,\n\tas the template for your translation rather than this file.\n\n\tSEE: https://github.com/tmedwards/sugarcube-2/tree/develop/locale\n*/\nvar l10nStrings = { // eslint-disable-line no-unused-vars, no-var\n\t/*\n\t\tGeneral.\n\t*/\n\tidentity : 'game',\n\taborting : 'Aborting',\n\tcancel   : 'Cancel',\n\tclose    : 'Close',\n\tok       : 'OK',\n\n\t/*\n\t\tErrors.\n\t*/\n\terrorTitle              : 'Error',\n\terrorToggle             : 'Toggle the error view',\n\terrorNonexistentPassage : 'the passage \"{passage}\" does not exist', // NOTE: `passage` is supplied locally\n\terrorSaveMissingData    : 'save is missing required data. Either the loaded file is not a save or the save has become corrupted',\n\terrorSaveIdMismatch     : 'save is from the wrong {identity}',\n\n\t/*\n\t\tWarnings.\n\t*/\n\t_warningIntroLacking  : 'Your browser either lacks or has disabled',\n\t_warningOutroDegraded : ', so this {identity} is running in a degraded mode. You may be able to continue, however, some parts may not work properly.',\n\twarningNoWebStorage   : '{_warningIntroLacking} the Web Storage API{_warningOutroDegraded}',\n\twarningDegraded       : '{_warningIntroLacking} some of the capabilities required by this {identity}{_warningOutroDegraded}',\n\n\t/*\n\t\tDebug bar.\n\t*/\n\tdebugBarToggle      : 'Toggle the debug bar',\n\tdebugBarNoWatches   : '\\u2014 no watches set \\u2014',\n\tdebugBarAddWatch    : 'Add watch',\n\tdebugBarDeleteWatch : 'Delete watch',\n\tdebugBarWatchAll    : 'Watch all',\n\tdebugBarWatchNone   : 'Delete all',\n\tdebugBarLabelAdd    : 'Add',\n\tdebugBarLabelWatch  : 'Watch',\n\tdebugBarLabelTurn   : 'Turn', // (noun) chance to act (in a game), moment, period\n\tdebugBarLabelViews  : 'Views',\n\tdebugBarViewsToggle : 'Toggle the debug views',\n\tdebugBarWatchToggle : 'Toggle the watch panel',\n\n\t/*\n\t\tUI bar.\n\t*/\n\tuiBarToggle   : 'Toggle the UI bar',\n\tuiBarBackward : 'Go backward within the {identity} history',\n\tuiBarForward  : 'Go forward within the {identity} history',\n\tuiBarJumpto   : 'Jump to a specific point within the {identity} history',\n\n\t/*\n\t\tJump To.\n\t*/\n\tjumptoTitle       : 'Jump To',\n\tjumptoTurn        : 'Turn', // (noun) chance to act (in a game), moment, period\n\tjumptoUnavailable : 'No jump points currently available\\u2026',\n\n\t/*\n\t\tSaves.\n\t*/\n\tsavesTitle       : 'Saves',\n\tsavesDisallowed  : 'Saving has been disallowed on this passage.',\n\tsavesIncapable   : '{_warningIntroLacking} the capabilities required to support saves, so saves have been disabled for this session.',\n\tsavesLabelAuto   : 'Autosave',\n\tsavesLabelDelete : 'Delete',\n\tsavesLabelExport : 'Save to Disk\\u2026',\n\tsavesLabelImport : 'Load from Disk\\u2026',\n\tsavesLabelLoad   : 'Load',\n\tsavesLabelClear  : 'Delete All',\n\tsavesLabelSave   : 'Save',\n\tsavesLabelSlot   : 'Slot',\n\tsavesUnavailable : 'No save slots found\\u2026',\n\tsavesUnknownDate : 'unknown',\n\n\t/*\n\t\tSettings.\n\t*/\n\tsettingsTitle : 'Settings',\n\tsettingsOff   : 'Off',\n\tsettingsOn    : 'On',\n\tsettingsReset : 'Reset to Defaults',\n\n\t/*\n\t\tRestart.\n\t*/\n\trestartTitle  : 'Restart',\n\trestartPrompt : 'Are you sure that you want to restart? Unsaved progress will be lost.',\n\n\t/*\n\t\tShare.\n\t*/\n\tshareTitle : 'Share',\n\n\t/*\n\t\tAlert.\n\t*/\n\t/* none */\n\n\t/*\n\t\tAutoload.\n\t*/\n\tautoloadTitle  : 'Autoload',\n\tautoloadCancel : 'Go to start',\n\tautoloadOk     : 'Load autosave',\n\tautoloadPrompt : 'An autosave exists. Load it now or go to the start?',\n\n\t/*\n\t\tMacros.\n\t*/\n\tmacroBackText   : 'Back',  // (verb) rewind, revert\n\tmacroReturnText : 'Return' // (verb) go/send back\n};\n\n/***********************************************************************************************************************\n\n\tconfig.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util */\n\nvar Config = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// General settings.\n\tlet _debug                 = false;\n\tlet _addVisitedLinkClass   = false;\n\tlet _cleanupWikifierOutput = false;\n\tlet _loadDelay             = 0;\n\n\t// Audio settings.\n\tlet _audioPauseOnFadeToZero = true;\n\tlet _audioPreloadMetadata   = true;\n\n\t// State history settings.\n\tlet _historyControls  = true;\n\tlet _historyMaxStates = 100;\n\n\t// Macros settings.\n\tlet _macrosIfAssignmentError = true;\n\tlet _macrosMaxLoopIterations = 1000;\n\n\t// Navigation settings.\n\tlet _navigationOverride;\n\n\t// Passages settings.\n\tlet _passagesDescriptions;\n\tlet _passagesDisplayTitles = false;\n\tlet _passagesNobr          = false;\n\tlet _passagesStart; // set by `Story.load()`\n\tlet _passagesOnProcess;\n\tlet _passagesTransitionOut;\n\n\t// Saves settings.\n\tlet _savesAutoload;\n\tlet _savesAutosave;\n\tlet _savesId        = 'untitled-story';\n\tlet _savesIsAllowed;\n\tlet _savesOnLoad;\n\tlet _savesOnSave;\n\tlet _savesSlots     = 8;\n\tlet _savesVersion;\n\n\t// UI settings.\n\tlet _uiStowBarInitially    = 800;\n\tlet _uiUpdateStoryElements = true;\n\n\n\t/*******************************************************************************\n\t\tError Constants.\n\t*******************************************************************************/\n\n\tconst _errHistoryModeDeprecated     = 'Config.history.mode has been deprecated and is no longer used by SugarCube, please remove it from your code';\n\tconst _errHistoryTrackingDeprecated = 'Config.history.tracking has been deprecated, use Config.history.maxStates instead';\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze({\n\t\t/*\n\t\t\tGeneral settings.\n\t\t*/\n\t\tget debug() { return _debug; },\n\t\tset debug(value) { _debug = Boolean(value); },\n\n\t\tget addVisitedLinkClass() { return _addVisitedLinkClass; },\n\t\tset addVisitedLinkClass(value) { _addVisitedLinkClass = Boolean(value); },\n\n\t\tget cleanupWikifierOutput() { return _cleanupWikifierOutput; },\n\t\tset cleanupWikifierOutput(value) { _cleanupWikifierOutput = Boolean(value); },\n\n\t\tget loadDelay() { return _loadDelay; },\n\t\tset loadDelay(value) {\n\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\tthrow new RangeError('Config.loadDelay must be a non-negative integer');\n\t\t\t}\n\n\t\t\t_loadDelay = value;\n\t\t},\n\n\t\t/*\n\t\t\tAudio settings.\n\t\t*/\n\t\taudio : Object.freeze({\n\t\t\tget pauseOnFadeToZero() { return _audioPauseOnFadeToZero; },\n\t\t\tset pauseOnFadeToZero(value) { _audioPauseOnFadeToZero = Boolean(value); },\n\n\t\t\tget preloadMetadata() { return _audioPreloadMetadata; },\n\t\t\tset preloadMetadata(value) { _audioPreloadMetadata = Boolean(value); }\n\t\t}),\n\n\t\t/*\n\t\t\tState history settings.\n\t\t*/\n\t\thistory : Object.freeze({\n\t\t\t// TODO: (v3) This should be under UI settings → `Config.ui.historyControls`.\n\t\t\tget controls() { return _historyControls; },\n\t\t\tset controls(value) {\n\t\t\t\tconst controls = Boolean(value);\n\n\t\t\t\tif (_historyMaxStates === 1 && controls) {\n\t\t\t\t\tthrow new Error('Config.history.controls must be false when Config.history.maxStates is 1');\n\t\t\t\t}\n\n\t\t\t\t_historyControls = controls;\n\t\t\t},\n\n\t\t\tget maxStates() { return _historyMaxStates; },\n\t\t\tset maxStates(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new RangeError('Config.history.maxStates must be a non-negative integer');\n\t\t\t\t}\n\n\t\t\t\t_historyMaxStates = value;\n\n\t\t\t\t// Force `Config.history.controls` to `false`, when limited to `1` moment.\n\t\t\t\tif (_historyControls && value === 1) {\n\t\t\t\t\t_historyControls = false;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// legacy\n\t\t\t// Die if deprecated state history settings are accessed.\n\t\t\tget mode()  { throw new Error(_errHistoryModeDeprecated); },\n\t\t\tset mode(_) { throw new Error(_errHistoryModeDeprecated); },\n\t\t\tget tracking()  { throw new Error(_errHistoryTrackingDeprecated); },\n\t\t\tset tracking(_) { throw new Error(_errHistoryTrackingDeprecated); }\n\t\t\t// /legacy\n\t\t}),\n\n\t\t/*\n\t\t\tMacros settings.\n\t\t*/\n\t\tmacros : Object.freeze({\n\t\t\tget ifAssignmentError() { return _macrosIfAssignmentError; },\n\t\t\tset ifAssignmentError(value) { _macrosIfAssignmentError = Boolean(value); },\n\n\t\t\tget maxLoopIterations() { return _macrosMaxLoopIterations; },\n\t\t\tset maxLoopIterations(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new RangeError('Config.macros.maxLoopIterations must be a non-negative integer');\n\t\t\t\t}\n\n\t\t\t\t_macrosMaxLoopIterations = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tNavigation settings.\n\t\t*/\n\t\tnavigation : Object.freeze({\n\t\t\tget override() { return _navigationOverride; },\n\t\t\tset override(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.navigation.override must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_navigationOverride = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tPassages settings.\n\t\t*/\n\t\tpassages : Object.freeze({\n\t\t\tget descriptions() { return _passagesDescriptions; },\n\t\t\tset descriptions(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'boolean' && valueType !== 'Object' && valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.descriptions must be a boolean, object, function, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesDescriptions = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.updateTitle`.\n\t\t\tget displayTitles() { return _passagesDisplayTitles; },\n\t\t\tset displayTitles(value) { _passagesDisplayTitles = Boolean(value); },\n\n\t\t\tget nobr() { return _passagesNobr; },\n\t\t\tset nobr(value) { _passagesNobr = Boolean(value); },\n\n\t\t\tget onProcess() { return _passagesOnProcess; },\n\t\t\tset onProcess(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.onProcess must be a function or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesOnProcess = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.(start|startingPassage)`.\n\t\t\tget start() { return _passagesStart; },\n\t\t\tset start(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'string') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.start must be a string or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesStart = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.transitionOut`.\n\t\t\tget transitionOut() { return _passagesTransitionOut; },\n\t\t\tset transitionOut(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t   valueType !== 'string'\n\t\t\t\t\t\t&& (valueType !== 'number' || !Number.isSafeInteger(value) || value < 0)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.transitionOut must be a string, non-negative integer, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesTransitionOut = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tSaves settings.\n\t\t*/\n\t\tsaves : Object.freeze({\n\t\t\tget autoload() { return _savesAutoload; },\n\t\t\tset autoload(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'boolean' && valueType !== 'string' && valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.saves.autoload must be a boolean, string, function, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_savesAutoload = value;\n\t\t\t},\n\n\t\t\tget autosave() { return _savesAutosave; },\n\t\t\tset autosave(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\t// legacy\n\t\t\t\t\t// Convert a string value to an Array of string.\n\t\t\t\t\tif (valueType === 'string') {\n\t\t\t\t\t\t_savesAutosave = [value];\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// /legacy\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t   valueType !== 'boolean'\n\t\t\t\t\t\t&& (valueType !== 'Array' || !value.every(item => typeof item === 'string'))\n\t\t\t\t\t\t&& valueType !== 'function'\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new TypeError(`Config.saves.autosave must be a boolean, Array of strings, function, or null/undefined (received: ${valueType}${valueType === 'Array' ? ' of mixed' : ''})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_savesAutosave = value;\n\t\t\t},\n\n\t\t\tget id() { return _savesId; },\n\t\t\tset id(value) {\n\t\t\t\tif (typeof value !== 'string' || value === '') {\n\t\t\t\t\tthrow new TypeError(`Config.saves.id must be a non-empty string (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesId = value;\n\t\t\t},\n\n\t\t\tget isAllowed() { return _savesIsAllowed; },\n\t\t\tset isAllowed(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.isAllowed must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesIsAllowed = value;\n\t\t\t},\n\n\t\t\tget onLoad() { return _savesOnLoad; },\n\t\t\tset onLoad(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.onLoad must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesOnLoad = value;\n\t\t\t},\n\n\t\t\tget onSave() { return _savesOnSave; },\n\t\t\tset onSave(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.onSave must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesOnSave = value;\n\t\t\t},\n\n\t\t\tget slots() { return _savesSlots; },\n\t\t\tset slots(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new TypeError(`Config.saves.slots must be a non-negative integer (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesSlots = value;\n\t\t\t},\n\n\t\t\tget version() { return _savesVersion; },\n\t\t\tset version(value) { _savesVersion = value; }\n\t\t}),\n\n\t\t/*\n\t\t\tUI settings.\n\t\t*/\n\t\tui : Object.freeze({\n\t\t\tget stowBarInitially() { return _uiStowBarInitially; },\n\t\t\tset stowBarInitially(value) {\n\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\tif (\n\t\t\t\t\t   valueType !== 'boolean'\n\t\t\t\t\t&& (valueType !== 'number' || !Number.isSafeInteger(value) || value < 0)\n\t\t\t\t) {\n\t\t\t\t\tthrow new TypeError(`Config.ui.stowBarInitially must be a boolean or non-negative integer (received: ${valueType})`);\n\t\t\t\t}\n\n\t\t\t\t_uiStowBarInitially = value;\n\t\t\t},\n\n\t\t\tget updateStoryElements() { return _uiUpdateStoryElements; },\n\t\t\tset updateStoryElements(value) { _uiUpdateStoryElements = Boolean(value); }\n\t\t})\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tsimpleaudio.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser, Config, Has, LoadScreen, Story, Util, Visibility, clone */\n\nvar SimpleAudio = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tEvents that count as user activation—i.e. \"user gestures\", \"activation behavior\".\n\n\t\tNOTE (ca. Dec, 2018): This not an exhaustive list and varies significantly by browser.\n\t\tProposals for a specification/standard are still very much in flux at this point.\n\n\t\tTODO (ca. Dec, 2018): Revisit this topic.\n\n\t\tSEE: (too many to list)\n\t\t\thttps://github.com/whatwg/html/issues/3849\n\t\t\thttps://github.com/whatwg/html/issues/1903\n\t\t\thttps://html.spec.whatwg.org/#activation\n\t\t\thttps://docs.google.com/spreadsheets/d/1DGXjhQ6D3yZXIePOMo0dsd2agz0t5W7rYH1NwJ-QGJo/edit#gid=0\n\t*/\n\tconst _gestureEventNames = Object.freeze(['click', 'contextmenu', 'dblclick', 'keyup', 'mouseup', 'pointerup', 'touchend']);\n\n\t// Special group IDs.\n\tconst _specialIds = Object.freeze([':not', ':all', ':looped', ':muted', ':paused', ':playing']);\n\n\t// Format specifier regular expression.\n\tconst _formatSpecRe = /^([\\w-]+)\\s*\\|\\s*(\\S.*)$/; // e.g. 'mp3|https://audiohost.tld/id'\n\n\t// ID verification regular expressions.\n\tconst _badIdRe = /[:\\s]/;\n\n\t// Tracks collection.\n\tconst _tracks = new Map();\n\n\t// Groups collection.\n\tconst _groups = new Map();\n\n\t// Playlists collection.\n\tconst _lists = new Map();\n\n\t// Subscriber collection.\n\tconst _subscribers = new Map();\n\n\t// Master playback rate.\n\tlet _masterRate = 1;\n\n\t// Master playback volume.\n\tlet _masterVolume = 1;\n\n\t// Master mute state.\n\tlet _masterMute = false;\n\n\t// Master mute on tab/window visibility state.\n\tlet _masterMuteOnHidden = false;\n\n\n\t/*******************************************************************************************************************\n\t\tFeature Detection Functions.\n\t*******************************************************************************************************************/\n\t// Return whether the `<HTMLAudioElement>.play()` method returns a `Promise`.\n\t//\n\t// NOTE: The initial result is cached for future calls.\n\tconst _playReturnsPromise = (function () {\n\t\t// Cache of whether `<HTMLAudioElement>.play()` returns a `Promise`.\n\t\tlet _hasPromise = null;\n\n\t\tfunction _playReturnsPromise() {\n\t\t\tif (_hasPromise !== null) {\n\t\t\t\treturn _hasPromise;\n\t\t\t}\n\n\t\t\t_hasPromise = false;\n\n\t\t\tif (Has.audio) {\n\t\t\t\ttry {\n\t\t\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t\t\t// NOTE (ca. Jan 01, 2020): Firefox will still log an \"Autoplay is only allowed\n\t\t\t\t\t// when […] media is muted.\" message to the console when attempting the test\n\t\t\t\t\t// below, even though the audio has been muted.  Stay classy, Firefox.\n\t\t\t\t\t//\n\t\t\t\t\t// QUESTION (ca. Jan 01, 2020): Keep this?  It's only here to appease Firefox,\n\t\t\t\t\t// but doesn't seem to work as Firefox seems to ignore mute in violation of the\n\t\t\t\t\t// `HTMLAudioElement` specification—willfully or simply a bug, I can't say.\n\t\t\t\t\taudio.muted = true;\n\n\t\t\t\t\tconst value = audio.play();\n\n\t\t\t\t\t// Silence \"Uncaught (in promise)\" console errors from Blink.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: Swallowing errors is generally bad, but in this case we know there's\n\t\t\t\t\t// going to be an error regardless, since there's no source, and we don't actually\n\t\t\t\t\t// care about the error, since we just want the return value, so we consign it\n\t\t\t\t\t// to the bit bucket.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: We don't ensure that the return value is not `undefined` here because\n\t\t\t\t\t// having the attempted call to `<Promise>.catch()` on an `undefined` value throw\n\t\t\t\t\t// is acceptable, since it will be caught and `false` eventually returned.\n\t\t\t\t\tvalue.catch(() => { /* no-op */ });\n\n\t\t\t\t\t_hasPromise = value instanceof Promise;\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t}\n\n\t\t\treturn _hasPromise;\n\t\t}\n\n\t\treturn _playReturnsPromise;\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tAudioTrack Class.\n\t*******************************************************************************************************************/\n\tclass AudioTrack {\n\t\tconstructor(obj) {\n\t\t\t// Process the given array of sources or AudioTrack object.\n\t\t\tif (obj instanceof Array) {\n\t\t\t\tthis._create(obj);\n\t\t\t}\n\t\t\telse if (obj instanceof AudioTrack) {\n\t\t\t\tthis._copy(obj);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('sources parameter must be either an array, of URIs or source objects, or an AudioTrack instance');\n\t\t\t}\n\t\t}\n\n\t\t_create(sourceList) {\n\t\t\tconst dataUriRe   = /^data:\\s*audio\\/([^;,]+)\\s*[;,]/i;\n\t\t\tconst extRe       = /\\.([^./\\\\]+)$/;\n\t\t\tconst getType     = AudioTrack.getType;\n\t\t\tconst usedSources = [];\n\t\t\t/*\n\t\t\t\tHTMLAudioElement: DOM factory method vs. constructor\n\n\t\t\t\tUse of the DOM factory method, `document.createElement('audio')`, should be\n\t\t\t\tpreferred over use of the constructor, `new Audio()`.  The reason being that\n\t\t\t\tobjects created by the latter are, erroneously, treated differently, often\n\t\t\t\tunfavorably, by certain browser engines—e.g. within some versions of the iOS\n\t\t\t\tbrowser core.\n\n\t\t\t\tNotably, the only difference between the two, per the specification, is that\n\t\t\t\tobjects created via the constructor should have their `preload` property\n\t\t\t\tautomatically set to 'auto'.  Thus, there's no technical reason to prefer\n\t\t\t\tusage of the constructor, even discounting buggy browser implementations.\n\t\t\t*/\n\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t// Initially set the `preload` attribute to `'none'`.\n\t\t\taudio.preload = 'none';\n\n\t\t\t// Process the array of sources, adding any valid sources to the `usedSources`\n\t\t\t// array and to the audio element as source elements.\n\t\t\tsourceList.forEach(src => {\n\t\t\t\tlet srcObj = null;\n\n\t\t\t\tswitch (typeof src) {\n\t\t\t\tcase 'string':\n\t\t\t\t\t{\n\t\t\t\t\t\tlet match;\n\n\t\t\t\t\t\tif (src.slice(0, 5) === 'data:') {\n\t\t\t\t\t\t\tmatch = dataUriRe.exec(src);\n\n\t\t\t\t\t\t\tif (match === null) {\n\t\t\t\t\t\t\t\tthrow new Error('source data URI missing media type');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tmatch = extRe.exec(Util.parseUrl(src).pathname);\n\n\t\t\t\t\t\t\tif (match === null) {\n\t\t\t\t\t\t\t\tthrow new Error('source URL missing file extension');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst type = getType(match[1]);\n\n\t\t\t\t\t\tif (type !== null) {\n\t\t\t\t\t\t\tsrcObj = { src, type };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\t{\n\t\t\t\t\t\tif (src === null) {\n\t\t\t\t\t\t\tthrow new Error('source object cannot be null');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (!src.hasOwnProperty('src')) {\n\t\t\t\t\t\t\tthrow new Error('source object missing required \"src\" property');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (!src.hasOwnProperty('format')) {\n\t\t\t\t\t\t\tthrow new Error('source object missing required \"format\" property');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst type = getType(src.format);\n\n\t\t\t\t\t\tif (type !== null) {\n\t\t\t\t\t\t\tsrcObj = { src : src.src, type };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`invalid source value (type: ${typeof src})`);\n\t\t\t\t}\n\n\t\t\t\tif (srcObj !== null) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tOpera (Blink; ca. Jul 2017) fails to play audio from some sources\n\t\t\t\t\t\twith MIME-types containing a `codecs` parameter, despite the fact\n\t\t\t\t\t\tthat `canPlayType()` blessed the full MIME-type including `codecs`.\n\n\t\t\t\t\t\tBizarrely, this only affects some MIME-types—e.g. MP3s are affected,\n\t\t\t\t\t\twhile WAVEs are not.\n\t\t\t\t\t\t\tFails: 'audio/mpeg; codecs=\"mp3\"'\n\t\t\t\t\t\t\tPlays: 'audio/mpeg'\n\t\t\t\t\t\t\tPlays: 'audio/wav; codecs=\"1\"'\n\n\t\t\t\t\t\tTo workaround this we remove all parameters from the MIME-type in\n\t\t\t\t\t\tOpera.\n\t\t\t\t\t*/\n\t\t\t\t\tif (Browser.isOpera) {\n\t\t\t\t\t\tsrcObj.type =  srcObj.type.replace(/;.*$/, '');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst source = document.createElement('source');\n\t\t\t\t\tsource.src  = srcObj.src;\n\t\t\t\t\tsource.type = srcObj.type;\n\t\t\t\t\taudio.appendChild(source);\n\t\t\t\t\tusedSources.push(srcObj);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (audio.hasChildNodes()) {\n\t\t\t\t// Set the `preload` attribute to `'metadata'`, unless preloading has been disabled.\n\t\t\t\tif (Config.audio.preloadMetadata) {\n\t\t\t\t\taudio.preload = 'metadata';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._finalize(audio, usedSources, clone(sourceList));\n\t\t}\n\n\t\t_copy(obj) {\n\t\t\tthis._finalize(\n\t\t\t\tobj.audio.cloneNode(true), // deep clone of the audio element & its children\n\t\t\t\tclone(obj.sources),\n\t\t\t\tclone(obj.originals)\n\t\t\t);\n\t\t}\n\n\t\t_finalize(audio, sources, originals) {\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\taudio : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : audio\n\t\t\t\t},\n\n\t\t\t\tsources : {\n\t\t\t\t\tvalue : Object.freeze(sources)\n\t\t\t\t},\n\n\t\t\t\toriginals : {\n\t\t\t\t\tvalue : Object.freeze(originals)\n\t\t\t\t},\n\n\t\t\t\t_error : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_faderId : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_mute : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_rate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_volume : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Set up event handlers on the audio and source elements.\n\t\t\tjQuery(this.audio)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving a `loadstart` event on the audio element, set `_error` to\n\t\t\t\t\t`false`.\n\t\t\t\t*/\n\t\t\t\t.on('loadstart.AudioTrack', () => this._error = false)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving an `error` event on the audio element, set `_error` to\n\t\t\t\t\t`true`.\n\n\t\t\t\t\tCaveats by browser:\n\t\t\t\t\t\tEdge violates the specification by triggering `error` events from source\n\t\t\t\t\t\telements on their parent media element, rather than the source element.\n\t\t\t\t\t\tTo enable error handling in all browsers, we set the error handler on the\n\t\t\t\t\t\taudio element and have the final source element forward its `error` event.\n\n\t\t\t\t\t\tIE does not trigger, at least some, `error` events from source elements at\n\t\t\t\t\t\tall, not on the source element or its parent media element.  AFAIK, nothing\n\t\t\t\t\t\tcan be done about this lossage.\n\t\t\t\t*/\n\t\t\t\t.on('error.AudioTrack', () => this._error = true)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving an `error` event on the final source element (if any), trigger\n\t\t\t\t\tan `error` event on the audio element—that being necessary because the source\n\t\t\t\t\t`error` event does not bubble.\n\t\t\t\t*/\n\t\t\t\t.find('source:last-of-type')\n\t\t\t\t.on('error.AudioTrack', () => this._trigger('error'));\n\n\t\t\t// Subscribe to command messages.\n\t\t\tsubscribe(this, mesg => {\n\t\t\t\tif (!this.audio) {\n\t\t\t\t\tunsubscribe(this);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch (mesg) {\n\t\t\t\tcase 'loadwithscreen':\n\t\t\t\t\tif (this.hasSource()) {\n\t\t\t\t\t\tconst lockId = LoadScreen.lock();\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t// NOTE: Do not use an arrow function here.\n\t\t\t\t\t\t\t.one(\n\t\t\t\t\t\t\t\t'canplaythrough.AudioTrack_loadwithscreen error.AudioTrack_loadwithscreen',\n\t\t\t\t\t\t\t\tfunction () {\n\t\t\t\t\t\t\t\t\tjQuery(this).off('.AudioTrack_loadwithscreen');\n\t\t\t\t\t\t\t\t\tLoadScreen.unlock(lockId);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.load();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'load':   this.load();               break;\n\t\t\t\tcase 'mute':   this._updateAudioMute();   break;\n\t\t\t\tcase 'rate':   this._updateAudioRate();   break;\n\t\t\t\tcase 'stop':   this.stop();               break;\n\t\t\t\tcase 'volume': this._updateAudioVolume(); break;\n\t\t\t\tcase 'unload': this.unload();             break;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Synchronize with the current master audio settings.\n\t\t\tthis._updateAudioMute();\n\t\t\tthis._updateAudioRate();\n\t\t\tthis._updateAudioVolume();\n\t\t}\n\n\t\t_trigger(eventName) {\n\t\t\t// Do not use `trigger()` here as we do not want these events to bubble.\n\t\t\tjQuery(this.audio).triggerHandler(eventName);\n\t\t}\n\n\t\t_destroy() {\n\t\t\t/*\n\t\t\t\tStrictly speaking, self-destruction is not necessary as this object will,\n\t\t\t\teventually, be garbage collected.  That said, since the audio element contains\n\t\t\t\tdata buffers for the selected audio source, which may be quite large, manually\n\t\t\t\tpurging them as soon as we know that they're no longer needed is not a bad idea.\n\t\t\t*/\n\t\t\tunsubscribe(this);\n\n\t\t\tif (!this.audio) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tjQuery(this.audio).off();\n\t\t\tthis.unload();\n\t\t\tthis._error = true;\n\n\t\t\t// Delete the audio element property.\n\t\t\tdelete this.audio;\n\t\t}\n\n\t\tclone() {\n\t\t\treturn new AudioTrack(this);\n\t\t}\n\n\t\tload() {\n\t\t\tthis.fadeStop();\n\t\t\tthis.audio.pause();\n\n\t\t\tif (!this.audio.hasChildNodes()) {\n\t\t\t\tif (this.sources.length === 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.sources.forEach(srcObj => {\n\t\t\t\t\tconst source = document.createElement('source');\n\t\t\t\t\tsource.src  = srcObj.src;\n\t\t\t\t\tsource.type = srcObj.type;\n\t\t\t\t\tthis.audio.appendChild(source);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (this.audio.preload !== 'auto') {\n\t\t\t\tthis.audio.preload = 'auto';\n\t\t\t}\n\n\t\t\tif (!this.isLoading()) {\n\t\t\t\tthis.audio.load();\n\t\t\t}\n\t\t}\n\n\t\tunload() {\n\t\t\tthis.fadeStop();\n\t\t\tthis.stop();\n\n\t\t\tconst audio = this.audio;\n\t\t\taudio.preload = 'none';\n\n\t\t\t// Remove all source elements.\n\t\t\twhile (audio.hasChildNodes()) {\n\t\t\t\taudio.removeChild(audio.firstChild);\n\t\t\t}\n\n\t\t\t// Force the audio element to drop any existing data buffers.\n\t\t\taudio.load();\n\t\t}\n\n\t\tplay() {\n\t\t\tif (!this.hasSource()) {\n\t\t\t\treturn Promise.reject(new Error('none of the candidate sources were acceptable'));\n\t\t\t}\n\n\t\t\tif (this.isUnloaded()) {\n\t\t\t\treturn Promise.reject(new Error('no sources are loaded'));\n\t\t\t}\n\n\t\t\tif (this.isFailed()) {\n\t\t\t\treturn Promise.reject(new Error('failed to load any of the sources'));\n\t\t\t}\n\n\t\t\tif (this.audio.preload !== 'auto') {\n\t\t\t\tthis.audio.preload = 'auto';\n\t\t\t}\n\n\t\t\tconst namespace = '.AudioTrack_play';\n\n\t\t\treturn _playReturnsPromise()\n\t\t\t\t? this.audio.play()\n\t\t\t\t: new Promise((resolve, reject) => {\n\t\t\t\t\tif (this.isPlaying()) {\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tjQuery(this.audio)\n\t\t\t\t\t\t\t.off(namespace)\n\t\t\t\t\t\t\t.one(`error${namespace} playing${namespace} timeupdate${namespace}`, ev => {\n\t\t\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\t\t\tif (ev.type === 'error') {\n\t\t\t\t\t\t\t\t\treject(new Error('unknown audio play error'));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.audio.play();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tthis.play().catch(() => {\n\t\t\t\tconst gestures = _gestureEventNames.map(name => `${name}.AudioTrack_playWhenAllowed`).join(' ');\n\t\t\t\tjQuery(document).one(gestures, () => {\n\t\t\t\t\tjQuery(document).off('.AudioTrack_playWhenAllowed');\n\t\t\t\t\tthis.audio.play();\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tpause() {\n\t\t\tthis.audio.pause();\n\t\t}\n\n\t\tstop() {\n\t\t\tthis.audio.pause();\n\t\t\tthis.time(0);\n\t\t\tthis._trigger(':stopped');\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (typeof duration !== 'number') {\n\t\t\t\tthrow new TypeError('duration parameter must be a number');\n\t\t\t}\n\t\t\tif (typeof toVol !== 'number') {\n\t\t\t\tthrow new TypeError('toVolume parameter must be a number');\n\t\t\t}\n\t\t\tif (fromVol != null && typeof fromVol !== 'number') { // lazy equality for null\n\t\t\t\tthrow new TypeError('fromVolume parameter must be a number');\n\t\t\t}\n\n\t\t\tif (!this.hasSource()) {\n\t\t\t\treturn Promise.reject(new Error('none of the candidate sources were acceptable'));\n\t\t\t}\n\n\t\t\tif (this.isUnloaded()) {\n\t\t\t\treturn Promise.reject(new Error('no sources are loaded'));\n\t\t\t}\n\n\t\t\tif (this.isFailed()) {\n\t\t\t\treturn Promise.reject(new Error('failed to load any of the sources'));\n\t\t\t}\n\n\t\t\tthis.fadeStop();\n\n\t\t\tconst from = Math.clamp(fromVol == null ? this.volume() : fromVol, 0, 1); // lazy equality for null\n\t\t\tconst to   = Math.clamp(toVol, 0, 1);\n\n\t\t\tif (from === to) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.volume(from);\n\n\t\t\t/*\n\t\t\t\tWe listen for the `timeupdate` event here, rather than `playing`, because\n\t\t\t\tvarious browsers (notably, mobile browsers) are poor at firing media events\n\t\t\t\tin a timely fashion, so we use `timeupdate` to ensure that we don't start\n\t\t\t\tthe fade until the track is actually progressing.\n\t\t\t*/\n\t\t\tjQuery(this.audio)\n\t\t\t\t.off('timeupdate.AudioTrack_fade')\n\t\t\t\t.one('timeupdate.AudioTrack_fade', () => {\n\t\t\t\t\tlet min;\n\t\t\t\t\tlet max;\n\n\t\t\t\t\t// Fade in.\n\t\t\t\t\tif (from < to) {\n\t\t\t\t\t\tmin = from;\n\t\t\t\t\t\tmax = to;\n\t\t\t\t\t}\n\t\t\t\t\t// Fade out.\n\t\t\t\t\telse {\n\t\t\t\t\t\tmin = to;\n\t\t\t\t\t\tmax = from;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst time     = Math.max(duration, 1);\n\t\t\t\t\tconst interval = 25; // in milliseconds\n\t\t\t\t\tconst delta    = (to - from) / (time / (interval / 1000));\n\n\t\t\t\t\tthis._trigger(':fading');\n\t\t\t\t\tthis._faderId = setInterval(() => {\n\t\t\t\t\t\tif (!this.isPlaying()) {\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tWhile it may seem like a good idea to also set the track volume\n\t\t\t\t\t\t\t\tto the `to` value here, we should not do so.  We cannot know why\n\t\t\t\t\t\t\t\tthe track is no longer playing, nor if the volume has been modified\n\t\t\t\t\t\t\t\tin the interim, so doing so now may clobber an end-user set volume.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tthis.fadeStop();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthis.volume(Math.clamp(this.volume() + delta, min, max));\n\n\t\t\t\t\t\tif (Config.audio.pauseOnFadeToZero && this.volume() === 0) {\n\t\t\t\t\t\t\tthis.pause();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.volume() === to) {\n\t\t\t\t\t\t\tthis.fadeStop();\n\t\t\t\t\t\t\tthis._trigger(':faded');\n\t\t\t\t\t\t}\n\t\t\t\t\t}, interval);\n\t\t\t\t});\n\n\t\t\treturn this.play();\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\treturn this.fade(duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\treturn this.fade(duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tif (this._faderId !== null) {\n\t\t\t\tclearInterval(this._faderId);\n\t\t\t\tthis._faderId = null;\n\t\t\t}\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\treturn this.audio.loop;\n\t\t\t}\n\n\t\t\tthis.audio.loop = !!loop;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\treturn this._mute;\n\t\t\t}\n\n\t\t\tthis._mute = !!mute;\n\t\t\tthis._updateAudioMute();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioMute() {\n\t\t\tthis.audio.muted = this._mute || _masterMute;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\treturn this._rate;\n\t\t\t}\n\n\t\t\tif (typeof rate !== 'number') {\n\t\t\t\tthrow new TypeError('rate parameter must be a number');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tClamp the playback rate to sane values—some browsers also do this to varying degrees.\n\n\t\t\t\tNOTE (ca. Aug 2016): The specification allows negative values for reverse playback,\n\t\t\t\thowever, most browsers either completely ignore negative values or clamp them to\n\t\t\t\tsome positive value.  In some (notably, IE & Edge), setting a negative playback\n\t\t\t\trate breaks the associated controls, if displayed.\n\t\t\t*/\n\t\t\t/*\n\t\t\tthis._rate = rate < 0\n\t\t\t\t? Math.clamp(rate, -0.2, -5) // clamp to 5× slower & faster, backward\n\t\t\t\t: Math.clamp(rate, 0.2, 5);  // clamp to 5× slower & faster, forward\n\t\t\t*/\n\t\t\tthis._rate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\t\t\tthis._updateAudioRate();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioRate() {\n\t\t\t/*\n\t\t\tconst rate = this._rate * _masterRate;\n\t\t\tthis.audio.playbackRate = rate < 0\n\t\t\t\t? Math.clamp(rate, -0.2, -5) // clamp to 5× slower & faster, backward\n\t\t\t\t: Math.clamp(rate, 0.2, 5);  // clamp to 5× slower & faster, forward\n\t\t\t*/\n\t\t\tthis.audio.playbackRate = Math.clamp(this._rate * _masterRate, 0.2, 5); // clamp to 5× slower & faster\n\t\t}\n\n\t\ttime(time) {\n\t\t\tif (time == null) { // lazy equality for null\n\t\t\t\treturn this.audio.currentTime;\n\t\t\t}\n\n\t\t\tif (typeof time !== 'number') {\n\t\t\t\tthrow new TypeError('time parameter must be a number');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tNOTE (historic): If we try to modify the audio clip's `.currentTime` property\n\t\t\t\tbefore its metadata has been loaded, it will throw an `InvalidStateError`\n\t\t\t\t(since it doesn't know its duration, allowing `.currentTime` to be set would\n\t\t\t\tbe undefined behavior), so in case an exception is thrown we provide a fallback\n\t\t\t\tusing the `loadedmetadata` event.\n\n\t\t\t\tNOTE (ca. 2016): This workaround should no longer be necessary in most browsers.\n\t\t\t\tThat said, it will still be required for some time to service legacy browsers.\n\n\t\t\t\tNOTE (ca. Dec 09, 2018): Firefox will still log an `InvalidStateError` to the\n\t\t\t\tconsole when attempting to modify the clip's `.currentTime` property before its\n\t\t\t\tmetadata has been loaded, even though it handles the situation properly—by waiting\n\t\t\t\tfor the metadata, as all browsers do now.  To prevent this spurious logging, we\n\t\t\t\tmust now manually check for the existence of the metadata and always failover to\n\t\t\t\tan event regardless of if the browser needs it or not—because I don't want to\n\t\t\t\tintroduce a browser check here.  Stay classy, Firefox.\n\t\t\t*/\n\t\t\tif (this.hasMetadata()) {\n\t\t\t\tthis.audio.currentTime = time;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery(this.audio)\n\t\t\t\t\t.off('loadedmetadata.AudioTrack_time')\n\t\t\t\t\t.one('loadedmetadata.AudioTrack_time', () => this.audio.currentTime = time);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\treturn this._volume;\n\t\t\t}\n\n\t\t\tif (typeof volume !== 'number') {\n\t\t\t\tthrow new TypeError('volume parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._volume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\t\t\tthis._updateAudioVolume();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioVolume() {\n\t\t\tthis.audio.volume = Math.clamp(this._volume * _masterVolume, 0, 1);\n\t\t}\n\n\t\tduration() {\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.audio.duration;\n\t\t}\n\n\t\tremaining() {\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.audio.duration - this.audio.currentTime;\n\t\t}\n\n\t\tisFailed() {\n\t\t\treturn this._error;\n\t\t}\n\n\t\tisLoading() {\n\t\t\treturn this.audio.networkState === HTMLMediaElement.NETWORK_LOADING;\n\t\t}\n\n\t\tisUnloaded() {\n\t\t\treturn !this.audio.hasChildNodes();\n\t\t}\n\n\t\tisUnavailable() {\n\t\t\treturn !this.hasSource() || this.isUnloaded() || this.isFailed();\n\t\t}\n\n\t\tisPlaying() {\n\t\t\t// NOTE: The `this.hasSomeData()` check is probably no longer necessary.\n\t\t\treturn !this.audio.paused && this.hasSomeData();\n\t\t}\n\n\t\tisPaused() {\n\t\t\t/*\n\t\t\t\tIf the selected audio resource is a stream, `currentTime` may return a non-zero\n\t\t\t\tvalue even at the earliest available position within the stream as the browser\n\t\t\t\tmay have dropped the earliest chunks of buffered data or the stream may have a\n\t\t\t\ttimeline which does not start at zero.\n\n\t\t\t\tIn an attempt to guard against these possiblities, as best as we can, we test\n\t\t\t\t`duration` against `Infinity` first, which should yield true for actual streams.\n\t\t\t*/\n\t\t\treturn this.audio.paused\n\t\t\t\t&& (this.audio.duration === Infinity || this.audio.currentTime > 0)\n\t\t\t\t&& !this.audio.ended;\n\t\t}\n\n\t\tisStopped() {\n\t\t\treturn this.audio.paused && this.audio.currentTime === 0;\n\t\t}\n\n\t\tisEnded() {\n\t\t\treturn this.audio.ended;\n\t\t}\n\n\t\tisFading() {\n\t\t\treturn this._faderId !== null;\n\t\t}\n\n\t\tisSeeking() {\n\t\t\treturn this.audio.seeking;\n\t\t}\n\n\t\thasSource() {\n\t\t\treturn this.sources.length > 0;\n\t\t}\n\n\t\thasNoData() {\n\t\t\treturn this.audio.readyState === HTMLMediaElement.HAVE_NOTHING;\n\t\t}\n\n\t\thasMetadata() {\n\t\t\treturn this.audio.readyState >= HTMLMediaElement.HAVE_METADATA;\n\t\t}\n\n\t\thasSomeData() {\n\t\t\treturn this.audio.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA;\n\t\t}\n\n\t\thasData() {\n\t\t\treturn this.audio.readyState === HTMLMediaElement.HAVE_ENOUGH_DATA;\n\t\t}\n\n\t\ton(...args) {\n\t\t\tjQuery.fn.on.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\tone(...args) {\n\t\t\tjQuery.fn.one.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\toff(...args) {\n\t\t\tjQuery.fn.off.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\t/*\n\t\t\tVerifies that the browser supports the given MIME-type and then retuns either\n\t\t\tthe MIME-type, if it is supported, or `null`, if it is not.\n\t\t*/\n\t\tstatic _verifyType(type) {\n\t\t\tif (!type || !Has.audio) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst cache = AudioTrack._types;\n\n\t\t\tif (!cache.hasOwnProperty(type)) {\n\t\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t\t// Some early implementations return 'no' instead of the empty string.\n\t\t\t\tcache[type] = audio.canPlayType(type).replace(/^no$/i, '') !== '';\n\t\t\t}\n\n\t\t\treturn cache[type] ? type : null;\n\t\t}\n\n\t\t/*\n\t\t\tRetuns the MIME-type associated with the given format-ID, if it is supported,\n\t\t\telsewise `null`.\n\t\t*/\n\t\tstatic getType(format) {\n\t\t\tif (!format || !Has.audio) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst known = AudioTrack.formats;\n\t\t\tconst id    = format.toLowerCase();\n\t\t\tconst type  = known.hasOwnProperty(id) ? known[id] : `audio/${id}`;\n\n\t\t\treturn AudioTrack._verifyType(type);\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the browser potentially supports a format.\n\t\t*/\n\t\tstatic canPlayFormat(format) {\n\t\t\treturn AudioTrack.getType(format) !== null;\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the browser potentially supports a MIME-type.\n\t\t*/\n\t\tstatic canPlayType(type) {\n\t\t\treturn AudioTrack._verifyType(type) !== null;\n\t\t}\n\t}\n\n\t// Attach the static data members.\n\tObject.defineProperties(AudioTrack, {\n\t\t/*\n\t\t\tFormat-ID to MIME-type mappings for common audio types.\n\n\t\t\tIn most cases, the codecs property should not be included with the MIME-type,\n\t\t\tas we have no way of knowing which codec was used—and the browser will figure\n\t\t\tit out.  Conversely, in cases where the relationship relationship between a\n\t\t\tformat-ID and a specific codec is strong, we should include the codecs property.\n\n\t\t\tNOTE: Caveats by browser/engine:\n\t\t\t\tOpera ≤12 (Presto) will return a false-negative if the codecs value is quoted\n\t\t\t\twith single quotes, requiring the use of either double quotes or no quotes.\n\n\t\t\t\tBlink-based browsers (e.g. Chrome, Opera ≥15) will return a false-negative\n\t\t\t\tfor WAVE audio if the preferred MIME-type of 'audio/wave' is specified,\n\t\t\t\trequiring the use of 'audio/wav' instead.\n\t\t*/\n\t\tformats : {\n\t\t\tvalue : { // Leave this object extensible for users.\n\t\t\t\t// AAC — MPEG-2 AAC audio; specific profiles vary, but commonly \"AAC-LC\".\n\t\t\t\taac : 'audio/aac',\n\n\t\t\t\t// CAF — Codecs vary.\n\t\t\t\tcaf     : 'audio/x-caf',\n\t\t\t\t'x-caf' : 'audio/x-caf',\n\n\t\t\t\t// MP3 — MPEG-1/-2 Layer-III audio.\n\t\t\t\tmp3  : 'audio/mpeg; codecs=\"mp3\"',\n\t\t\t\tmpeg : 'audio/mpeg; codecs=\"mp3\"',\n\n\t\t\t\t// MP4 — Codecs vary, but commonly \"mp4a.40.2\" (a.k.a. \"AAC-LC\").\n\t\t\t\tm4a     : 'audio/mp4',\n\t\t\t\tmp4     : 'audio/mp4',\n\t\t\t\t'x-m4a' : 'audio/mp4',\n\t\t\t\t'x-mp4' : 'audio/mp4',\n\n\t\t\t\t// OGG — Codecs vary, but commonly \"vorbis\" and, recently, \"opus\".\n\t\t\t\toga : 'audio/ogg',\n\t\t\t\togg : 'audio/ogg',\n\n\t\t\t\t// OPUS — Opus audio in an Ogg container.\n\t\t\t\topus : 'audio/ogg; codecs=\"opus\"',\n\n\t\t\t\t// WAVE — Codecs vary, but commonly \"1\" (1 is the FourCC for PCM/LPCM).\n\t\t\t\twav  : 'audio/wav',\n\t\t\t\twave : 'audio/wav',\n\n\t\t\t\t// WEBM — Codecs vary, but commonly \"vorbis\" and, recently, \"opus\".\n\t\t\t\tweba : 'audio/webm',\n\t\t\t\twebm : 'audio/webm'\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t\tCache of supported MIME-types.\n\t\t*/\n\t\t_types : {\n\t\t\tvalue : {}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAudioList Class.\n\t*******************************************************************************************************************/\n\tclass AudioList {\n\t\tconstructor(obj) {\n\t\t\t// Process the given array of track objects or AudioList object.\n\t\t\tif (obj instanceof Array) {\n\t\t\t\tthis._create(obj);\n\t\t\t}\n\t\t\telse if (obj instanceof AudioList) {\n\t\t\t\tthis._copy(obj);\n\t\t\t\t// this._create(obj.tracks);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('tracks parameter must be either an array, of track objects, or an AudioTrack instance');\n\t\t\t}\n\t\t}\n\n\t\t_create(trackList) {\n\t\t\t// Map the array of tracks to playlist track objects.\n\t\t\tthis._finalize(trackList.map(trackObj => {\n\t\t\t\tif (typeof trackObj !== 'object') { // lazy equality for null\n\t\t\t\t\tthrow new Error('tracks parameter array members must be objects');\n\t\t\t\t}\n\n\t\t\t\tlet own;\n\t\t\t\tlet rate;\n\t\t\t\tlet track;\n\t\t\t\tlet volume;\n\n\t\t\t\tif (trackObj instanceof AudioTrack) {\n\t\t\t\t\town    = true;\n\t\t\t\t\trate   = trackObj.rate();\n\t\t\t\t\ttrack  = trackObj.clone();\n\t\t\t\t\tvolume = trackObj.volume();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (!trackObj.hasOwnProperty('track')) {\n\t\t\t\t\t\tthrow new Error('track object missing required \"track\" property');\n\t\t\t\t\t}\n\t\t\t\t\telse if (!(trackObj.track instanceof AudioTrack)) {\n\t\t\t\t\t\tthrow new Error('track object\\'s \"track\" property must be an AudioTrack object');\n\t\t\t\t\t}\n\t\t\t\t\t// else if (!trackObj.hasOwnProperty('volume')) {\n\t\t\t\t\t// \tthrow new Error('track object missing required \"volume\" property');\n\t\t\t\t\t// }\n\n\t\t\t\t\town    = trackObj.hasOwnProperty('own') && trackObj.own;\n\t\t\t\t\trate   = trackObj.hasOwnProperty('rate') ? trackObj.rate : trackObj.track.rate();\n\t\t\t\t\ttrack  = trackObj.track;\n\t\t\t\t\tvolume = trackObj.hasOwnProperty('volume') ? trackObj.volume : trackObj.track.volume();\n\t\t\t\t}\n\n\t\t\t\ttrack.stop();\n\t\t\t\ttrack.loop(false);\n\t\t\t\ttrack.mute(false);\n\t\t\t\ttrack.rate(rate);\n\t\t\t\ttrack.volume(volume);\n\t\t\t\ttrack.on('ended.AudioList', () => this._onEnd());\n\n\t\t\t\treturn { own, track, volume, rate };\n\t\t\t}));\n\t\t}\n\n\t\t_copy(obj) {\n\t\t\tthis._finalize(clone(obj.tracks));\n\t\t}\n\n\t\t_finalize(tracks) {\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\ttracks : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : Object.freeze(tracks)\n\t\t\t\t},\n\n\t\t\t\tqueue : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : []\n\t\t\t\t},\n\n\t\t\t\tcurrent : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_rate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_volume : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_mute : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_loop : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_shuffle : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t_destroy() {\n\t\t\t/*\n\t\t\t\tStrictly speaking, self-destruction is not necessary as this object will,\n\t\t\t\teventually, be garbage collected.\n\t\t\t*/\n\t\t\t// Stop playback.\n\t\t\tthis.stop();\n\n\t\t\t// Destroy all owned tracks.\n\t\t\tthis.tracks\n\t\t\t\t.filter(trackObj => trackObj.own)\n\t\t\t\t.forEach(trackObj => trackObj.track._destroy());\n\n\t\t\t// Delete the reference-type properties.\n\t\t\tdelete this.tracks;\n\t\t\tdelete this.queue;\n\t\t}\n\n\t\tload() {\n\t\t\tthis.tracks.forEach(trackObj => trackObj.track.load());\n\t\t}\n\n\t\tunload() {\n\t\t\tthis.stop();\n\t\t\tthis.tracks.forEach(trackObj => trackObj.track.unload());\n\t\t}\n\n\t\tplay() {\n\t\t\tif (this.current === null || this.current.track.isUnavailable() || this.current.track.isEnded()) {\n\t\t\t\tif (this.queue.length === 0) {\n\t\t\t\t\tthis._fillQueue();\n\t\t\t\t}\n\n\t\t\t\tif (!this._next()) {\n\t\t\t\t\treturn Promise.reject(new Error('no tracks were available'));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.current.track.play();\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tthis.play().catch(() => {\n\t\t\t\tconst gestures = _gestureEventNames.map(name => `${name}.AudioList_playWhenAllowed`).join(' ');\n\t\t\t\tjQuery(document).one(gestures, () => {\n\t\t\t\t\tjQuery(document).off('.AudioList_playWhenAllowed');\n\t\t\t\t\tthis.play();\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tpause() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.pause();\n\t\t\t}\n\t\t}\n\n\t\tstop() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.stop();\n\t\t\t\tthis.current = null;\n\t\t\t}\n\n\t\t\tthis._drainQueue();\n\t\t}\n\n\t\tskip() {\n\t\t\tif (this._next()) {\n\t\t\t\tthis.current.track.play();\n\t\t\t}\n\t\t\telse if (this._loop) {\n\t\t\t\tthis.play();\n\t\t\t}\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (typeof duration !== 'number') {\n\t\t\t\tthrow new TypeError('duration parameter must be a number');\n\t\t\t}\n\t\t\tif (typeof toVol !== 'number') {\n\t\t\t\tthrow new TypeError('toVolume parameter must be a number');\n\t\t\t}\n\t\t\tif (fromVol != null && typeof fromVol !== 'number') { // lazy equality for null\n\t\t\t\tthrow new TypeError('fromVolume parameter must be a number');\n\t\t\t}\n\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\tthis._fillQueue();\n\t\t\t}\n\n\t\t\tif (this.current === null || this.current.track.isUnavailable() || this.current.track.isEnded()) {\n\t\t\t\tif (!this._next()) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst adjToVol = Math.clamp(toVol, 0, 1) * this.current.volume;\n\t\t\tlet adjFromVol;\n\n\t\t\tif (fromVol != null) { // lazy equality for null\n\t\t\t\tadjFromVol = Math.clamp(fromVol, 0, 1) * this.current.volume;\n\t\t\t}\n\n\t\t\tthis._volume = toVol; // NOTE: Kludgey, but necessary.\n\n\t\t\treturn this.current.track.fade(duration, adjToVol, adjFromVol);\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\treturn this.fade(duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\treturn this.fade(duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.fadeStop();\n\t\t\t}\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\treturn this._loop;\n\t\t\t}\n\n\t\t\tthis._loop = !!loop;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\treturn this._mute;\n\t\t\t}\n\n\t\t\tthis._mute = !!mute;\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.mute(this._mute);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\treturn this._rate;\n\t\t\t}\n\n\t\t\tif (typeof rate !== 'number') {\n\t\t\t\tthrow new TypeError('rate parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._rate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.rate(this._rate * this.current.rate);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tshuffle(shuffle) {\n\t\t\tif (shuffle == null) { // lazy equality for null\n\t\t\t\treturn this._shuffle;\n\t\t\t}\n\n\t\t\tthis._shuffle = !!shuffle;\n\n\t\t\tif (this.queue.length > 0) {\n\t\t\t\tthis._fillQueue();\n\n\t\t\t\t// Try not to immediately replay the last track when not shuffling.\n\t\t\t\tif (!this._shuffle && this.current !== null && this.queue.length > 1) {\n\t\t\t\t\tconst firstIdx = this.queue.findIndex(trackObj => trackObj === this.current);\n\n\t\t\t\t\tif (firstIdx !== -1) {\n\t\t\t\t\t\tthis.queue.push(...this.queue.splice(0, firstIdx + 1));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\treturn this._volume;\n\t\t\t}\n\n\t\t\tif (typeof volume !== 'number') {\n\t\t\t\tthrow new TypeError('volume parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._volume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.volume(this._volume * this.current.volume);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tduration() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('duration takes no parameters');\n\t\t\t}\n\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.tracks\n\t\t\t\t.map(trackObj => trackObj.track.duration())\n\t\t\t\t.reduce((prev, cur) => prev + cur, 0);\n\t\t}\n\n\t\tremaining() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('remaining takes no parameters');\n\t\t\t}\n\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\tlet remainingTime = this.queue\n\t\t\t\t.map(trackObj => trackObj.track.duration())\n\t\t\t\t.reduce((prev, cur) => prev + cur, 0);\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tremainingTime += this.current.track.remaining();\n\t\t\t}\n\n\t\t\treturn remainingTime;\n\t\t}\n\n\t\ttime() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('time takes no parameters');\n\t\t\t}\n\n\t\t\treturn this.duration() - this.remaining();\n\t\t}\n\n\t\tisPlaying() {\n\t\t\treturn this.current !== null && this.current.track.isPlaying();\n\t\t}\n\n\t\tisPaused() {\n\t\t\treturn this.current === null || this.current.track.isPaused();\n\t\t}\n\n\t\tisStopped() {\n\t\t\treturn this.queue.length === 0 && this.current === null;\n\t\t}\n\n\t\tisEnded() {\n\t\t\treturn this.queue.length === 0 && (this.current === null || this.current.track.isEnded());\n\t\t}\n\n\t\tisFading() {\n\t\t\treturn this.current !== null && this.current.track.isFading();\n\t\t}\n\n\t\t_next() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.stop();\n\t\t\t\tthis.current = null;\n\t\t\t}\n\n\t\t\tlet nextTrack;\n\n\t\t\twhile ((nextTrack = this.queue.shift())) {\n\t\t\t\tif (!nextTrack.track.isUnavailable()) {\n\t\t\t\t\tthis.current = nextTrack;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.current === null) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis.current.track.mute(this._mute);\n\t\t\tthis.current.track.rate(this._rate * this.current.rate);\n\t\t\tthis.current.track.volume(this._volume * this.current.volume);\n\n\t\t\t// Attempt to protect against the `loop` state being reenabled\n\t\t\t// outside of the playlist.  Mostly for unowned tracks.\n\t\t\t//\n\t\t\t// TODO: Should we reapply the `ended` event handler too?\n\t\t\tthis.current.track.loop(false);\n\n\t\t\treturn true;\n\t\t}\n\n\t\t_onEnd() {\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\tif (!this._loop) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._fillQueue();\n\t\t\t}\n\n\t\t\tif (!this._next()) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.current.track.play();\n\t\t}\n\n\t\t_drainQueue() {\n\t\t\tthis.queue.splice(0);\n\t\t}\n\n\t\t_fillQueue() {\n\t\t\tthis._drainQueue();\n\t\t\tthis.queue.push(...this.tracks.filter(trackObj => !trackObj.track.isUnavailable()));\n\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (this._shuffle) {\n\t\t\t\tthis.queue.shuffle();\n\n\t\t\t\t// Try not to immediately replay the last track when shuffling.\n\t\t\t\tif (this.queue.length > 1 && this.queue[0] === this.current) {\n\t\t\t\t\tthis.queue.push(this.queue.shift());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAudioRunner Class.\n\t*******************************************************************************************************************/\n\tclass AudioRunner {\n\t\tconstructor(list) {\n\t\t\tif (!(list instanceof Set || list instanceof AudioRunner)) {\n\t\t\t\tthrow new TypeError('list parameter must be a Set or a AudioRunner instance');\n\t\t\t}\n\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\ttrackIds : {\n\t\t\t\t\tvalue : new Set(list instanceof AudioRunner ? list.trackIds : list)\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tload() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.load);\n\t\t}\n\n\t\tunload() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.unload);\n\t\t}\n\n\t\tplay() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.play);\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.playWhenAllowed);\n\t\t}\n\n\t\tpause() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.pause);\n\t\t}\n\n\t\tstop() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.stop);\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (duration == null || toVol == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fade requires parameters');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fade, duration, toVol, fromVol);\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\tif (duration == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fadeIn requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeIn, duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\tif (duration == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fadeOut requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeOut, duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeStop);\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\tthrow new Error('loop requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.loop, loop);\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\tthrow new Error('mute requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.mute, mute);\n\t\t\treturn this;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\tthrow new Error('rate requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.rate, rate);\n\t\t\treturn this;\n\t\t}\n\n\t\ttime(time) {\n\t\t\tif (time == null) { // lazy equality for null\n\t\t\t\tthrow new Error('time requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.time, time);\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\tthrow new Error('volume requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.volume, volume);\n\t\t\treturn this;\n\t\t}\n\n\t\ton(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.on, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\tone(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.one, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\toff(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.off, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\tstatic _run(ids, fn, ...args) {\n\t\t\tids.forEach(id => {\n\t\t\t\tconst track = _tracks.get(id);\n\n\t\t\t\tif (track) {\n\t\t\t\t\tfn.apply(track, args);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTrack Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.tracks.add(trackId, sources…);\n\n\t\tE.g.\n\t\t\tSimpleAudio.tracks.add(\n\t\t\t\t'over_the_top',\n\t\t\t\t'https://audiohost.tld/id/over_the_top.mp3',\n\t\t\t\t'https://audiohost.tld/id/over_the_top.ogg'\n\t\t\t);\n\t*/\n\tfunction trackAdd(/* trackId , sources… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('track ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('sources'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `track ID \"${id}\"`;\n\n\t\tif (_badIdRe.test(id)) {\n\t\t\tthrow new Error(`invalid ${what}: track IDs must not contain colons or whitespace`);\n\t\t}\n\n\t\tconst sources = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet track;\n\n\t\ttry {\n\t\t\ttrack = _newTrack(sources);\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during track initialization: ${ex.message}`);\n\t\t}\n\n\t\t// If in Test Mode and no supported sources were specified, throw an error.\n\t\tif (Config.debug && !track.hasSource()) {\n\t\t\tthrow new Error(`${what}: no supported audio sources found`);\n\t\t}\n\n\t\t// If a track by the given ID already exists, destroy it.\n\t\tif (_tracks.has(id)) {\n\t\t\t_tracks.get(id)._destroy();\n\t\t}\n\n\t\t// Add the track to the cache.\n\t\t_tracks.set(id, track);\n\t}\n\n\tfunction trackDelete(id) {\n\t\tif (_tracks.has(id)) {\n\t\t\t_tracks.get(id)._destroy();\n\t\t}\n\n\t\t// TODO: Should this also remove references to the track from groups and playlists?\n\n\t\treturn _tracks.delete(id);\n\t}\n\n\tfunction trackClear() {\n\t\t_tracks.forEach(track => track._destroy());\n\t\t_tracks.clear();\n\t}\n\n\tfunction trackHas(id) {\n\t\treturn _tracks.has(id);\n\t}\n\n\tfunction trackGet(id) {\n\t\treturn _tracks.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tGroup Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.groups.add(groupId, trackIds…);\n\n\t\tE.g.\n\t\t\tSimpleAudio.groups.add(':ui', 'beep', 'boop', 'boing');\n\t*/\n\tfunction groupAdd(/* groupId , trackIds… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('group ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('track IDs'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `group ID \"${id}\"`;\n\n\t\tif (id[0] !== ':' || _badIdRe.test(id.slice(1))) {\n\t\t\tthrow new Error(`invalid ${what}: group IDs must start with a colon and must not contain colons or whitespace`);\n\t\t}\n\n\t\tif (_specialIds.includes(id)) {\n\t\t\tthrow new Error(`cannot clobber special ${what}`);\n\t\t}\n\n\t\tconst trackIds = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet group;\n\n\t\ttry {\n\t\t\tgroup = new Set(trackIds.map(trackId => {\n\t\t\t\tif (!_tracks.has(trackId)) {\n\t\t\t\t\tthrow new Error(`track \"${trackId}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\treturn trackId;\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during group initialization: ${ex.message}`);\n\t\t}\n\n\t\t// Add the group to the cache.\n\t\t_groups.set(id, Object.freeze(Array.from(group)));\n\t}\n\n\tfunction groupDelete(id) {\n\t\treturn _groups.delete(id);\n\t}\n\n\tfunction groupClear() {\n\t\t_groups.clear();\n\t}\n\n\tfunction groupHas(id) {\n\t\treturn _groups.has(id);\n\t}\n\n\tfunction groupGet(id) {\n\t\treturn _groups.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPlaylist Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.lists.add(listId, sources…);\n\t\t\tWhere `sources` may be either a track ID or descriptor (object).\n\t\t\tTrack descriptors are either { id, [own], [rate], [volume] } or { sources, [rate], [volume] }.\n\n\t\tNOTE: Rate properties are currently unsupported due to poor browser support.\n\n\t\tE.g.\n\t\t\tSimpleAudio.lists.add(\n\t\t\t\t'bgm',\n\t\t\t\t'over_the_top',\n\t\t\t\t{\n\t\t\t\t\tid     : 'heavens_a_lie',\n\t\t\t\t\tvolume : 0.5,\n\t\t\t\t\town    : true\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tsources : [\n\t\t\t\t\t\t'https://audiohost.tld/id/swamped.mp3',\n\t\t\t\t\t\t'https://audiohost.tld/id/swamped.ogg'\n\t\t\t\t\t],\n\t\t\t\t\tvolume  : 0.75\n\t\t\t\t}\n\t\t\t);\n\t*/\n\tfunction listAdd(/* listId , sources… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('list ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('track IDs'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `list ID \"${id}\"`;\n\n\t\tif (_badIdRe.test(id)) {\n\t\t\treturn this.error(`invalid ${what}: list IDs must not contain colons or whitespace`);\n\t\t}\n\n\t\tconst descriptors = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet list;\n\n\t\ttry {\n\t\t\tlist = new AudioList(descriptors.map(desc => {\n\t\t\t\tif (desc === null) {\n\t\t\t\t\tthrow new Error('track descriptor must be a string or object (type: null)');\n\t\t\t\t}\n\n\t\t\t\tswitch (typeof desc) {\n\t\t\t\tcase 'string':\n\t\t\t\t\t// Simply a track ID, so convert it into an object.\n\t\t\t\t\tdesc = { id : desc }; // eslint-disable-line no-param-reassign\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\tif (!desc.hasOwnProperty('id') && !desc.hasOwnProperty('sources')) {\n\t\t\t\t\t\tthrow new Error('track descriptor must contain one of either an \"id\" or a \"sources\" property');\n\t\t\t\t\t}\n\t\t\t\t\telse if (desc.hasOwnProperty('id') && desc.hasOwnProperty('sources')) {\n\t\t\t\t\t\tthrow new Error('track descriptor must contain either an \"id\" or a \"sources\" property, not both');\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`track descriptor must be a string or object (type: ${typeof desc})`);\n\t\t\t\t}\n\n\t\t\t\tlet own;\n\t\t\t\t// let rate;\n\t\t\t\tlet track;\n\t\t\t\tlet volume;\n\n\t\t\t\tif (desc.hasOwnProperty('id')) {\n\t\t\t\t\tif (typeof desc.id !== 'string') {\n\t\t\t\t\t\tthrow new Error('\"id\" property must be a string');\n\t\t\t\t\t}\n\t\t\t\t\tif (!_tracks.has(desc.id)) {\n\t\t\t\t\t\tthrow new Error(`track \"${desc.id}\" does not exist`);\n\t\t\t\t\t}\n\n\t\t\t\t\ttrack = _tracks.get(desc.id);\n\t\t\t\t}\n\t\t\t\telse if (desc.hasOwnProperty('sources')) {\n\t\t\t\t\tif (!Array.isArray(desc.sources) || desc.sources.length === 0) {\n\t\t\t\t\t\tthrow new Error('\"sources\" property must be a non-empty array');\n\t\t\t\t\t}\n\t\t\t\t\tif (desc.hasOwnProperty('own')) {\n\t\t\t\t\t\tthrow new Error('\"own\" property is not allowed with the \"sources\" property');\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\ttrack = _newTrack(desc.sources);\n\t\t\t\t\t\town = true;\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`error during track initialization: ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// If in Test Mode and no supported sources were specified, return an error.\n\t\t\t\t\tif (Config.debug && !track.hasSource()) {\n\t\t\t\t\t\tthrow new Error('no supported audio sources found');\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (desc.hasOwnProperty('own')) {\n\t\t\t\t\tif (typeof desc.own !== 'boolean') {\n\t\t\t\t\t\tthrow new Error('\"own\" property must be a boolean');\n\t\t\t\t\t}\n\n\t\t\t\t\town = desc.own;\n\n\t\t\t\t\tif (own) {\n\t\t\t\t\t\ttrack = track.clone();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if (desc.hasOwnProperty('rate')) {\n\t\t\t\t// \tif (\n\t\t\t\t// \t\t   typeof desc.rate !== 'number'\n\t\t\t\t// \t\t|| Number.isNaN(desc.rate)\n\t\t\t\t// \t\t|| !Number.isFinite(desc.rate)\n\t\t\t\t// \t) {\n\t\t\t\t// \t\tthrow new Error('\"rate\" property must be a finite number');\n\t\t\t\t// \t}\n\t\t\t\t//\n\t\t\t\t// \trate = desc.rate;\n\t\t\t\t// }\n\n\t\t\t\tif (desc.hasOwnProperty('volume')) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t   typeof desc.volume !== 'number'\n\t\t\t\t\t\t|| Number.isNaN(desc.volume)\n\t\t\t\t\t\t|| !Number.isFinite(desc.volume)\n\t\t\t\t\t\t|| desc.volume < 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new Error('\"volume\" property must be a non-negative finite number');\n\t\t\t\t\t}\n\n\t\t\t\t\tvolume = desc.volume;\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\town    : own != null ? own : false, // lazy equality for null,\n\t\t\t\t\t// rate   : rate != null ? rate : track.rate(), // lazy equality for null,\n\t\t\t\t\ttrack,\n\t\t\t\t\tvolume : volume != null ? volume : track.volume() // lazy equality for null\n\t\t\t\t};\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during playlist initialization: ${ex.message}`);\n\t\t}\n\n\t\t// If a playlist by the given ID already exists, destroy it.\n\t\tif (_lists.has(id)) {\n\t\t\t_lists.get(id)._destroy();\n\t\t}\n\n\t\t// Add the playlist to the cache.\n\t\t_lists.set(id, list);\n\t}\n\n\tfunction listDelete(id) {\n\t\tif (_lists.has(id)) {\n\t\t\t_lists.get(id)._destroy();\n\t\t}\n\n\t\treturn _lists.delete(id);\n\t}\n\n\tfunction listClear() {\n\t\t_lists.forEach(list => list._destroy());\n\t\t_lists.clear();\n\t}\n\n\tfunction listHas(id) {\n\t\treturn _lists.has(id);\n\t}\n\n\tfunction listGet(id) {\n\t\treturn _lists.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tRunner Functions.\n\t*******************************************************************************************************************/\n\tconst _runnerParseSelector = (() => {\n\t\tconst notWsRe = /\\S/g;\n\t\tconst parenRe = /[()]/g;\n\n\t\tfunction processNegation(str, startPos) {\n\t\t\tlet match;\n\n\t\t\tnotWsRe.lastIndex = startPos;\n\t\t\tmatch = notWsRe.exec(str);\n\n\t\t\tif (match === null || match[0] !== '(') {\n\t\t\t\tthrow new Error('invalid \":not()\" syntax: missing parentheticals');\n\t\t\t}\n\n\t\t\tparenRe.lastIndex = notWsRe.lastIndex;\n\t\t\tconst start  = notWsRe.lastIndex;\n\t\t\tconst result = { str : '', nextMatch : -1 };\n\t\t\tlet depth = 1;\n\n\t\t\twhile ((match = parenRe.exec(str)) !== null) {\n\t\t\t\tif (match[0] === '(') {\n\t\t\t\t\t++depth;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t--depth;\n\t\t\t\t}\n\n\t\t\t\tif (depth < 1) {\n\t\t\t\t\tresult.nextMatch = parenRe.lastIndex;\n\t\t\t\t\tresult.str = str.slice(start, result.nextMatch - 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tfunction parseSelector(idArg) {\n\t\t\tconst ids  = [];\n\t\t\tconst idRe = /:?[^\\s:()]+/g;\n\t\t\tlet match;\n\n\t\t\twhile ((match = idRe.exec(idArg)) !== null) {\n\t\t\t\tconst id = match[0];\n\n\t\t\t\t// Group negation.\n\t\t\t\tif (id === ':not') {\n\t\t\t\t\tif (ids.length === 0) {\n\t\t\t\t\t\tthrow new Error('invalid negation: no group ID preceded \":not()\"');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst parent = ids[ids.length - 1];\n\n\t\t\t\t\tif (parent.id[0] !== ':') {\n\t\t\t\t\t\tthrow new Error(`invalid negation of track \"${parent.id}\": only groups may be negated with \":not()\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst negation = processNegation(idArg, idRe.lastIndex);\n\n\t\t\t\t\tif (negation.nextMatch === -1) {\n\t\t\t\t\t\tthrow new Error('unknown error parsing \":not()\"');\n\t\t\t\t\t}\n\n\t\t\t\t\tidRe.lastIndex = negation.nextMatch;\n\t\t\t\t\tparent.not = parseSelector(negation.str);\n\t\t\t\t}\n\n\t\t\t\t// Group or track ID.\n\t\t\t\telse {\n\t\t\t\t\tids.push({ id });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn ids;\n\t\t}\n\n\t\treturn parseSelector;\n\t})();\n\n\t/*\n\t\tSimpleAudio.select(selector).…;\n\n\t\tE.g.\n\t\t\tSimpleAudio.select(':ui').…\n\t\t\tSimpleAudio.select(':ui:not(boop)').…\n\t\t\tSimpleAudio.select('boop beep').…\n\t\t\tSimpleAudio.select(':ui :sfx').…\n\t\t\tSimpleAudio.select(':ui:not(boop) :sfx overthetop').…\n\t*/\n\tfunction runnerGet(/* selector */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('no track selector specified');\n\t\t}\n\n\t\tconst selector = String(arguments[0]).trim();\n\t\tconst trackIds = new Set();\n\n\t\ttry {\n\t\t\tconst allIds = Array.from(_tracks.keys());\n\n\t\t\tfunction renderIds(idObj) {\n\t\t\t\tconst id = idObj.id;\n\t\t\t\tlet ids;\n\n\t\t\t\tswitch (id) {\n\t\t\t\tcase ':all':     ids = allIds; break;\n\t\t\t\tcase ':looped':  ids = allIds.filter(id => _tracks.get(id).loop()); break;\n\t\t\t\tcase ':muted':   ids = allIds.filter(id => _tracks.get(id).mute()); break;\n\t\t\t\tcase ':paused':  ids = allIds.filter(id => _tracks.get(id).isPaused()); break;\n\t\t\t\tcase ':playing': ids = allIds.filter(id => _tracks.get(id).isPlaying()); break;\n\t\t\t\tdefault:         ids = id[0] === ':' ? _groups.get(id) : [id]; break;\n\t\t\t\t}\n\n\t\t\t\tif (idObj.hasOwnProperty('not')) {\n\t\t\t\t\tconst negated = idObj.not.map(idObj => renderIds(idObj)).flat(Infinity);\n\t\t\t\t\tids = ids.filter(id => !negated.includes(id));\n\t\t\t\t}\n\n\t\t\t\treturn ids;\n\t\t\t}\n\n\t\t\t_runnerParseSelector(selector).forEach(idObj => renderIds(idObj).forEach(id => {\n\t\t\t\tif (!_tracks.has(id)) {\n\t\t\t\t\tthrow new Error(`track \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\ttrackIds.add(id);\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`error during runner initialization: ${ex.message}`);\n\t\t}\n\n\t\treturn new AudioRunner(trackIds);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMaster Audio Functions.\n\t*******************************************************************************************************************/\n\tfunction masterLoad() {\n\t\tpublish('load');\n\t}\n\n\tfunction masterLoadWithScreen() {\n\t\tpublish('loadwithscreen');\n\t}\n\n\tfunction masterMute(mute) {\n\t\tif (mute == null) { // lazy equality for null\n\t\t\treturn _masterMute;\n\t\t}\n\n\t\t_masterMute = !!mute;\n\t\tpublish('mute', _masterMute);\n\t}\n\n\tfunction masterMuteOnHidden(mute) {\n\t\t// NOTE: Some older browsers—notably: IE 9—do not support the Page Visibility API.\n\t\tif (!Visibility.isEnabled()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (mute == null) { // lazy equality for null\n\t\t\treturn _masterMuteOnHidden;\n\t\t}\n\n\t\t_masterMuteOnHidden = !!mute;\n\n\t\tconst namespace = '.SimpleAudio_masterMuteOnHidden';\n\n\t\tif (_masterMuteOnHidden) {\n\t\t\tconst visibilityChange = `${Visibility.changeEvent}${namespace}`;\n\t\t\tjQuery(document)\n\t\t\t\t.off(namespace)\n\t\t\t\t.on(visibilityChange, () => masterMute(Visibility.isHidden()));\n\n\t\t\t// Only change the mute state initially if hidden.\n\t\t\tif (Visibility.isHidden()) {\n\t\t\t\tmasterMute(true);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tjQuery(document).off(namespace);\n\t\t}\n\t}\n\n\tfunction masterRate(rate) {\n\t\tif (rate == null) { // lazy equality for null\n\t\t\treturn _masterRate;\n\t\t}\n\n\t\tif (typeof rate !== 'number' || Number.isNaN(rate) || !Number.isFinite(rate)) {\n\t\t\tthrow new Error('rate must be a finite number');\n\t\t}\n\n\t\t_masterRate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\t\tpublish('rate', _masterRate);\n\t}\n\n\tfunction masterStop() {\n\t\tpublish('stop');\n\t}\n\n\tfunction masterUnload() {\n\t\tpublish('unload');\n\t}\n\n\tfunction masterVolume(volume) {\n\t\tif (volume == null) { // lazy equality for null\n\t\t\treturn _masterVolume;\n\t\t}\n\n\t\tif (typeof volume !== 'number' || Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\tthrow new Error('volume must be a finite number');\n\t\t}\n\n\t\t_masterVolume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\t\tpublish('volume', _masterVolume);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSubscription Functions.\n\t*******************************************************************************************************************/\n\tfunction subscribe(id, callback) {\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new Error('callback parameter must be a function');\n\t\t}\n\n\t\t_subscribers.set(id, callback);\n\t}\n\n\tfunction unsubscribe(id) {\n\t\t_subscribers.delete(id);\n\t}\n\n\tfunction publish(mesg, data) {\n\t\t_subscribers.forEach(fn => fn(mesg, data));\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _newTrack(sources) {\n\t\treturn new AudioTrack(sources.map(source => {\n\t\t\t// Handle audio passages.\n\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\tif (passage.tags.includes('Twine.audio')) {\n\t\t\t\t\treturn passage.text.trim();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle URIs—possibly prefixed with a format specifier.\n\t\t\tconst match = _formatSpecRe.exec(source);\n\t\t\treturn match === null ? source : {\n\t\t\t\tformat : match[1],\n\t\t\t\tsrc    : match[2]\n\t\t\t};\n\t\t}));\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Track Functions.\n\t\ttracks : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : trackAdd },\n\t\t\t\tdelete : { value : trackDelete },\n\t\t\t\tclear  : { value : trackClear },\n\t\t\t\thas    : { value : trackHas },\n\t\t\t\tget    : { value : trackGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Group Functions.\n\t\tgroups : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : groupAdd },\n\t\t\t\tdelete : { value : groupDelete },\n\t\t\t\tclear  : { value : groupClear },\n\t\t\t\thas    : { value : groupHas },\n\t\t\t\tget    : { value : groupGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Playlist Functions.\n\t\tlists : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : listAdd },\n\t\t\t\tdelete : { value : listDelete },\n\t\t\t\tclear  : { value : listClear },\n\t\t\t\thas    : { value : listHas },\n\t\t\t\tget    : { value : listGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Runner Functions.\n\t\tselect : { value : runnerGet },\n\n\t\t// Master Audio Functions.\n\t\tload           : { value : masterLoad },\n\t\tloadWithScreen : { value : masterLoadWithScreen },\n\t\tmute           : { value : masterMute },\n\t\tmuteOnHidden   : { value : masterMuteOnHidden },\n\t\trate           : { value : masterRate },\n\t\tstop           : { value : masterStop },\n\t\tunload         : { value : masterUnload },\n\t\tvolume         : { value : masterVolume }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tstate.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Diff, Engine, PRNGWrapper, Patterns, clone, session, storage */\n\nvar State = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// History moment stack.\n\tlet _history = [];\n\n\t// Currently active/played moment.\n\tlet _active = momentCreate();\n\n\t// Currently active/played moment index.\n\tlet _activeIndex = -1;\n\n\t// Titles of all moments which have expired (i.e. fallen off the bottom of the stack).\n\tlet _expired = [];\n\n\t// (optional) Seedable PRNG object.\n\tlet _prng = null;\n\n\t// Temporary variables object.\n\tlet _tempVariables = {};\n\n\n\t/*******************************************************************************************************************\n\t\tState Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tResets the story state.\n\t*/\n\tfunction stateReset() {\n\t\tif (DEBUG) { console.log('[State/stateReset()]'); }\n\n\t\t/*\n\t\t\tDelete the active session.\n\t\t*/\n\t\tsession.delete('state');\n\n\t\t/*\n\t\t\tReset the properties.\n\t\t*/\n\t\t_history     = [];\n\t\t_active      = momentCreate();\n\t\t_activeIndex = -1;\n\t\t_expired     = [];\n\t\t_prng        = _prng === null ? null : new PRNGWrapper(_prng.seed, false);\n\t}\n\n\t/*\n\t\tRestores the story state from the active session.\n\t*/\n\tfunction stateRestore() {\n\t\tif (DEBUG) { console.log('[State/stateRestore()]'); }\n\n\t\t/*\n\t\t\tAttempt to restore an active session.\n\t\t*/\n\t\tif (session.has('state')) {\n\t\t\t/*\n\t\t\t\tRetrieve the session.\n\t\t\t*/\n\t\t\tconst stateObj = session.get('state');\n\n\t\t\tif (DEBUG) { console.log('\\tsession state:', stateObj); }\n\n\t\t\tif (stateObj == null) { // lazy equality for null\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tRestore the session.\n\t\t\t*/\n\t\t\tstateUnmarshal(stateObj);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tReturns the current story state marshaled into a serializable object.\n\t*/\n\tfunction stateMarshal(noDelta) {\n\t\t/*\n\t\t\tGather the properties.\n\t\t*/\n\t\tconst stateObj = {\n\t\t\tindex : _activeIndex\n\t\t};\n\n\t\tif (noDelta) {\n\t\t\tstateObj.history = clone(_history);\n\t\t}\n\t\telse {\n\t\t\tstateObj.delta = historyDeltaEncode(_history);\n\t\t}\n\n\t\tif (_expired.length > 0) {\n\t\t\tstateObj.expired = [];\n\t\t}\n\n\t\tif (_prng !== null) {\n\t\t\tstateObj.seed = _prng.seed;\n\t\t}\n\n\t\treturn stateObj;\n\t}\n\n\t/*\n\t\tRestores the story state from a marshaled story state serialization object.\n\t*/\n\tfunction stateUnmarshal(stateObj, noDelta) {\n\t\tif (stateObj == null) { // lazy equality for null\n\t\t\tthrow new Error('state object is null or undefined');\n\t\t}\n\n\t\tif (\n\t\t\t   !stateObj.hasOwnProperty(noDelta ? 'history' : 'delta')\n\t\t\t|| stateObj[noDelta ? 'history' : 'delta'].length === 0\n\t\t) {\n\t\t\tthrow new Error('state object has no history or history is empty');\n\t\t}\n\n\t\tif (!stateObj.hasOwnProperty('index')) {\n\t\t\tthrow new Error('state object has no index');\n\t\t}\n\n\t\tif (_prng !== null && !stateObj.hasOwnProperty('seed')) {\n\t\t\tthrow new Error('state object has no seed, but PRNG is enabled');\n\t\t}\n\n\t\tif (_prng === null && stateObj.hasOwnProperty('seed')) {\n\t\t\tthrow new Error('state object has seed, but PRNG is disabled');\n\t\t}\n\n\t\t/*\n\t\t\tRestore the properties.\n\t\t*/\n\t\t_history     = noDelta ? clone(stateObj.history) : historyDeltaDecode(stateObj.delta);\n\t\t_activeIndex = stateObj.index;\n\t\t_expired     = stateObj.hasOwnProperty('expired') ? [...stateObj.expired] : [];\n\n\t\tif (stateObj.hasOwnProperty('seed')) {\n\t\t\t/*\n\t\t\t\tWe only need to restore the PRNG's seed here as `momentActivate()` will handle\n\t\t\t\tfully restoring the PRNG to its proper state.\n\t\t\t*/\n\t\t\t_prng.seed = stateObj.seed;\n\t\t}\n\n\t\t/*\n\t\t\tActivate the current moment (do this only after all properties have been restored).\n\t\t*/\n\t\tmomentActivate(_activeIndex);\n\t}\n\n\t/*\n\t\tReturns the current story state marshaled into a save-compatible serializable object.\n\t*/\n\tfunction stateMarshalForSave() {\n\t\treturn stateMarshal(true);\n\t}\n\n\t/*\n\t\tRestores the story state from a marshaled save-compatible story state serialization object.\n\t*/\n\tfunction stateUnmarshalForSave(stateObj) {\n\t\treturn stateUnmarshal(stateObj, true);\n\t}\n\n\t/*\n\t\tReturns the titles of expired moments.\n\t*/\n\tfunction stateExpired() {\n\t\treturn _expired;\n\t}\n\n\t/*\n\t\tReturns the total number of played moments (expired + in-play history moments).\n\t*/\n\tfunction stateTurns() {\n\t\treturn _expired.length + historyLength();\n\t}\n\n\t/*\n\t\tReturns the passage titles of all played moments (expired + in-play history moments).\n\t*/\n\tfunction stateTitles() {\n\t\treturn _expired.concat(_history.slice(0, historyLength()).map(moment => moment.title));\n\t}\n\n\t/*\n\t\tReturns whether a passage with the given title has been played (expired + in-play history moments).\n\t*/\n\tfunction stateHasPlayed(title) {\n\t\tif (title == null || title === '') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tif (_expired.includes(title)) {\n\t\t\treturn true;\n\t\t}\n\t\telse if (_history.slice(0, historyLength()).some(moment => moment.title === title)) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMoment Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a new moment object created from the given passage title and variables object.\n\t*/\n\tfunction momentCreate(title, variables) {\n\t\treturn {\n\t\t\ttitle     : title == null ? '' : String(title),       // lazy equality for null\n\t\t\tvariables : variables == null ? {} : clone(variables) // lazy equality for null\n\t\t};\n\t}\n\n\t/*\n\t\tReturns the active (present) moment.\n\t*/\n\tfunction momentActive() {\n\t\treturn _active;\n\t}\n\n\t/*\n\t\tReturns the index within the history of the active (present) moment.\n\t*/\n\tfunction momentActiveIndex() {\n\t\treturn _activeIndex;\n\t}\n\n\t/*\n\t\tReturns the title from the active (present) moment.\n\t*/\n\tfunction momentActiveTitle() {\n\t\treturn _active.title;\n\t}\n\n\t/*\n\t\tReturns the variables from the active (present) moment.\n\t*/\n\tfunction momentActiveVariables() {\n\t\treturn _active.variables;\n\t}\n\n\t/*\n\t\tReturns the active (present) moment after setting it to either the given moment object\n\t\tor the moment object at the given history index.  Additionally, updates the active session\n\t\tand triggers a history update event.\n\t*/\n\tfunction momentActivate(moment) {\n\t\tif (moment == null) { // lazy equality for null\n\t\t\tthrow new Error('moment activation attempted with null or undefined');\n\t\t}\n\n\t\t/*\n\t\t\tSet the active moment.\n\t\t*/\n\t\tswitch (typeof moment) {\n\t\tcase 'object':\n\t\t\t_active = clone(moment);\n\t\t\tbreak;\n\n\t\tcase 'number':\n\t\t\tif (historyIsEmpty()) {\n\t\t\t\tthrow new Error('moment activation attempted with index on empty history');\n\t\t\t}\n\n\t\t\tif (moment < 0 || moment >= historySize()) {\n\t\t\t\tthrow new RangeError(`moment activation attempted with out-of-bounds index; need [0, ${historySize() - 1}], got ${moment}`);\n\t\t\t}\n\n\t\t\t_active = clone(_history[moment]);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new TypeError(`moment activation attempted with a \"${typeof moment}\"; must be an object or valid history stack index`);\n\t\t}\n\n\t\t/*\n\t\t\tRestore the seedable PRNG.\n\n\t\t\tNOTE: We cannot simply set `_prng.pull` to `_active.pull` as that would\n\t\t\tnot properly mutate the PRNG's internal state.\n\t\t*/\n\t\tif (_prng !== null) {\n\t\t\t_prng = PRNGWrapper.unmarshal({\n\t\t\t\tseed : _prng.seed,\n\t\t\t\tpull : _active.pull\n\t\t\t});\n\t\t}\n\n\t\t/*\n\t\t\tUpdate the active session.\n\t\t*/\n\t\tsession.set('state', stateMarshal());\n\n\t\t/*\n\t\t\tTrigger a global `:historyupdate` event.\n\n\t\t\tNOTE: We do this here because setting a new active moment is a core component\n\t\t\tof, virtually, all history updates.\n\t\t*/\n\t\tjQuery.event.trigger(':historyupdate');\n\n\t\treturn _active;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tHistory Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the moment history.\n\t*/\n\tfunction historyGet() {\n\t\treturn _history;\n\t}\n\n\t/*\n\t\tReturns the number of active history moments (past only).\n\t*/\n\tfunction historyLength() {\n\t\treturn _activeIndex + 1;\n\t}\n\n\t/*\n\t\tReturns the total number of history moments (past + future).\n\t*/\n\tfunction historySize() {\n\t\treturn _history.length;\n\t}\n\n\t/*\n\t\tReturns whether the history is empty.\n\t*/\n\tfunction historyIsEmpty() {\n\t\treturn _history.length === 0;\n\t}\n\n\t/*\n\t\tReturns the current (pre-play version of the active) moment within the history.\n\t*/\n\tfunction historyCurrent() {\n\t\treturn _history.length > 0 ? _history[_activeIndex] : null;\n\t}\n\n\t/*\n\t\tReturns the topmost (most recent) moment within the history.\n\t*/\n\tfunction historyTop() {\n\t\treturn _history.length > 0 ? _history[_history.length - 1] : null;\n\t}\n\n\t/*\n\t\tReturns the bottommost (least recent) moment within the history.\n\t*/\n\tfunction historyBottom() {\n\t\treturn _history.length > 0 ? _history[0] : null;\n\t}\n\n\t/*\n\t\tReturns the moment at the given index within the history.\n\t*/\n\tfunction historyIndex(index) {\n\t\tif (historyIsEmpty() || index < 0 || index > _activeIndex) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn _history[index];\n\t}\n\n\t/*\n\t\tReturns the moment at the given offset from the active moment within the history.\n\t*/\n\tfunction historyPeek(offset) {\n\t\tif (historyIsEmpty()) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst lengthOffset = 1 + (offset ? Math.abs(offset) : 0);\n\n\t\tif (lengthOffset > historyLength()) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn _history[historyLength() - lengthOffset];\n\t}\n\n\t/*\n\t\tReturns whether a moment with the given title exists within the history.\n\t*/\n\tfunction historyHas(title) {\n\t\tif (historyIsEmpty() || title == null || title === '') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (let i = _activeIndex; i >= 0; --i) {\n\t\t\tif (_history[i].title === title) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tCreates a new moment and pushes it onto the history, discarding future moments if necessary.\n\t*/\n\tfunction historyCreate(title) {\n\t\tif (DEBUG) { console.log(`[State/historyCreate(title: \"${title}\")]`); }\n\n\t\t/*\n\t\t\tTODO: It might be good to have some assertions about the passage title here.\n\t\t*/\n\n\t\t/*\n\t\t\tIf we're not at the top of the stack, discard the future moments.\n\t\t*/\n\t\tif (historyLength() < historySize()) {\n\t\t\tif (DEBUG) { console.log(`\\tnon-top push; discarding ${historySize() - historyLength()} future moments`); }\n\n\t\t\t_history.splice(historyLength(), historySize() - historyLength());\n\t\t}\n\n\t\t/*\n\t\t\tPush the new moment onto the history stack.\n\t\t*/\n\t\t_history.push(momentCreate(title, _active.variables));\n\n\t\tif (_prng) {\n\t\t\thistoryTop().pull = _prng.pull;\n\t\t}\n\n\t\t/*\n\t\t\tTruncate the history, if necessary, by discarding moments from the bottom.\n\t\t*/\n\t\tif (Config.history.maxStates > 0) {\n\t\t\twhile (historySize() > Config.history.maxStates) {\n\t\t\t\t_expired.push(_history.shift().title);\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t\tActivate the new top moment.\n\t\t*/\n\t\t_activeIndex = historySize() - 1;\n\t\tmomentActivate(_activeIndex);\n\n\t\treturn historyLength();\n\t}\n\n\t/*\n\t\tActivate the moment at the given index within the history.\n\t*/\n\tfunction historyGoTo(index) {\n\t\tif (DEBUG) { console.log(`[State/historyGoTo(index: ${index})]`); }\n\n\t\tif (\n\t\t\t   index == null /* lazy equality for null */\n\t\t\t|| index < 0\n\t\t\t|| index >= historySize()\n\t\t\t|| index === _activeIndex\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\t_activeIndex = index;\n\t\tmomentActivate(_activeIndex);\n\n\t\treturn true;\n\t}\n\n\t/*\n\t\tActivate the moment at the given offset from the active moment within the history.\n\t*/\n\tfunction historyGo(offset) {\n\t\tif (DEBUG) { console.log(`[State/historyGo(offset: ${offset})]`); }\n\n\t\tif (offset == null || offset === 0) { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\treturn historyGoTo(_activeIndex + offset);\n\t}\n\n\t/*\n\t\tReturns the delta encoded form of the given history array.\n\t*/\n\tfunction historyDeltaEncode(historyArr) {\n\t\tif (!Array.isArray(historyArr)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (historyArr.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst delta = [clone(historyArr[0])];\n\n\t\tfor (let i = 1, iend = historyArr.length; i < iend; ++i) {\n\t\t\tdelta.push(Diff.diff(historyArr[i - 1], historyArr[i]));\n\t\t}\n\n\t\treturn delta;\n\t}\n\n\t/*\n\t\tReturns a history array from the given delta encoded history array.\n\t*/\n\tfunction historyDeltaDecode(delta) {\n\t\tif (!Array.isArray(delta)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (delta.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst historyArr = [clone(delta[0])];\n\n\t\tfor (let i = 1, iend = delta.length; i < iend; ++i) {\n\t\t\thistoryArr.push(Diff.patch(historyArr[i - 1], delta[i]));\n\t\t}\n\n\t\treturn historyArr;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPRNG Functions.\n\t*******************************************************************************************************************/\n\tfunction prngInit(seed, useEntropy) {\n\t\tif (DEBUG) { console.log(`[State/prngInit(seed: ${seed}, useEntropy: ${useEntropy})]`); }\n\n\t\tif (!historyIsEmpty()) {\n\t\t\tlet scriptSection;\n\n\t\t\tif (TWINE1) { // for Twine 1\n\t\t\t\tscriptSection = 'a script-tagged passage';\n\t\t\t}\n\t\t\telse { // for Twine 2\n\t\t\t\tscriptSection = 'the Story JavaScript';\n\t\t\t}\n\n\t\t\tthrow new Error(`State.initPRNG must be called during initialization, within either ${scriptSection} or the StoryInit special passage`);\n\t\t}\n\n\t\t_prng = new PRNGWrapper(seed, useEntropy);\n\t\t_active.pull = _prng.pull;\n\t}\n\n\tfunction prngIsEnabled() {\n\t\treturn _prng !== null;\n\t}\n\n\tfunction prngPull() {\n\t\treturn _prng ? _prng.pull : NaN;\n\t}\n\n\tfunction prngSeed() {\n\t\treturn _prng ? _prng.seed : null;\n\t}\n\n\tfunction prngRandom() {\n\t\tif (DEBUG) { console.log('[State/prngRandom()]'); }\n\n\t\treturn _prng ? _prng.random() : Math.random();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTemporary Variables Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tClear the temporary variables.\n\t*/\n\tfunction tempVariablesClear() {\n\t\tif (DEBUG) { console.log('[State/tempVariablesReset()]'); }\n\n\t\t_tempVariables = {};\n\n\t\t/* legacy */\n\t\tTempVariables = _tempVariables; // eslint-disable-line no-undef\n\t\t/* /legacy */\n\t}\n\n\t/*\n\t\tReturns the current temporary variables.\n\t*/\n\tfunction tempVariables() {\n\t\treturn _tempVariables;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tVariable Chain Parsing Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the value of the given story/temporary variable.\n\t*/\n\tfunction variableGet(name) {\n\t\tconst varData = _parseVariableChain(name);\n\n\t\tif (varData === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst pNames = varData.names;\n\t\tlet retVal = varData.store;\n\n\t\tfor (let i = 0, iend = pNames.length; i < iend; ++i) {\n\t\t\tif (typeof retVal[pNames[i]] === 'undefined') {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tretVal = retVal[pNames[i]];\n\t\t}\n\n\t\treturn retVal;\n\t}\n\n\t/*\n\t\tSets the value of the given story/temporary variable.\n\t*/\n\tfunction variableSet(name, value) {\n\t\tconst varData = _parseVariableChain(name);\n\n\t\tif (varData === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst pNames  = varData.names;\n\t\tconst varName = pNames.pop();\n\t\tlet baseObj = varData.store;\n\n\t\tfor (let i = 0, iend = pNames.length; i < iend; ++i) {\n\t\t\tif (typeof baseObj[pNames[i]] === 'undefined') {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tbaseObj = baseObj[pNames[i]];\n\t\t}\n\n\t\tbaseObj[varName] = value;\n\t\treturn true;\n\t}\n\n\t/*\n\t\tReturns the property name chain of the given story/temporary variable,\n\t\twhich may be of arbitrary complexity.\n\t*/\n\tconst _parseVarRegExp = new RegExp(`^(?:${Patterns.variableSigil}(${Patterns.identifier})|\\\\.(${Patterns.identifier})|\\\\[(?:(?:\"((?:\\\\\\\\.|[^\"\\\\\\\\])+)\")|(?:'((?:\\\\\\\\.|[^'\\\\\\\\])+)')|(${Patterns.variableSigil}${Patterns.identifierFirstChar}.*)|(\\\\d+))\\\\])`);\n\tfunction _parseVariableChain(varText) {\n\t\tconst retVal = {\n\t\t\tstore : varText[0] === '$' ? State.variables : State.temporary,\n\t\t\tnames : []\n\t\t};\n\t\tlet text  = varText;\n\t\tlet match;\n\n\t\twhile ((match = _parseVarRegExp.exec(text)) !== null) {\n\t\t\t// Remove full match from text.\n\t\t\ttext = text.slice(match[0].length);\n\n\t\t\t// Base variable.\n\t\t\tif (match[1]) {\n\t\t\t\tretVal.names.push(match[1]);\n\t\t\t}\n\n\t\t\t// Dot property.\n\t\t\telse if (match[2]) {\n\t\t\t\tretVal.names.push(match[2]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (double quoted).\n\t\t\telse if (match[3]) {\n\t\t\t\tretVal.names.push(match[3]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (single quoted).\n\t\t\telse if (match[4]) {\n\t\t\t\tretVal.names.push(match[4]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (embedded variable).\n\t\t\telse if (match[5]) {\n\t\t\t\tretVal.names.push(variableGet(match[5]));\n\t\t\t}\n\n\t\t\t// Square-bracketed property (numeric index).\n\t\t\telse if (match[6]) {\n\t\t\t\tretVal.names.push(Number(match[6]));\n\t\t\t}\n\t\t}\n\n\t\treturn text === '' ? retVal : null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tStory Metadata Functions.\n\t*******************************************************************************************************************/\n\tconst _METADATA_STORE = 'metadata';\n\n\tfunction metadataClear() {\n\t\tstorage.delete(_METADATA_STORE);\n\t}\n\n\tfunction metadataDelete(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.delete key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\n\t\tif (store && store.hasOwnProperty(key)) {\n\t\t\tif (Object.keys(store).length === 1) {\n\t\t\t\tstorage.delete(_METADATA_STORE);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdelete store[key];\n\t\t\t\tstorage.set(_METADATA_STORE, store);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction metadataGet(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.get key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store && store.hasOwnProperty(key) ? store[key] : undefined;\n\t}\n\n\tfunction metadataHas(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.has key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store && store.hasOwnProperty(key);\n\t}\n\n\tfunction metadataSet(key, value) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.set key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tif (typeof value === 'undefined') {\n\t\t\tmetadataDelete(key);\n\t\t}\n\t\telse {\n\t\t\tconst store = storage.get(_METADATA_STORE) || {};\n\t\t\tstore[key] = value;\n\t\t\tstorage.set(_METADATA_STORE, store);\n\t\t}\n\t}\n\n\tfunction metadataSize() {\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store ? Object.keys(store).length : 0;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tState Functions.\n\t\t*/\n\t\treset            : { value : stateReset },\n\t\trestore          : { value : stateRestore },\n\t\tmarshalForSave   : { value : stateMarshalForSave },\n\t\tunmarshalForSave : { value : stateUnmarshalForSave },\n\t\texpired          : { get : stateExpired },\n\t\tturns            : { get : stateTurns },\n\t\tpassages         : { get : stateTitles },\n\t\thasPlayed        : { value : stateHasPlayed },\n\n\t\t/*\n\t\t\tMoment Functions.\n\t\t*/\n\t\tactive      : { get : momentActive },\n\t\tactiveIndex : { get : momentActiveIndex },\n\t\tpassage     : { get : momentActiveTitle },     // shortcut for `State.active.title`\n\t\tvariables   : { get : momentActiveVariables }, // shortcut for `State.active.variables`\n\n\t\t/*\n\t\t\tHistory Functions.\n\t\t*/\n\t\thistory     : { get : historyGet },\n\t\tlength      : { get : historyLength },\n\t\tsize        : { get : historySize },\n\t\tisEmpty     : { value : historyIsEmpty },\n\t\tcurrent     : { get : historyCurrent },\n\t\ttop         : { get : historyTop },\n\t\tbottom      : { get : historyBottom },\n\t\tindex       : { value : historyIndex },\n\t\tpeek        : { value : historyPeek },\n\t\thas         : { value : historyHas },\n\t\tcreate      : { value : historyCreate },\n\t\tgoTo        : { value : historyGoTo },\n\t\tgo          : { value : historyGo },\n\t\tdeltaEncode : { value : historyDeltaEncode },\n\t\tdeltaDecode : { value : historyDeltaDecode },\n\n\t\t/*\n\t\t\tPRNG Functions.\n\t\t*/\n\t\tprng : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tinit      : { value : prngInit },\n\t\t\t\tisEnabled : { value : prngIsEnabled },\n\t\t\t\tpull      : { get : prngPull },\n\t\t\t\tseed      : { get : prngSeed }\n\t\t\t}))\n\t\t},\n\t\trandom : { value : prngRandom },\n\n\t\t/*\n\t\t\tTemporary Variables Functions.\n\t\t*/\n\t\tclearTemporary : { value : tempVariablesClear },\n\t\ttemporary      : { get : tempVariables },\n\n\t\t/*\n\t\t\tVariable Chain Parsing Functions.\n\t\t*/\n\t\tgetVar : { value : variableGet },\n\t\tsetVar : { value : variableSet },\n\n\t\t/*\n\t\t\tStory Metadata Functions.\n\t\t*/\n\t\tmetadata : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tclear  : { value : metadataClear },\n\t\t\t\tdelete : { value : metadataDelete },\n\t\t\t\tget    : { value : metadataGet },\n\t\t\t\thas    : { value : metadataHas },\n\t\t\t\tset    : { value : metadataSet },\n\t\t\t\tsize   : { get : metadataSize }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tinitPRNG : { value : prngInit },\n\t\trestart  : { value : () => Engine.restart() },\n\t\tbackward : { value : () => Engine.backward() },\n\t\tforward  : { value : () => Engine.forward() },\n\t\tdisplay  : { value : (...args) => Engine.display(...args) },\n\t\tshow     : { value : (...args) => Engine.show(...args) },\n\t\tplay     : { value : (...args) => Engine.play(...args) }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/scripting.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Engine, Patterns, State, Story, Util */\n\nvar Scripting = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/* eslint-disable no-unused-vars */\n\n\t/*******************************************************************************************************************\n\t\tDeprecated Legacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Returns the jQuery-wrapped target element(s) after making them accessible\n\t\tclickables (ARIA compatibility).\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction addAccessibleClickHandler(targets, selector, handler, one, namespace) {\n\t\tif (arguments.length < 2) {\n\t\t\tthrow new Error('addAccessibleClickHandler insufficient number of parameters');\n\t\t}\n\n\t\tlet fn;\n\t\tlet opts;\n\n\t\tif (typeof selector === 'function') {\n\t\t\tfn = selector;\n\t\t\topts = {\n\t\t\t\tnamespace : one,\n\t\t\t\tone       : !!handler\n\t\t\t};\n\t\t}\n\t\telse {\n\t\t\tfn = handler;\n\t\t\topts = {\n\t\t\t\tnamespace,\n\t\t\t\tone : !!one,\n\t\t\t\tselector\n\t\t\t};\n\t\t}\n\n\t\tif (typeof fn !== 'function') {\n\t\t\tthrow new TypeError('addAccessibleClickHandler handler parameter must be a function');\n\t\t}\n\n\t\treturn jQuery(targets).ariaClick(opts, fn);\n\t}\n\n\t/*\n\t\t[DEPRECATED] Returns a new DOM element, optionally appending it to the passed DOM element, if any.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction insertElement(place, type, id, classNames, text, title) { // eslint-disable-line max-params\n\t\tconst $el = jQuery(document.createElement(type));\n\n\t\t// Add attributes/properties.\n\t\tif (id) {\n\t\t\t$el.attr('id', id);\n\t\t}\n\n\t\tif (classNames) {\n\t\t\t$el.addClass(classNames);\n\t\t}\n\n\t\tif (title) {\n\t\t\t$el.attr('title', title);\n\t\t}\n\n\t\t// Add text content.\n\t\tif (text) {\n\t\t\t$el.text(text);\n\t\t}\n\n\t\t// Append it to the given node.\n\t\tif (place) {\n\t\t\t$el.appendTo(place);\n\t\t}\n\n\t\treturn $el[0];\n\t}\n\n\t/*\n\t\t[DEPRECATED] Creates a new text node and appends it to the passed DOM element.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction insertText(place, text) {\n\t\tjQuery(place).append(document.createTextNode(text));\n\t}\n\n\t/*\n\t\t[DEPRECATED] Removes all children from the passed DOM node.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction removeChildren(node) {\n\t\tjQuery(node).empty();\n\t}\n\n\t/*\n\t\t[DEPRECATED] Removes the passed DOM node.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction removeElement(node) {\n\t\tjQuery(node).remove();\n\t}\n\n\t/*\n\t\t[DEPRECATED] Fades a DOM element in or out.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction fade(el, options) {\n\t\t/* eslint-disable no-param-reassign */\n\t\tconst direction = options.fade === 'in' ? 1 : -1;\n\t\tlet current;\n\t\tlet proxy      = el.cloneNode(true);\n\t\tlet intervalId; // eslint-disable-line prefer-const\n\n\t\tfunction tick() {\n\t\t\tcurrent += 0.05 * direction;\n\t\t\tsetOpacity(proxy, Math.easeInOut(current));\n\n\t\t\tif (direction === 1 && current >= 1 || direction === -1 && current <= 0) {\n\t\t\t\tel.style.visibility = options.fade === 'in' ? 'visible' : 'hidden';\n\t\t\t\tproxy.parentNode.replaceChild(el, proxy);\n\t\t\t\tproxy = null;\n\t\t\t\twindow.clearInterval(intervalId);\n\n\t\t\t\tif (options.onComplete) {\n\t\t\t\t\toptions.onComplete();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction setOpacity(el, opacity) {\n\t\t\t// Old IE.\n\t\t\tel.style.zoom = 1;\n\t\t\tel.style.filter = `alpha(opacity=${Math.floor(opacity * 100)})`;\n\n\t\t\t// CSS.\n\t\t\tel.style.opacity = opacity;\n\t\t}\n\n\t\tel.parentNode.replaceChild(proxy, el);\n\n\t\tif (options.fade === 'in') {\n\t\t\tcurrent = 0;\n\t\t\tproxy.style.visibility = 'visible';\n\t\t}\n\t\telse {\n\t\t\tcurrent = 1;\n\t\t}\n\n\t\tsetOpacity(proxy, current);\n\t\tintervalId = window.setInterval(tick, 25);\n\t\t/* eslint-enable no-param-reassign */\n\t}\n\n\t/*\n\t\t[DEPRECATED] Scrolls the browser window to ensure that a DOM element is in view.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction scrollWindowTo(el, incrementBy) {\n\t\t/* eslint-disable no-param-reassign */\n\t\tlet increment = incrementBy != null ? Number(incrementBy) : 0.1; // lazy equality for null\n\n\t\tif (Number.isNaN(increment) || !Number.isFinite(increment) || increment < 0) {\n\t\t\tincrement = 0.1;\n\t\t}\n\t\telse if (increment > 1) {\n\t\t\tincrement = 1;\n\t\t}\n\n\t\tconst start     = window.scrollY ? window.scrollY : document.body.scrollTop;\n\t\tconst end       = ensureVisible(el);\n\t\tconst distance  = Math.abs(start - end);\n\t\tconst direction = start > end ? -1 : 1;\n\t\tlet progress   = 0;\n\t\tlet intervalId; // eslint-disable-line prefer-const\n\n\t\tfunction tick() {\n\t\t\tprogress += increment;\n\t\t\twindow.scroll(0, start + direction * (distance * Math.easeInOut(progress)));\n\n\t\t\tif (progress >= 1) {\n\t\t\t\twindow.clearInterval(intervalId);\n\t\t\t}\n\t\t}\n\n\t\tfunction findPosY(el) { // eslint-disable-line no-shadow\n\t\t\tlet curtop = 0;\n\n\t\t\twhile (el.offsetParent) {\n\t\t\t\tcurtop += el.offsetTop;\n\t\t\t\tel = el.offsetParent;\n\t\t\t}\n\n\t\t\treturn curtop;\n\t\t}\n\n\t\tfunction ensureVisible(el) { // eslint-disable-line no-shadow\n\t\t\tconst posTop    = findPosY(el);\n\t\t\tconst posBottom = posTop + el.offsetHeight;\n\t\t\tconst winTop    = window.scrollY ? window.scrollY : document.body.scrollTop;\n\t\t\tconst winHeight = window.innerHeight ? window.innerHeight : document.body.clientHeight;\n\t\t\tconst winBottom = winTop + winHeight;\n\n\t\t\treturn posTop >= winTop && posBottom > winBottom && el.offsetHeight < winHeight\n\t\t\t\t? posTop - (winHeight - el.offsetHeight) + 20\n\t\t\t\t: posTop;\n\t\t}\n\n\t\tintervalId = window.setInterval(tick, 25);\n\t\t/* eslint-enable no-param-reassign */\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUser Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a random value from its given arguments.\n\t*/\n\tfunction either(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn Array.prototype.concat.apply([], arguments).random();\n\t}\n\n\t/*\n\t\tRemoves the given key, and its value, from the story metadata store.\n\t*/\n\tfunction forget(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`forget key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\tState.metadata.delete(key);\n\t}\n\n\t/*\n\t\tReturns whether a passage with the given title exists within the story\n\t\thistory.  If multiple passage titles are given, returns the logical-AND\n\t\taggregate of the set.\n\t*/\n\tfunction hasVisited(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('hasVisited called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst played  = State.passages;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend; ++i) {\n\t\t\tif (!played.includes(needles[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/*\n\t\tReturns the number of turns that have passed since the last instance of the given passage\n\t\toccurred within the story history or `-1` if it does not exist.  If multiple passages are\n\t\tgiven, returns the lowest count (which can be `-1`).\n\t*/\n\tfunction lastVisited(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('lastVisited called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn -1;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst played  = State.passages;\n\t\tconst uBound  = played.length - 1;\n\t\tlet turns = State.turns;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend && turns > -1; ++i) {\n\t\t\tconst lastIndex = played.lastIndexOf(needles[i]);\n\t\t\tturns = Math.min(turns, lastIndex === -1 ? -1 : uBound - lastIndex);\n\t\t}\n\n\t\treturn turns;\n\t}\n\n\t/*\n\t\tSets the given key/value pair within the story metadata store.\n\t*/\n\tfunction memorize(key, value) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`memorize key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\tState.metadata.set(key, value);\n\t}\n\n\t/*\n\t\tReturns the title of the current passage.\n\t*/\n\tfunction passage() {\n\t\treturn State.passage;\n\t}\n\n\t/*\n\t\tReturns the title of a previous passage, either the most recent one whose title does not\n\t\tmatch that of the active passage or the one at the optional offset, or an empty string,\n\t\tif there is no such passage.\n\t*/\n\tfunction previous(/* legacy: offset */) {\n\t\tconst passages = State.passages;\n\n\t\t/* legacy: behavior with an offset */\n\t\tif (arguments.length > 0) {\n\t\t\tconst offset = Number(arguments[0]);\n\n\t\t\tif (!Number.isSafeInteger(offset) || offset < 1) {\n\t\t\t\tthrow new RangeError('previous offset parameter must be a positive integer greater than zero');\n\t\t\t}\n\n\t\t\treturn passages.length > offset ? passages[passages.length - 1 - offset] : '';\n\t\t}\n\t\t/* /legacy */\n\n\t\tfor (let i = passages.length - 2; i >= 0; --i) {\n\t\t\tif (passages[i] !== State.passage) {\n\t\t\t\treturn passages[i];\n\t\t\t}\n\t\t}\n\n\t\treturn '';\n\t}\n\n\t/*\n\t\tReturns a pseudo-random whole number (integer) within the range of the given bounds.\n\t*/\n\tfunction random(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('random called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = Math.trunc(arguments[0]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Math.trunc(arguments[0]);\n\t\t\tmax = Math.trunc(arguments[1]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (!Number.isInteger(min)) {\n\t\t\tthrow new Error('random min parameter must be an integer');\n\t\t}\n\t\tif (!Number.isInteger(max)) {\n\t\t\tthrow new Error('random max parameter must be an integer');\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn Math.floor(State.random() * (max - min + 1)) + min;\n\t}\n\n\t/*\n\t\tReturns a pseudo-random real number (floating-point) within the range of the given bounds.\n\n\t\tNOTE: Unlike with its sibling function `random()`, the `max` parameter\n\t\tis exclusive, not inclusive—i.e. the range goes to, but does not include,\n\t\tthe given value.\n\t*/\n\tfunction randomFloat(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('randomFloat called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0.0;\n\t\t\tmax = Number(arguments[0]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Number(arguments[0]);\n\t\t\tmax = Number(arguments[1]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (Number.isNaN(min) || !Number.isFinite(min)) {\n\t\t\tthrow new Error('randomFloat min parameter must be a number');\n\t\t}\n\t\tif (Number.isNaN(max) || !Number.isFinite(max)) {\n\t\t\tthrow new Error('randomFloat max parameter must be a number');\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn State.random() * (max - min) + min;\n\t}\n\n\t/*\n\t\tReturns the value of the given key from the story metadata store\n\t\tor the given default value if the key does not exist.\n\t*/\n\tfunction recall(key, defaultValue) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`recall key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\treturn State.metadata.has(key) ? State.metadata.get(key) : defaultValue;\n\t}\n\n\t/*\n\t\tReturns a new array consisting of all of the tags of the given passages.\n\t*/\n\tfunction tags(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\treturn Story.get(State.passage).tags.slice(0);\n\t\t}\n\n\t\tconst passages = Array.prototype.concat.apply([], arguments);\n\t\tlet tags = [];\n\n\t\tfor (let i = 0, iend = passages.length; i < iend; ++i) {\n\t\t\ttags = tags.concat(Story.get(passages[i]).tags);\n\t\t}\n\n\t\treturn tags;\n\t}\n\n\t/*\n\t\tReturns a reference to the current temporary _variables store.\n\t*/\n\tfunction temporary() {\n\t\treturn State.temporary;\n\t}\n\n\t/*\n\t\tReturns the number of milliseconds which have passed since the current passage was rendered.\n\t*/\n\tfunction time() {\n\t\treturn Engine.lastPlay === null ? 0 : Util.now() - Engine.lastPlay;\n\t}\n\n\t/*\n\t\tReturns the number of passages that the player has visited.\n\n\t\tNOTE: Passages which were visited but have been undone—e.g. via the backward\n\t\tbutton or the `<<back>>` macro—are no longer part of the in-play story\n\t\thistory and thus are not tallied.  Passages which were visited but have\n\t\texpired from the story history, on the other hand, are tallied.\n\t*/\n\tfunction turns() {\n\t\treturn State.turns;\n\t}\n\n\t/*\n\t\tReturns a reference to the current story $variables store.\n\t*/\n\tfunction variables() {\n\t\treturn State.variables;\n\t}\n\n\t/*\n\t\tReturns the number of times that the passage with the given title exists within the story\n\t\thistory.  If multiple passage titles are given, returns the lowest count.\n\t*/\n\tfunction visited(/* variadic */) {\n\t\tif (State.isEmpty()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments.length === 0 ? [State.passage] : arguments);\n\t\tconst played  = State.passages;\n\t\tlet count = State.turns;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend && count > 0; ++i) {\n\t\t\tcount = Math.min(count, played.count(needles[i]));\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/*\n\t\tReturns the number of passages within the story history which are tagged with all of the given tags.\n\t*/\n\tfunction visitedTags(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('visitedTags called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst nLength = needles.length;\n\t\tconst played  = State.passages;\n\t\tconst seen    = new Map();\n\t\tlet count = 0;\n\n\t\tfor (let i = 0, iend = played.length; i < iend; ++i) {\n\t\t\tconst title = played[i];\n\n\t\t\tif (seen.has(title)) {\n\t\t\t\tif (seen.get(title)) {\n\t\t\t\t\t++count;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst tags = Story.get(title).tags;\n\n\t\t\t\tif (tags.length > 0) {\n\t\t\t\t\tlet found = 0;\n\n\t\t\t\t\tfor (let j = 0; j < nLength; ++j) {\n\t\t\t\t\t\tif (tags.includes(needles[j])) {\n\t\t\t\t\t\t\t++found;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (found === nLength) {\n\t\t\t\t\t\t++count;\n\t\t\t\t\t\tseen.set(title, true);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tseen.set(title, false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/* eslint-enable no-unused-vars */\n\n\n\t/*******************************************************************************************************************\n\t\tImport Functions.\n\t*******************************************************************************************************************/\n\tvar { // eslint-disable-line no-var\n\t\t/* eslint-disable no-unused-vars */\n\t\timportScripts,\n\t\timportStyles\n\t\t/* eslint-enable no-unused-vars */\n\t} = (() => {\n\t\t// Slugify the given URL.\n\t\tfunction slugifyUrl(url) {\n\t\t\treturn Util.parseUrl(url).path\n\t\t\t\t.replace(/^[^\\w]+|[^\\w]+$/g, '')\n\t\t\t\t.replace(/[^\\w]+/g, '-')\n\t\t\t\t.toLocaleLowerCase();\n\t\t}\n\n\t\t// Add a <script> element which will load the script from the given URL.\n\t\tfunction addScript(url) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t/*\n\t\t\t\t\tWARNING: The ordering of the code within this function is important,\n\t\t\t\t\tas some browsers don't play well with different arrangements, so\n\t\t\t\t\tbe careful when mucking around with it.\n\n\t\t\t\t\tThe best supported ordering seems be: events → DOM append → attributes.\n\t\t\t\t*/\n\t\t\t\tjQuery(document.createElement('script'))\n\t\t\t\t\t.one('load abort error', ev => {\n\t\t\t\t\t\tjQuery(ev.target).off();\n\n\t\t\t\t\t\tif (ev.type === 'load') {\n\t\t\t\t\t\t\tresolve(ev.target);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treject(new Error(`importScripts failed to load the script \"${url}\".`));\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo(document.head)\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid   : `script-imported-${slugifyUrl(url)}`,\n\t\t\t\t\t\ttype : 'text/javascript',\n\t\t\t\t\t\tsrc  : url\n\t\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\t// Add a <link> element which will load the stylesheet from the given URL.\n\t\tfunction addStyle(url) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t/*\n\t\t\t\t\tWARNING: The ordering of the code within this function is important,\n\t\t\t\t\tas some browsers don't play well with different arrangements, so\n\t\t\t\t\tbe careful when mucking around with it.\n\n\t\t\t\t\tThe best supported ordering seems be: events → DOM append → attributes.\n\t\t\t\t*/\n\t\t\t\tjQuery(document.createElement('link'))\n\t\t\t\t\t.one('load abort error', ev => {\n\t\t\t\t\t\tjQuery(ev.target).off();\n\n\t\t\t\t\t\tif (ev.type === 'load') {\n\t\t\t\t\t\t\tresolve(ev.target);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treject(new Error(`importStyles failed to load the stylesheet \"${url}\".`));\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo(document.head)\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid   : `style-imported-${slugifyUrl(url)}`,\n\t\t\t\t\t\trel  : 'stylesheet',\n\t\t\t\t\t\thref : url\n\t\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\t// Turn a list of callbacks into a sequential chain of `Promise` objects.\n\t\tfunction sequence(callbacks) {\n\t\t\treturn callbacks.reduce((seq, fn) => seq = seq.then(fn), Promise.resolve()); // eslint-disable-line no-param-reassign\n\t\t}\n\n\t\t/*\n\t\t\tImport scripts from a URL.\n\t\t*/\n\t\tfunction importScripts(...urls) {\n\t\t\treturn Promise.all(urls.map(oneOrSeries => {\n\t\t\t\t// Array of URLs to be imported in sequence.\n\t\t\t\tif (Array.isArray(oneOrSeries)) {\n\t\t\t\t\treturn sequence(oneOrSeries.map(url => () => addScript(url)));\n\t\t\t\t}\n\n\t\t\t\t// Single URL to be imported.\n\t\t\t\treturn addScript(oneOrSeries);\n\t\t\t}));\n\t\t}\n\n\t\t/*\n\t\t\tImport stylesheets from a URL.\n\t\t*/\n\t\tfunction importStyles(...urls) {\n\t\t\treturn Promise.all(urls.map(oneOrSeries => {\n\t\t\t\t// Array of URLs to be imported in sequence.\n\t\t\t\tif (Array.isArray(oneOrSeries)) {\n\t\t\t\t\treturn sequence(oneOrSeries.map(url => () => addStyle(url)));\n\t\t\t\t}\n\n\t\t\t\t// Single URL to be imported.\n\t\t\t\treturn addStyle(oneOrSeries);\n\t\t\t}));\n\t\t}\n\n\t\t// Exports.\n\t\treturn {\n\t\t\timportScripts,\n\t\t\timportStyles\n\t\t};\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tParsing Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the given string after converting all TwineScript syntactical sugars to\n\t\ttheir native JavaScript counterparts.\n\t*/\n\tconst parse = (() => {\n\t\tconst parseMap = Object.freeze({\n\t\t\t/* eslint-disable quote-props */\n\t\t\t// Story $variable sigil-prefix.\n\t\t\t'$'     : 'State.variables.',\n\t\t\t// Temporary _variable sigil-prefix.\n\t\t\t'_'     : 'State.temporary.',\n\t\t\t// Assignment operators.\n\t\t\t'to'    : '=',\n\t\t\t// Equality operators.\n\t\t\t'eq'    : '==',\n\t\t\t'neq'   : '!=',\n\t\t\t'is'    : '===',\n\t\t\t'isnot' : '!==',\n\t\t\t// Relational operators.\n\t\t\t'gt'    : '>',\n\t\t\t'gte'   : '>=',\n\t\t\t'lt'    : '<',\n\t\t\t'lte'   : '<=',\n\t\t\t// Logical operators.\n\t\t\t'and'   : '&&',\n\t\t\t'or'    : '||',\n\t\t\t// Unary operators.\n\t\t\t'not'   : '!',\n\t\t\t'def'   : '\"undefined\" !== typeof',\n\t\t\t'ndef'  : '\"undefined\" === typeof'\n\t\t\t/* eslint-enable quote-props */\n\t\t});\n\t\tconst parseRe = new RegExp([\n\t\t\t'(\"\"|\\'\\')',                                          // 1=Empty quotes\n\t\t\t'(\"(?:\\\\\\\\.|[^\"\\\\\\\\])+\")',                            // 2=Double quoted, non-empty\n\t\t\t\"('(?:\\\\\\\\.|[^'\\\\\\\\])+')\",                            // 3=Single quoted, non-empty\n\t\t\t'([=+\\\\-*\\\\/%<>&\\\\|\\\\^~!?:,;\\\\(\\\\)\\\\[\\\\]{}]+)',       // 4=Operator delimiters\n\t\t\t'([^\"\\'=+\\\\-*\\\\/%<>&\\\\|\\\\^~!?:,;\\\\(\\\\)\\\\[\\\\]{}\\\\s]+)' // 5=Barewords\n\t\t].join('|'), 'g');\n\t\tconst varTest = new RegExp(`^${Patterns.variable}`);\n\n\t\tfunction parse(rawCodeString) {\n\t\t\tif (parseRe.lastIndex !== 0) {\n\t\t\t\tthrow new RangeError('Scripting.parse last index is non-zero at start');\n\t\t\t}\n\n\t\t\tlet code  = rawCodeString;\n\t\t\tlet match;\n\n\t\t\twhile ((match = parseRe.exec(code)) !== null) {\n\t\t\t\t// no-op: Empty quotes | Double quoted | Single quoted | Operator delimiters\n\n\t\t\t\t/*\n\t\t\t\t\tBarewords.\n\t\t\t\t*/\n\t\t\t\tif (match[5]) {\n\t\t\t\t\tlet token = match[5];\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is simply a dollar-sign or underscore, then it's either\n\t\t\t\t\t\tjust the raw character or, probably, a function alias, so skip it.\n\t\t\t\t\t*/\n\t\t\t\t\tif (token === '$' || token === '_') {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is a story $variable or temporary _variable, reset it\n\t\t\t\t\t\tto just its sigil—for later mapping.\n\t\t\t\t\t*/\n\t\t\t\t\telse if (varTest.test(token)) {\n\t\t\t\t\t\ttoken = token[0];\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is `is`, check to see if it's followed by `not`, if so,\n\t\t\t\t\t\tconvert them into the `isnot` operator.\n\n\t\t\t\t\t\tNOTE: This is a safety feature, since `$a is not $b` probably sounds\n\t\t\t\t\t\treasonable to most users.\n\t\t\t\t\t*/\n\t\t\t\t\telse if (token === 'is') {\n\t\t\t\t\t\tconst start = parseRe.lastIndex;\n\t\t\t\t\t\tconst part  = code.slice(start);\n\n\t\t\t\t\t\tif (/^\\s+not\\b/.test(part)) {\n\t\t\t\t\t\t\tcode = code.splice(start, part.search(/\\S/));\n\t\t\t\t\t\t\ttoken = 'isnot';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the finalized token has a mapping, replace it within the code string\n\t\t\t\t\t\twith its counterpart.\n\n\t\t\t\t\t\tNOTE: We must use `parseMap.hasOwnProperty(token)` here, rather than\n\t\t\t\t\t\tsimply using something like `parseMap[token]`, otherwise tokens which\n\t\t\t\t\t\tmatch properties from the prototype chain will cause shenanigans.\n\t\t\t\t\t*/\n\t\t\t\t\tif (parseMap.hasOwnProperty(token)) {\n\t\t\t\t\t\tcode = code.splice(\n\t\t\t\t\t\t\tmatch.index,    // starting index\n\t\t\t\t\t\t\ttoken.length,   // replace how many\n\t\t\t\t\t\t\tparseMap[token] // replacement string\n\t\t\t\t\t\t);\n\t\t\t\t\t\tparseRe.lastIndex += parseMap[token].length - token.length;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn code;\n\t\t}\n\n\t\treturn parse;\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tEval Functions.\n\t*******************************************************************************************************************/\n\t/* eslint-disable no-eval, no-extra-parens, no-unused-vars */\n\t/*\n\t\tEvaluates the given JavaScript code and returns the result, throwing if there were errors.\n\t*/\n\tfunction evalJavaScript(code, output) {\n\t\treturn (function (code, output) {\n\t\t\treturn eval(code);\n\t\t}).call(output ? { output } : null, String(code), output);\n\t}\n\n\t/*\n\t\tEvaluates the given TwineScript code and returns the result, throwing if there were errors.\n\t*/\n\tfunction evalTwineScript(code, output) {\n\t\treturn (function (code, output) {\n\t\t\treturn eval(code);\n\t\t}).call(output ? { output } : null, parse(String(code)), output);\n\t}\n\t/* eslint-enable no-eval, no-extra-parens, no-unused-vars */\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tparse           : { value : parse },\n\t\tevalJavaScript  : { value : evalJavaScript },\n\t\tevalTwineScript : { value : evalTwineScript }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/lexer.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar { // eslint-disable-line no-var\n\t/* eslint-disable no-unused-vars */\n\tEOF,\n\tLexer\n\t/* eslint-enable no-unused-vars */\n} = (() => {\n\t'use strict';\n\n\t// End of file (string, actually).\n\tconst EOF = -1;\n\n\n\t/*******************************************************************************************************************\n\t\tLexer Class.\n\t*******************************************************************************************************************/\n\tclass Lexer {\n\t\tconstructor(source, initialState) {\n\t\t\tif (arguments.length < 2) {\n\t\t\t\tthrow new Error('Lexer constructor called with too few parameters (source:string , initialState:function)');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tthis.source  → the string to be scanned\n\t\t\t\tthis.initial → initial state\n\t\t\t\tthis.state   → current state\n\t\t\t\tthis.start   → start position of an item\n\t\t\t\tthis.pos     → current position in the source string\n\t\t\t\tthis.depth   → current brace/bracket/parenthesis nesting depth\n\t\t\t\tthis.items   → scanned item queue\n\t\t\t\tthis.data    → lexing data\n\t\t\t*/\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : source\n\t\t\t\t},\n\n\t\t\t\tinitial : {\n\t\t\t\t\tvalue : initialState\n\t\t\t\t},\n\n\t\t\t\tstate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : initialState\n\t\t\t\t},\n\n\t\t\t\tstart : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\tpos : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\tdepth : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\titems : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : []\n\t\t\t\t},\n\n\t\t\t\tdata : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : {}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treset() {\n\t\t\tthis.state  = this.initial;\n\t\t\tthis.start  = 0;\n\t\t\tthis.pos    = 0;\n\t\t\tthis.depth  = 0;\n\t\t\tthis.items  = [];\n\t\t\tthis.data   = {};\n\t\t}\n\n\t\trun() {\n\t\t\t// scan the source string until no states remain\n\t\t\twhile (this.state !== null) {\n\t\t\t\tthis.state = this.state(this);\n\t\t\t}\n\n\t\t\t// return the array of items\n\t\t\treturn this.items;\n\t\t}\n\n\t\tnextItem() {\n\t\t\t// scan the source string until we have an item or no states remain\n\t\t\twhile (this.items.length === 0 && this.state !== null) {\n\t\t\t\tthis.state = this.state(this);\n\t\t\t}\n\n\t\t\t// return the current item\n\t\t\treturn this.items.shift();\n\t\t}\n\n\t\tnext() {\n\t\t\tif (this.pos >= this.source.length) {\n\t\t\t\treturn EOF;\n\t\t\t}\n\n\t\t\treturn this.source[this.pos++];\n\t\t}\n\n\t\tpeek() {\n\t\t\tif (this.pos >= this.source.length) {\n\t\t\t\treturn EOF;\n\t\t\t}\n\n\t\t\treturn this.source[this.pos];\n\t\t}\n\n\t\tbackup(num) {\n\t\t\t// if (num) {\n\t\t\t// \tthis.pos -= num;\n\t\t\t// }\n\t\t\t// else {\n\t\t\t// \t--this.pos;\n\t\t\t// }\n\t\t\tthis.pos -= num || 1;\n\t\t}\n\n\t\tforward(num) {\n\t\t\t// if (num) {\n\t\t\t// \tthis.pos += num;\n\t\t\t// }\n\t\t\t// else {\n\t\t\t// \t++this.pos;\n\t\t\t// }\n\t\t\tthis.pos += num || 1;\n\t\t}\n\n\t\tignore() {\n\t\t\tthis.start = this.pos;\n\t\t}\n\n\t\taccept(valid) {\n\t\t\tconst ch = this.next();\n\n\t\t\tif (ch === EOF) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (valid.includes(ch)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t\treturn false;\n\t\t}\n\n\t\tacceptRe(validRe) {\n\t\t\tconst ch = this.next();\n\n\t\t\tif (ch === EOF) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (validRe.test(ch)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t\treturn false;\n\t\t}\n\n\t\tacceptRun(valid) {\n\t\t\tfor (;;) {\n\t\t\t\tconst ch = this.next();\n\n\t\t\t\tif (ch === EOF) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!valid.includes(ch)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t}\n\n\t\tacceptRunRe(validRe) {\n\t\t\tfor (;;) {\n\t\t\t\tconst ch = this.next();\n\n\t\t\t\tif (ch === EOF) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!validRe.test(ch)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t}\n\n\t\temit(type) {\n\t\t\tthis.items.push({\n\t\t\t\ttype,\n\t\t\t\ttext  : this.source.slice(this.start, this.pos),\n\t\t\t\tstart : this.start,\n\t\t\t\tpos   : this.pos\n\t\t\t});\n\t\t\tthis.start = this.pos;\n\t\t}\n\n\t\terror(type, message) {\n\t\t\tif (arguments.length < 2) {\n\t\t\t\tthrow new Error('Lexer.prototype.error called with too few parameters (type:number , message:string)');\n\t\t\t}\n\n\t\t\tthis.items.push({\n\t\t\t\ttype,\n\t\t\t\tmessage,\n\t\t\t\ttext  : this.source.slice(this.start, this.pos),\n\t\t\t\tstart : this.start,\n\t\t\t\tpos   : this.pos\n\t\t\t});\n\t\t\treturn null;\n\t\t}\n\n\t\tstatic enumFromNames(names) {\n\t\t\tconst obj = names.reduce((obj, name, i) => {\n\t\t\t\tobj[name] = i; // eslint-disable-line no-param-reassign\n\t\t\t\treturn obj;\n\t\t\t}, {});\n\t\t\treturn Object.freeze(Object.assign(Object.create(null), obj));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn {\n\t\tEOF,\n\t\tLexer\n\t};\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/wikifier.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, EOF, Engine, Lexer, Patterns, Scripting, State, Story, TempState, Util, convertBreaks,\n\t       errorPrologRegExp\n*/\n\n/*\n\tTODO: The Wikifier, and associated code, could stand to receive a serious refactoring.\n*/\n/* eslint-disable max-len */\nvar Wikifier = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Wikifier call depth.\n\tlet _callDepth = 0;\n\n\n\t/*******************************************************************************************************************\n\t\tWikifier Class.\n\t*******************************************************************************************************************/\n\tclass Wikifier {\n\t\tconstructor(destination, source, options) {\n\t\t\tif (Wikifier.Parser.Profile.isEmpty()) {\n\t\t\t\tWikifier.Parser.Profile.compile();\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// General Wikifier properties.\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : String(source)\n\t\t\t\t},\n\n\t\t\t\toptions : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : Object.assign({\n\t\t\t\t\t\tprofile : 'all'\n\t\t\t\t\t}, options)\n\t\t\t\t},\n\n\t\t\t\tnextMatch : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\toutput : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t// Macro parser ('macro') related properties.\n\t\t\t\t_rawArgs : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : ''\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// No destination specified.  Create a fragment to act as the output buffer.\n\t\t\tif (destination == null) { // lazy equality for null\n\t\t\t\tthis.output = document.createDocumentFragment();\n\t\t\t}\n\n\t\t\t// jQuery-wrapped destination.  Grab the first element.\n\t\t\telse if (destination.jquery) { // cannot use `hasOwnProperty()` here as `jquery` is from jQuery's prototype\n\t\t\t\tthis.output = destination[0];\n\t\t\t}\n\n\t\t\t// Normal destination.\n\t\t\telse {\n\t\t\t\tthis.output = destination;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tWikify the source into the output buffer element, possibly converting line\n\t\t\t\tbreaks into paragraphs.\n\n\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\tto ensure that the call depth is properly restored in the event that an\n\t\t\t\tuncaught exception is thrown during the call to `subWikify()`.\n\t\t\t*/\n\t\t\ttry {\n\t\t\t\t++_callDepth;\n\n\t\t\t\tthis.subWikify(this.output);\n\n\t\t\t\t// Limit line break conversion to non-recursive calls.\n\t\t\t\tif (_callDepth === 1 && Config.cleanupWikifierOutput) {\n\t\t\t\t\tconvertBreaks(this.output);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\t--_callDepth;\n\t\t\t}\n\t\t}\n\n\t\tsubWikify(output, terminator, options) {\n\t\t\t// Cache and temporarily replace the current output buffer.\n\t\t\tconst oldOutput = this.output;\n\t\t\tthis.output = output;\n\n\t\t\tlet newOptions;\n\t\t\tlet oldOptions;\n\n\t\t\t// Parser option overrides.\n\t\t\tif (Wikifier.Option.length > 0) {\n\t\t\t\tnewOptions = Object.assign(newOptions || {}, Wikifier.Option.options);\n\t\t\t}\n\t\t\t// Local parameter option overrides.\n\t\t\tif (options !== null && typeof options === 'object') {\n\t\t\t\tnewOptions = Object.assign(newOptions || {}, options);\n\t\t\t}\n\t\t\t// If new options exist, cache and temporarily replace the current options.\n\t\t\tif (newOptions) {\n\t\t\t\toldOptions = this.options;\n\t\t\t\tthis.options = Object.assign({}, this.options, newOptions);\n\t\t\t}\n\n\t\t\tconst parsersProfile   = Wikifier.Parser.Profile.get(this.options.profile);\n\t\t\tconst terminatorRegExp = terminator\n\t\t\t\t? new RegExp(`(?:${terminator})`, this.options.ignoreTerminatorCase ? 'gim' : 'gm')\n\t\t\t\t: null;\n\t\t\tlet terminatorMatch;\n\t\t\tlet parserMatch;\n\n\t\t\tdo {\n\t\t\t\t// Prepare the RegExp match positions.\n\t\t\t\tparsersProfile.parserRegExp.lastIndex = this.nextMatch;\n\n\t\t\t\tif (terminatorRegExp) {\n\t\t\t\t\tterminatorRegExp.lastIndex = this.nextMatch;\n\t\t\t\t}\n\n\t\t\t\t// Get the first matches.\n\t\t\t\tparserMatch     = parsersProfile.parserRegExp.exec(this.source);\n\t\t\t\tterminatorMatch = terminatorRegExp ? terminatorRegExp.exec(this.source) : null;\n\n\t\t\t\t// Try for a terminator match, unless there's a closer parser match.\n\t\t\t\tif (terminatorMatch && (!parserMatch || terminatorMatch.index <= parserMatch.index)) {\n\t\t\t\t\t// Output any text before the match.\n\t\t\t\t\tif (terminatorMatch.index > this.nextMatch) {\n\t\t\t\t\t\tthis.outputText(this.output, this.nextMatch, terminatorMatch.index);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set the match parameters.\n\t\t\t\t\tthis.matchStart  = terminatorMatch.index;\n\t\t\t\t\tthis.matchLength = terminatorMatch[0].length;\n\t\t\t\t\tthis.matchText   = terminatorMatch[0];\n\t\t\t\t\tthis.nextMatch   = terminatorRegExp.lastIndex;\n\n\t\t\t\t\t// Restore the original output buffer and options.\n\t\t\t\t\tthis.output = oldOutput;\n\n\t\t\t\t\tif (oldOptions) {\n\t\t\t\t\t\tthis.options = oldOptions;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Exit.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Try for a parser match.\n\t\t\t\telse if (parserMatch) {\n\t\t\t\t\t// Output any text before the match.\n\t\t\t\t\tif (parserMatch.index > this.nextMatch) {\n\t\t\t\t\t\tthis.outputText(this.output, this.nextMatch, parserMatch.index);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set the match parameters.\n\t\t\t\t\tthis.matchStart  = parserMatch.index;\n\t\t\t\t\tthis.matchLength = parserMatch[0].length;\n\t\t\t\t\tthis.matchText   = parserMatch[0];\n\t\t\t\t\tthis.nextMatch   = parsersProfile.parserRegExp.lastIndex;\n\n\t\t\t\t\t// Figure out which parser matched.\n\t\t\t\t\tlet matchingParser;\n\n\t\t\t\t\tfor (let i = 1, iend = parserMatch.length; i < iend; ++i) {\n\t\t\t\t\t\tif (parserMatch[i]) {\n\t\t\t\t\t\t\tmatchingParser = i - 1;\n\t\t\t\t\t\t\tbreak; // stop once we've found the matching parser\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Call the parser.\n\t\t\t\t\tparsersProfile.parsers[matchingParser].handler(this);\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} while (terminatorMatch || parserMatch);\n\n\t\t\t// Output any text after the last match.\n\t\t\tif (TempState.break == null) { // lazy equality for null\n\t\t\t\tif (this.nextMatch < this.source.length) {\n\t\t\t\t\tthis.outputText(this.output, this.nextMatch, this.source.length);\n\t\t\t\t\tthis.nextMatch = this.source.length;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// In case of <<break>>/<<continue>>, remove the last <br>.\n\t\t\telse if (\n\t\t\t\t   this.output.lastChild\n\t\t\t\t&& this.output.lastChild.nodeType === Node.ELEMENT_NODE\n\t\t\t\t&& this.output.lastChild.nodeName.toUpperCase() === 'BR'\n\t\t\t) {\n\t\t\t\tjQuery(this.output.lastChild).remove();\n\t\t\t}\n\n\t\t\t// Restore the original output buffer and options.\n\t\t\tthis.output = oldOutput;\n\n\t\t\tif (oldOptions) {\n\t\t\t\tthis.options = oldOptions;\n\t\t\t}\n\t\t}\n\n\t\toutputText(destination, startPos, endPos) {\n\t\t\tdestination.appendChild(document.createTextNode(this.source.substring(startPos, endPos)));\n\t\t}\n\n\t\t/*\n\t\t\t[DEPRECATED] Meant to be called by legacy macros, this returns the raw, unprocessed\n\t\t\ttext given to the currently executing macro.\n\t\t*/\n\t\trawArgs() {\n\t\t\treturn this._rawArgs;\n\t\t}\n\n\t\t/*\n\t\t\t[DEPRECATED] Meant to be called by legacy macros, this returns the text given to\n\t\t\tthe currently executing macro after doing TwineScript-to-JavaScript transformations.\n\t\t*/\n\t\tfullArgs() {\n\t\t\treturn Scripting.parse(this._rawArgs);\n\t\t}\n\n\t\t/*\n\t\t\tReturns the output generated by wikifying the given text, throwing if there were errors.\n\t\t*/\n\t\tstatic wikifyEval(text) {\n\t\t\tconst output = document.createDocumentFragment();\n\n\t\t\tnew Wikifier(output, text);\n\n\t\t\tconst errors = output.querySelector('.error');\n\n\t\t\tif (errors !== null) {\n\t\t\t\tthrow new Error(errors.textContent.replace(errorPrologRegExp, ''));\n\t\t\t}\n\n\t\t\treturn output;\n\t\t}\n\n\t\t/*\n\t\t\tCreate and return an internal link.\n\t\t*/\n\t\tstatic createInternalLink(destination, passage, text, callback) {\n\t\t\tconst $link = jQuery(document.createElement('a'));\n\n\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t$link.attr('data-passage', passage);\n\n\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t$link.addClass('link-internal');\n\n\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t$link.addClass('link-visited');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$link.addClass('link-broken');\n\t\t\t\t}\n\n\t\t\t\t$link.ariaClick({ one : true }, () => {\n\t\t\t\t\tif (typeof callback === 'function') {\n\t\t\t\t\t\tcallback();\n\t\t\t\t\t}\n\n\t\t\t\t\tEngine.play(passage);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (text) {\n\t\t\t\t$link.append(document.createTextNode(text));\n\t\t\t}\n\n\t\t\tif (destination) {\n\t\t\t\t$link.appendTo(destination);\n\t\t\t}\n\n\t\t\t// For legacy-compatibility we must return the DOM node.\n\t\t\treturn $link[0];\n\t\t}\n\n\t\t/*\n\t\t\tCreate and return an external link.\n\t\t*/\n\t\tstatic createExternalLink(destination, url, text) {\n\t\t\tconst $link = jQuery(document.createElement('a'))\n\t\t\t\t.attr('target', '_blank')\n\t\t\t\t.addClass('link-external')\n\t\t\t\t.text(text)\n\t\t\t\t.appendTo(destination);\n\n\t\t\tif (url != null) { // lazy equality for null\n\t\t\t\t$link.attr({\n\t\t\t\t\thref     : url,\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// For legacy-compatibility we must return the DOM node.\n\t\t\treturn $link[0];\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the given link source is external (probably).\n\t\t*/\n\t\tstatic isExternalLink(link) {\n\t\t\tif (Story.has(link)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst urlRegExp = new RegExp(`^${Patterns.url}`, 'gim');\n\t\t\treturn urlRegExp.test(link) || /[/.?#]/.test(link);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tOption Static Object.\n\t*******************************************************************************************************************/\n\tObject.defineProperty(Wikifier, 'Option', {\n\t\tvalue : (() => {\n\t\t\t// Options array (stack).\n\t\t\tlet _optionsStack = [];\n\n\n\t\t\t/*\n\t\t\t\tGlobalOption Functions.\n\t\t\t*/\n\t\t\tfunction optionLength() {\n\t\t\t\treturn _optionsStack.length;\n\t\t\t}\n\n\t\t\tfunction optionGetter() {\n\t\t\t\treturn Object.assign({}, ..._optionsStack);\n\t\t\t}\n\n\t\t\tfunction optionClear() {\n\t\t\t\t_optionsStack = [];\n\t\t\t}\n\n\t\t\tfunction optionGet(idx) {\n\t\t\t\treturn _optionsStack[idx];\n\t\t\t}\n\n\t\t\tfunction optionPop() {\n\t\t\t\treturn _optionsStack.pop();\n\t\t\t}\n\n\t\t\tfunction optionPush(options) {\n\t\t\t\tif (typeof options !== 'object' || options === null) {\n\t\t\t\t\tthrow new TypeError(`Wikifier.Option.push options parameter must be an object (received: ${Util.getType(options)})`);\n\t\t\t\t}\n\n\t\t\t\treturn _optionsStack.push(options);\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tExports.\n\t\t\t*/\n\t\t\treturn Object.freeze(Object.defineProperties({}, {\n\t\t\t\tlength  : { get : optionLength },\n\t\t\t\toptions : { get : optionGetter },\n\t\t\t\tclear   : { value : optionClear },\n\t\t\t\tget     : { value : optionGet },\n\t\t\t\tpop     : { value : optionPop },\n\t\t\t\tpush    : { value : optionPush }\n\t\t\t}));\n\t\t})()\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tParser Static Object.\n\t*******************************************************************************************************************/\n\tObject.defineProperty(Wikifier, 'Parser', {\n\t\tvalue : (() => {\n\t\t\t// Parser definition array.  Ordering matters, so this must be an ordered list.\n\t\t\tconst _parsers = [];\n\n\t\t\t// Parser profiles object.\n\t\t\tlet _profiles;\n\n\n\t\t\t/*\n\t\t\t\tParser Functions.\n\t\t\t*/\n\t\t\tfunction parsersGetter() {\n\t\t\t\treturn _parsers;\n\t\t\t}\n\n\t\t\tfunction parsersAdd(parser) {\n\t\t\t\t// Parser object sanity checks.\n\t\t\t\tif (typeof parser !== 'object') {\n\t\t\t\t\tthrow new Error('Wikifier.Parser.add parser parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('name')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"name\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.name !== 'string') {\n\t\t\t\t\tthrow new Error('parser object \"name\" property must be a string');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('match')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"match\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.match !== 'string') {\n\t\t\t\t\tthrow new Error('parser object \"match\" property must be a string');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('handler')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"handler\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.handler !== 'function') {\n\t\t\t\t\tthrow new Error('parser object \"handler\" property must be a function');\n\t\t\t\t}\n\n\t\t\t\tif (parser.hasOwnProperty('profiles') && !Array.isArray(parser.profiles)) {\n\t\t\t\t\tthrow new Error('parser object \"profiles\" property must be an array');\n\t\t\t\t}\n\n\t\t\t\t// Check for an existing parser with the same name.\n\t\t\t\tif (parsersHas(parser.name)) {\n\t\t\t\t\tthrow new Error(`cannot clobber existing parser \"${parser.name}\"`);\n\t\t\t\t}\n\n\t\t\t\t// Add the parser to the end of the array.\n\t\t\t\t_parsers.push(parser);\n\t\t\t}\n\n\t\t\tfunction parsersDelete(name) {\n\t\t\t\tconst parser = _parsers.find(parser => parser.name === name);\n\n\t\t\t\tif (parser) {\n\t\t\t\t\t_parsers.delete(parser);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction parsersIsEmpty() {\n\t\t\t\treturn _parsers.length === 0;\n\t\t\t}\n\n\t\t\tfunction parsersHas(name) {\n\t\t\t\treturn !!_parsers.find(parser => parser.name === name);\n\t\t\t}\n\n\t\t\tfunction parsersGet(name) {\n\t\t\t\treturn _parsers.find(parser => parser.name === name) || null;\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tParser Profile Functions.\n\t\t\t*/\n\t\t\tfunction profilesGetter() {\n\t\t\t\treturn _profiles;\n\t\t\t}\n\n\t\t\tfunction profilesCompile() {\n\t\t\t\tif (DEBUG) { console.log('[Wikifier.Parser/profilesCompile()]'); }\n\n\t\t\t\tconst all  = _parsers;\n\t\t\t\tconst core = all.filter(parser => !Array.isArray(parser.profiles) || parser.profiles.includes('core'));\n\n\t\t\t\t_profiles = Object.freeze({\n\t\t\t\t\tall : {\n\t\t\t\t\t\tparsers      : all,\n\t\t\t\t\t\tparserRegExp : new RegExp(all.map(parser => `(${parser.match})`).join('|'), 'gm')\n\t\t\t\t\t},\n\t\t\t\t\tcore : {\n\t\t\t\t\t\tparsers      : core,\n\t\t\t\t\t\tparserRegExp : new RegExp(core.map(parser => `(${parser.match})`).join('|'), 'gm')\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\treturn _profiles;\n\t\t\t}\n\n\t\t\tfunction profilesIsEmpty() {\n\t\t\t\treturn typeof _profiles !== 'object' || Object.keys(_profiles).length === 0;\n\t\t\t}\n\n\t\t\tfunction profilesGet(profile) {\n\t\t\t\tif (typeof _profiles !== 'object' || !_profiles.hasOwnProperty(profile)) {\n\t\t\t\t\tthrow new Error(`nonexistent parser profile \"${profile}\"`);\n\t\t\t\t}\n\n\t\t\t\treturn _profiles[profile];\n\t\t\t}\n\n\t\t\tfunction profilesHas(profile) {\n\t\t\t\treturn typeof _profiles === 'object' && _profiles.hasOwnProperty(profile);\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tExports.\n\t\t\t*/\n\t\t\treturn Object.freeze(Object.defineProperties({}, {\n\t\t\t\t/*\n\t\t\t\t\tParser Containers.\n\t\t\t\t*/\n\t\t\t\tparsers : { get : parsersGetter },\n\n\t\t\t\t/*\n\t\t\t\t\tParser Functions.\n\t\t\t\t*/\n\t\t\t\tadd     : { value : parsersAdd },\n\t\t\t\tdelete  : { value : parsersDelete },\n\t\t\t\tisEmpty : { value : parsersIsEmpty },\n\t\t\t\thas     : { value : parsersHas },\n\t\t\t\tget     : { value : parsersGet },\n\n\t\t\t\t/*\n\t\t\t\t\tParser Profile.\n\t\t\t\t*/\n\t\t\t\tProfile : {\n\t\t\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tProfiles Containers.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tprofiles : { get : profilesGetter },\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tProfiles Functions.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tcompile : { value : profilesCompile },\n\t\t\t\t\t\tisEmpty : { value : profilesIsEmpty },\n\t\t\t\t\t\thas     : { value : profilesHas },\n\t\t\t\t\t\tget     : { value : profilesGet }\n\t\t\t\t\t}))\n\t\t\t\t}\n\t\t\t}));\n\t\t})()\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAdditional Static Properties.\n\t*******************************************************************************************************************/\n\tObject.defineProperties(Wikifier, {\n\t\thelpers : { value : {} },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tgetValue       : { value : State.getVar },              // SEE: `state.js`.\n\t\tsetValue       : { value : State.setVar },              // SEE: `state.js`.\n\t\tparse          : { value : Scripting.parse },           // SEE: `markup/scripting.js`.\n\t\tevalExpression : { value : Scripting.evalTwineScript }, // SEE: `markup/scripting.js`.\n\t\tevalStatements : { value : Scripting.evalTwineScript }, // SEE: `markup/scripting.js`.\n\t\ttextPrimitives : { value : Patterns }                   // SEE: `lib/patterns.js`.\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tHelper Static Methods.\n\t*******************************************************************************************************************/\n\tObject.defineProperties(Wikifier.helpers, {\n\t\tinlineCss : {\n\t\t\tvalue : (() => {\n\t\t\t\tconst lookaheadRe = new RegExp(Patterns.inlineCss, 'gm');\n\t\t\t\tconst idOrClassRe = new RegExp(`(${Patterns.cssIdOrClassSigil})(${Patterns.anyLetter}+)`, 'g');\n\n\t\t\t\tfunction helperInlineCss(w) {\n\t\t\t\t\tconst css = { classes : [], id : '', styles : {} };\n\t\t\t\t\tlet matched;\n\n\t\t\t\t\tdo {\n\t\t\t\t\t\tlookaheadRe.lastIndex = w.nextMatch;\n\n\t\t\t\t\t\tconst match = lookaheadRe.exec(w.source);\n\n\t\t\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\t\t\tif (matched) {\n\t\t\t\t\t\t\tif (match[1]) {\n\t\t\t\t\t\t\t\tcss.styles[Util.fromCssProperty(match[1])] = match[2].trim();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (match[3]) {\n\t\t\t\t\t\t\t\tcss.styles[Util.fromCssProperty(match[3])] = match[4].trim();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (match[5]) {\n\t\t\t\t\t\t\t\tlet subMatch;\n\n\t\t\t\t\t\t\t\tidOrClassRe.lastIndex = 0; // NOTE: Guard against buggy implementations.\n\n\t\t\t\t\t\t\t\twhile ((subMatch = idOrClassRe.exec(match[5])) !== null) {\n\t\t\t\t\t\t\t\t\tif (subMatch[1] === '.') {\n\t\t\t\t\t\t\t\t\t\tcss.classes.push(subMatch[2]);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tcss.id = subMatch[2];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tw.nextMatch = lookaheadRe.lastIndex; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\t\t\t\t\t} while (matched);\n\n\t\t\t\t\treturn css;\n\t\t\t\t}\n\n\t\t\t\treturn helperInlineCss;\n\t\t\t})()\n\t\t},\n\n\t\tevalText : {\n\t\t\tvalue(text) {\n\t\t\t\tlet result;\n\n\t\t\t\ttry {\n\t\t\t\t\tresult = Scripting.evalTwineScript(text);\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAttempt to prevent the leakage of auto-globals by enforcing that\n\t\t\t\t\t\tthe resultant value be either a string or a number.\n\n\t\t\t\t\t\tNOTE: This is not a foolproof solution to the problem of auto-global\n\t\t\t\t\t\tleakage.  Various auto-globals, which return strings or numbers, can\n\t\t\t\t\t\tstill leak through—e.g. `window.status` → string.\n\t\t\t\t\t*/\n\t\t\t\t\tswitch (typeof result) {\n\t\t\t\t\tcase 'string':\n\t\t\t\t\t\tif (result.trim() === '') {\n\t\t\t\t\t\t\tresult = text;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'number':\n\t\t\t\t\t\tresult = String(result);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tresult = text;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\tresult = text;\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}\n\t\t},\n\n\t\tevalPassageId : {\n\t\t\tvalue(passage) {\n\t\t\t\tif (passage == null || Story.has(passage)) { // lazy equality for null; `0` is a valid name, so we cannot simply evaluate `passage`\n\t\t\t\t\treturn passage;\n\t\t\t\t}\n\n\t\t\t\treturn Wikifier.helpers.evalText(passage);\n\t\t\t}\n\t\t},\n\n\t\thasBlockContext : {\n\t\t\tvalue(nodes) {\n\t\t\t\tconst hasGCS = typeof window.getComputedStyle === 'function';\n\n\t\t\t\tfor (let i = nodes.length - 1; i >= 0; --i) {\n\t\t\t\t\tconst node = nodes[i];\n\n\t\t\t\t\tswitch (node.nodeType) {\n\t\t\t\t\tcase Node.ELEMENT_NODE:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst tagName = node.nodeName.toUpperCase();\n\n\t\t\t\t\t\t\tif (tagName === 'BR') {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst styles = hasGCS ? window.getComputedStyle(node, null) : node.currentStyle;\n\n\t\t\t\t\t\t\tif (styles && styles.display) {\n\t\t\t\t\t\t\t\tif (styles.display === 'none') {\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn styles.display === 'block';\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tWebKit/Blink-based browsers do not attach any computed style\n\t\t\t\t\t\t\t\tinformation to elements until they're inserted into the DOM\n\t\t\t\t\t\t\t\t(and probably visible), not even the default browser styles\n\t\t\t\t\t\t\t\tand any user styles.  So, we make an assumption based on the\n\t\t\t\t\t\t\t\telement.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tswitch (tagName) {\n\t\t\t\t\t\t\tcase 'ADDRESS':\n\t\t\t\t\t\t\tcase 'ARTICLE':\n\t\t\t\t\t\t\tcase 'ASIDE':\n\t\t\t\t\t\t\tcase 'BLOCKQUOTE':\n\t\t\t\t\t\t\tcase 'CENTER':\n\t\t\t\t\t\t\tcase 'DIV':\n\t\t\t\t\t\t\tcase 'DL':\n\t\t\t\t\t\t\tcase 'FIGURE':\n\t\t\t\t\t\t\tcase 'FOOTER':\n\t\t\t\t\t\t\tcase 'FORM':\n\t\t\t\t\t\t\tcase 'H1':\n\t\t\t\t\t\t\tcase 'H2':\n\t\t\t\t\t\t\tcase 'H3':\n\t\t\t\t\t\t\tcase 'H4':\n\t\t\t\t\t\t\tcase 'H5':\n\t\t\t\t\t\t\tcase 'H6':\n\t\t\t\t\t\t\tcase 'HEADER':\n\t\t\t\t\t\t\tcase 'HR':\n\t\t\t\t\t\t\tcase 'MAIN':\n\t\t\t\t\t\t\tcase 'NAV':\n\t\t\t\t\t\t\tcase 'OL':\n\t\t\t\t\t\t\tcase 'P':\n\t\t\t\t\t\t\tcase 'PRE':\n\t\t\t\t\t\t\tcase 'SECTION':\n\t\t\t\t\t\t\tcase 'TABLE':\n\t\t\t\t\t\t\tcase 'UL':\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn false;\n\n\t\t\t\t\tcase Node.COMMENT_NODE:\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t},\n\n\t\tcreateShadowSetterCallback : {\n\t\t\tvalue : (() => {\n\t\t\t\tlet macroParser = null;\n\n\t\t\t\tfunction cacheMacroParser() {\n\t\t\t\t\tif (!macroParser) {\n\t\t\t\t\t\tmacroParser = Wikifier.Parser.get('macro');\n\n\t\t\t\t\t\tif (!macroParser) {\n\t\t\t\t\t\t\tthrow new Error('cannot find \"macro\" parser');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn macroParser;\n\t\t\t\t}\n\n\t\t\t\tfunction getMacroContextShadowView() {\n\t\t\t\t\tconst macro = macroParser || cacheMacroParser();\n\t\t\t\t\tconst view  = new Set();\n\n\t\t\t\t\tfor (let context = macro.context; context !== null; context = context.parent) {\n\t\t\t\t\t\tif (context._shadows) {\n\t\t\t\t\t\t\tcontext._shadows.forEach(name => view.add(name));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn [...view];\n\t\t\t\t}\n\n\t\t\t\tfunction helperCreateShadowSetterCallback(code) {\n\t\t\t\t\tconst shadowStore = {};\n\n\t\t\t\t\tgetMacroContextShadowView().forEach(varName => {\n\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\t\t\t\t\t});\n\n\t\t\t\t\treturn function () {\n\t\t\t\t\t\tconst shadowNames = Object.keys(shadowStore);\n\t\t\t\t\t\tconst valueCache  = shadowNames.length > 0 ? {} : null;\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t\t\tevaluation.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tCache the existing values of the variables to be shadowed and assign the\n\t\t\t\t\t\t\t\tshadow values.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tstore[varKey] = shadowStore[varName];\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t// Evaluate the JavaScript.\n\t\t\t\t\t\t\treturn Scripting.evalJavaScript(code);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t// Revert the variable shadowing.\n\t\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tUpdate the shadow store with the variable's current value, in case it\n\t\t\t\t\t\t\t\t\twas modified during the callback.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\n\t\t\t\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn helperCreateShadowSetterCallback;\n\t\t\t})()\n\t\t},\n\n\t\tparseSquareBracketedMarkup : {\n\t\t\tvalue : (() => {\n\t\t\t\t/* eslint-disable no-param-reassign */\n\t\t\t\tconst Item = Lexer.enumFromNames([ // lex item types object (pseudo-enumeration)\n\t\t\t\t\t'Error',     // error\n\t\t\t\t\t'DelimLTR',  // '|' or '->'\n\t\t\t\t\t'DelimRTL',  // '<-'\n\t\t\t\t\t'InnerMeta', // ']['\n\t\t\t\t\t'ImageMeta', // '[img[', '[<img[', or '[>img['\n\t\t\t\t\t'LinkMeta',  // '[['\n\t\t\t\t\t'Link',      // link destination\n\t\t\t\t\t'RightMeta', // ']]'\n\t\t\t\t\t'Setter',    // setter expression\n\t\t\t\t\t'Source',    // image source\n\t\t\t\t\t'Text'       // link text or image alt text\n\t\t\t\t]);\n\t\t\t\tconst Delim = Lexer.enumFromNames([ // delimiter state object (pseudo-enumeration)\n\t\t\t\t\t'None', // no delimiter encountered\n\t\t\t\t\t'LTR',  // '|' or '->'\n\t\t\t\t\t'RTL'   // '<-'\n\t\t\t\t]);\n\n\t\t\t\t// Lexing functions.\n\t\t\t\tfunction slurpQuote(lexer, endQuote) {\n\t\t\t\t\tloop: for (;;) {\n\t\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/* falls through */\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn EOF;\n\n\t\t\t\t\t\tcase endQuote:\n\t\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t\t}\n\n\t\t\t\t\treturn lexer.pos;\n\t\t\t\t}\n\n\t\t\t\tfunction lexLeftMeta(lexer) {\n\t\t\t\t\tif (!lexer.accept('[')) {\n\t\t\t\t\t\treturn lexer.error(Item.Error, 'malformed square-bracketed markup');\n\t\t\t\t\t}\n\n\t\t\t\t\t// Is link markup.\n\t\t\t\t\tif (lexer.accept('[')) {\n\t\t\t\t\t\tlexer.data.isLink = true;\n\t\t\t\t\t\tlexer.emit(Item.LinkMeta);\n\t\t\t\t\t}\n\n\t\t\t\t\t// May be image markup.\n\t\t\t\t\telse {\n\t\t\t\t\t\tlexer.accept('<>'); // aligner syntax\n\n\t\t\t\t\t\tif (!lexer.accept('Ii') || !lexer.accept('Mm') || !lexer.accept('Gg') || !lexer.accept('[')) {\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, 'malformed square-bracketed markup');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlexer.data.isLink = false;\n\t\t\t\t\t\tlexer.emit(Item.ImageMeta);\n\t\t\t\t\t}\n\n\t\t\t\t\tlexer.depth = 2; // account for both initial left square brackets\n\t\t\t\t\treturn lexCoreComponents;\n\t\t\t\t}\n\n\t\t\t\tfunction lexCoreComponents(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\t\t\t\t\tlet delim = Delim.None;\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tThis is not entirely reliable within sections that allow raw strings, since\n\t\t\t\t\t\t\t\tit's possible, however unlikely, for a raw string to contain unpaired double\n\t\t\t\t\t\t\t\tquotes.  The likelihood is low enough, however, that I'm deeming the risk as\n\t\t\t\t\t\t\t\tacceptable—for now, at least.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '|': // possible pipe ('|') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None) {\n\t\t\t\t\t\t\t\tdelim = Delim.LTR;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\tlexer.forward();\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimLTR);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '-': // possible right arrow ('->') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None && lexer.peek() === '>') {\n\t\t\t\t\t\t\t\tdelim = Delim.LTR;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimLTR);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '<': // possible left arrow ('<-') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None && lexer.peek() === '-') {\n\t\t\t\t\t\t\t\tdelim = Delim.RTL;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimRTL);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tswitch (lexer.peek()) {\n\t\t\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\n\t\t\t\t\t\t\t\t\tif (delim === Delim.RTL) {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.InnerMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn lexer.data.isLink ? lexSetter : lexImageLink;\n\n\t\t\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\n\t\t\t\t\t\t\t\t\tif (delim === Delim.RTL) {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfunction lexImageLink(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tThis is not entirely reliable within sections that allow raw strings, since\n\t\t\t\t\t\t\t\tit's possible, however unlikely, for a raw string to contain unpaired double\n\t\t\t\t\t\t\t\tquotes.  The likelihood is low enough, however, that I'm deeming the risk as\n\t\t\t\t\t\t\t\tacceptable—for now, at least.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup link component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tswitch (lexer.peek()) {\n\t\t\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.Link);\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.InnerMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn lexSetter;\n\n\t\t\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.Link);\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfunction lexSetter(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup setter component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase \"'\":\n\t\t\t\t\t\t\tif (slurpQuote(lexer, \"'\") === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated single quoted string in ${what} markup setter component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tif (lexer.peek() !== ']') {\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Setter);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Parse function.\n\t\t\t\tfunction parseSquareBracketedMarkup(w) {\n\t\t\t\t\t// Initialize the lexer.\n\t\t\t\t\tconst lexer  = new Lexer(w.source, lexLeftMeta);\n\n\t\t\t\t\t// Set the initial positions within the source string.\n\t\t\t\t\tlexer.start = lexer.pos = w.matchStart;\n\n\t\t\t\t\t// Lex the raw argument string.\n\t\t\t\t\tconst markup = {};\n\t\t\t\t\tconst items  = lexer.run();\n\t\t\t\t\tconst last   = items.last();\n\n\t\t\t\t\tif (last && last.type === Item.Error) {\n\t\t\t\t\t\tmarkup.error = last.message;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\titems.forEach(item => {\n\t\t\t\t\t\t\tconst text = item.text.trim();\n\n\t\t\t\t\t\t\tswitch (item.type) {\n\t\t\t\t\t\t\tcase Item.ImageMeta:\n\t\t\t\t\t\t\t\tmarkup.isImage = true;\n\n\t\t\t\t\t\t\t\tif (text[1] === '<') {\n\t\t\t\t\t\t\t\t\tmarkup.align = 'left';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (text[1] === '>') {\n\t\t\t\t\t\t\t\t\tmarkup.align = 'right';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.LinkMeta:\n\t\t\t\t\t\t\t\tmarkup.isLink = true;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Link:\n\t\t\t\t\t\t\t\tif (text[0] === '~') {\n\t\t\t\t\t\t\t\t\tmarkup.forceInternal = true;\n\t\t\t\t\t\t\t\t\tmarkup.link = text.slice(1);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tmarkup.link = text;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Setter:\n\t\t\t\t\t\t\t\tmarkup.setter = text;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Source:\n\t\t\t\t\t\t\t\tmarkup.source = text;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Text:\n\t\t\t\t\t\t\t\tmarkup.text = text;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tmarkup.pos = lexer.pos;\n\t\t\t\t\treturn markup;\n\t\t\t\t}\n\n\t\t\t\treturn parseSquareBracketedMarkup;\n\t\t\t\t/* eslint-enable no-param-reassign */\n\t\t\t})()\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Wikifier;\n})();\n/* eslint-enable max-len */\n\n/***********************************************************************************************************************\n\n\tmarkup/parserlib.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, DebugView, EOF, Engine, Lexer, Macro, MacroContext, Patterns, Scripting, State, Story, Template,\n\t       Wikifier, toStringOrDefault, throwError\n*/\n/* eslint \"no-param-reassign\": [ 2, { \"props\" : false } ] */\n\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _verbatimTagHandler(w) {\n\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\tconst match = this.lookahead.exec(w.source);\n\n\t\tif (match && match.index === w.matchStart) {\n\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t.append(match[1])\n\t\t\t\t.appendTo(w.output);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tParsers.\n\t*******************************************************************************************************************/\n\tWikifier.Parser.add({\n\t\tname       : 'quoteByBlock',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^<<<\\\\n',\n\t\tterminator : '^<<<\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.subWikify(\n\t\t\t\tjQuery(document.createElement('blockquote'))\n\t\t\t\t\t.appendTo(w.output)\n\t\t\t\t\t.get(0),\n\t\t\t\tthis.terminator\n\t\t\t);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'quoteByLine',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^>+',\n\t\tlookahead  : /^>+/gm,\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst destStack = [w.output];\n\t\t\tlet curLevel = 0;\n\t\t\tlet newLevel = w.matchLength;\n\t\t\tlet matched;\n\t\t\tlet i;\n\n\t\t\tdo {\n\t\t\t\tif (newLevel > curLevel) {\n\t\t\t\t\tfor (i = curLevel; i < newLevel; ++i) {\n\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\tjQuery(document.createElement('blockquote'))\n\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (newLevel < curLevel) {\n\t\t\t\t\tfor (i = curLevel; i > newLevel; --i) {\n\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcurLevel = newLevel;\n\t\t\t\tw.subWikify(destStack[destStack.length - 1], this.terminator);\n\t\t\t\tjQuery(document.createElement('br')).appendTo(destStack[destStack.length - 1]);\n\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tnewLevel = match[0].length;\n\t\t\t\t\tw.nextMatch += match[0].length;\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'macro',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<<',\n\t\tlookahead : new RegExp(`<<(/?${Patterns.macroName})(?:\\\\s*)((?:(?:\\`(?:\\\\\\\\.|[^\\`\\\\\\\\])*\\`)|(?:\"(?:\\\\\\\\.|[^\"\\\\\\\\])*\")|(?:'(?:\\\\\\\\.|[^'\\\\\\\\])*')|(?:\\\\[(?:[<>]?[Ii][Mm][Gg])?\\\\[[^\\\\r\\\\n]*?\\\\]\\\\]+)|[^>]|(?:>(?!>)))*)>>`, 'gm'),\n\t\tworking   : { source : '', name : '', arguments : '', index : 0 }, // the working parse object\n\t\tcontext   : null, // last execution context object (top-level macros, hierarchically, have a null context)\n\n\t\thandler(w) {\n\t\t\tconst matchStart = this.lookahead.lastIndex = w.matchStart;\n\n\t\t\tif (this.parseTag(w)) {\n\t\t\t\t/*\n\t\t\t\t\tIf `parseBody()` is called below, it will modify the current working\n\t\t\t\t\tvalues, so we must cache them now.\n\t\t\t\t*/\n\t\t\t\tconst nextMatch = w.nextMatch;\n\t\t\t\tconst name      = this.working.name;\n\t\t\t\tconst rawArgs   = this.working.arguments;\n\t\t\t\tlet macro;\n\n\t\t\t\ttry {\n\t\t\t\t\tmacro = Macro.get(name);\n\n\t\t\t\t\tif (macro) {\n\t\t\t\t\t\tlet payload = null;\n\n\t\t\t\t\t\tif (macro.hasOwnProperty('tags')) {\n\t\t\t\t\t\t\tpayload = this.parseBody(w, macro);\n\n\t\t\t\t\t\t\tif (!payload) {\n\t\t\t\t\t\t\t\tw.nextMatch = nextMatch; // we must reset `w.nextMatch` here, as `parseBody()` modifies it\n\t\t\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t\t`cannot find a closing tag for macro <<${name}>>`,\n\t\t\t\t\t\t\t\t\t`${w.source.slice(matchStart, w.nextMatch)}\\u2026`\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (typeof macro.handler === 'function') {\n\t\t\t\t\t\t\tconst args = !payload\n\t\t\t\t\t\t\t\t? this.createArgs(rawArgs, this.skipArgs(macro, macro.name))\n\t\t\t\t\t\t\t\t: payload[0].args;\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tNew-style macros.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (macro.hasOwnProperty('_MACRO_API')) {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tAdd the macro's execution context to the context chain.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tthis.context = new MacroContext({\n\t\t\t\t\t\t\t\t\tmacro,\n\t\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\t\targs,\n\t\t\t\t\t\t\t\t\tpayload,\n\t\t\t\t\t\t\t\t\tsource : w.source.slice(matchStart, w.nextMatch),\n\t\t\t\t\t\t\t\t\tparent : this.context,\n\t\t\t\t\t\t\t\t\tparser : w\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tCall the handler.\n\n\t\t\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\t\t\t\t\t\tto ensure that the execution context is properly restored in the event\n\t\t\t\t\t\t\t\t\tthat an uncaught exception is thrown during the handler call.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tmacro.handler.call(this.context);\n\t\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\t\tQUESTION: Swap to the following, which passes macro arguments in\n\t\t\t\t\t\t\t\t\t\tas parameters to the handler function, in addition to them being\n\t\t\t\t\t\t\t\t\t\tavailable on its `this`?  If so, it might still be something to\n\t\t\t\t\t\t\t\t\t\thold off on until v3, when the legacy macro API is removed.\n\n\t\t\t\t\t\t\t\t\t\tmacro.handler.apply(this.context, this.context.args);\n\t\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t\tthis.context = this.context.parent;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t[DEPRECATED] Old-style/legacy macros.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tSet up the raw arguments string.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tconst prevRawArgs = w._rawArgs;\n\t\t\t\t\t\t\t\tw._rawArgs = rawArgs;\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tCall the handler.\n\n\t\t\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\t\t\t\t\t\tto ensure that the previous raw arguments string is properly restored in\n\t\t\t\t\t\t\t\t\tthe event that an uncaught exception is thrown during the handler call.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tmacro.handler(w.output, name, args, w, payload);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t\tw._rawArgs = prevRawArgs;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t`macro <<${name}>> handler function ${macro.hasOwnProperty('handler') ? 'is not a function' : 'does not exist'}`,\n\t\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (Macro.tags.has(name)) {\n\t\t\t\t\t\tconst tags = Macro.tags.get(name);\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`child tag <<${name}>> was found outside of a call to its parent macro${tags.length === 1 ? '' : 's'} <<${tags.join('>>, <<')}>>`,\n\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`macro <<${name}>> does not exist`,\n\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot execute ${macro && macro.isWidget ? 'widget' : 'macro'} <<${name}>>: ${ex.message}`,\n\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\tthis.working.source    = '';\n\t\t\t\t\tthis.working.name      = '';\n\t\t\t\t\tthis.working.arguments = '';\n\t\t\t\t\tthis.working.index     = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t}\n\t\t},\n\n\t\tparseTag(w) {\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart && match[1]) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tthis.working.source    = w.source.slice(match.index, this.lookahead.lastIndex);\n\t\t\t\tthis.working.name      = match[1];\n\t\t\t\tthis.working.arguments = match[2];\n\t\t\t\tthis.working.index     = match.index;\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t},\n\n\t\tparseBody(w, macro) {\n\t\t\tconst openTag  = this.working.name;\n\t\t\tconst closeTag = `/${openTag}`;\n\t\t\tconst closeAlt = `end${openTag}`;\n\t\t\tconst bodyTags = Array.isArray(macro.tags) ? macro.tags : false;\n\t\t\tconst payload  = [];\n\t\t\tlet end          = -1;\n\t\t\tlet opened       = 1;\n\t\t\tlet curSource    = this.working.source;\n\t\t\tlet curTag       = this.working.name;\n\t\t\tlet curArgument  = this.working.arguments;\n\t\t\tlet contentStart = w.nextMatch;\n\n\t\t\twhile ((w.matchStart = w.source.indexOf(this.match, w.nextMatch)) !== -1) {\n\t\t\t\tif (!this.parseTag(w)) {\n\t\t\t\t\tthis.lookahead.lastIndex = w.nextMatch = w.matchStart + this.match.length;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst tagSource = this.working.source;\n\t\t\t\tconst tagName   = this.working.name;\n\t\t\t\tconst tagArgs   = this.working.arguments;\n\t\t\t\tconst tagBegin  = this.working.index;\n\t\t\t\tconst tagEnd    = w.nextMatch;\n\n\t\t\t\tswitch (tagName) {\n\t\t\t\tcase openTag:\n\t\t\t\t\t++opened;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase closeAlt:\n\t\t\t\tcase closeTag:\n\t\t\t\t\t--opened;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tif (opened === 1 && bodyTags) {\n\t\t\t\t\t\tfor (let i = 0, iend = bodyTags.length; i < iend; ++i) {\n\t\t\t\t\t\t\tif (tagName === bodyTags[i]) {\n\t\t\t\t\t\t\t\tpayload.push({\n\t\t\t\t\t\t\t\t\tsource    : curSource,\n\t\t\t\t\t\t\t\t\tname      : curTag,\n\t\t\t\t\t\t\t\t\targuments : curArgument,\n\t\t\t\t\t\t\t\t\targs      : this.createArgs(curArgument, this.skipArgs(macro, curTag)),\n\t\t\t\t\t\t\t\t\tcontents  : w.source.slice(contentStart, tagBegin)\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tcurSource    = tagSource;\n\t\t\t\t\t\t\t\tcurTag       = tagName;\n\t\t\t\t\t\t\t\tcurArgument  = tagArgs;\n\t\t\t\t\t\t\t\tcontentStart = tagEnd;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (opened === 0) {\n\t\t\t\t\tpayload.push({\n\t\t\t\t\t\tsource    : curSource,\n\t\t\t\t\t\tname      : curTag,\n\t\t\t\t\t\targuments : curArgument,\n\t\t\t\t\t\targs      : this.createArgs(curArgument, this.skipArgs(macro, curTag)),\n\t\t\t\t\t\tcontents  : w.source.slice(contentStart, tagBegin)\n\t\t\t\t\t});\n\t\t\t\t\tend = tagEnd;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (end !== -1) {\n\t\t\t\tw.nextMatch = end;\n\t\t\t\treturn payload;\n\t\t\t}\n\n\t\t\treturn null;\n\t\t},\n\n\t\tcreateArgs(rawArgsString, skipArgs) {\n\t\t\tconst args = skipArgs ? [] : this.parseArgs(rawArgsString);\n\n\t\t\t// Extend the args array with the raw and full argument strings.\n\t\t\tObject.defineProperties(args, {\n\t\t\t\traw : {\n\t\t\t\t\tvalue : rawArgsString\n\t\t\t\t},\n\t\t\t\tfull : {\n\t\t\t\t\tvalue : Scripting.parse(rawArgsString)\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn args;\n\t\t},\n\n\t\tskipArgs(macro, tagName) {\n\t\t\tif (macro.hasOwnProperty('skipArgs')) {\n\t\t\t\tconst sa = macro.skipArgs;\n\n\t\t\t\treturn typeof sa === 'boolean' && sa || Array.isArray(sa) && sa.includes(tagName);\n\t\t\t}\n\t\t\t/* legacy */\n\t\t\telse if (macro.hasOwnProperty('skipArg0')) {\n\t\t\t\treturn macro.skipArg0 && macro.name === tagName;\n\t\t\t}\n\t\t\t/* /legacy */\n\n\t\t\treturn false;\n\t\t},\n\n\t\tparseArgs : (() => {\n\t\t\tconst Item = Lexer.enumFromNames([ // lex item types object (pseudo-enumeration)\n\t\t\t\t'Error',        // error\n\t\t\t\t'Bareword',     // bare identifier\n\t\t\t\t'Expression',   // expression (backquoted)\n\t\t\t\t'String',       // quoted string (single or double)\n\t\t\t\t'SquareBracket' // [[…]] or [img[…]]\n\t\t\t]);\n\t\t\tconst spaceRe    = new RegExp(Patterns.space);\n\t\t\tconst notSpaceRe = new RegExp(Patterns.notSpace);\n\t\t\tconst varTest    = new RegExp(`^${Patterns.variable}`);\n\n\t\t\t// Lexing functions.\n\t\t\tfunction slurpQuote(lexer, endQuote) {\n\t\t\t\tloop: for (;;) {\n\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* falls through */\n\t\t\t\t\tcase EOF:\n\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\treturn EOF;\n\n\t\t\t\t\tcase endQuote:\n\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t}\n\n\t\t\t\treturn lexer.pos;\n\t\t\t}\n\n\t\t\tfunction lexSpace(lexer) {\n\t\t\t\tconst offset = lexer.source.slice(lexer.pos).search(notSpaceRe);\n\n\t\t\t\tif (offset === EOF) {\n\t\t\t\t\t// no non-whitespace characters, so bail\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\telse if (offset !== 0) {\n\t\t\t\t\tlexer.pos += offset;\n\t\t\t\t\tlexer.ignore();\n\t\t\t\t}\n\n\t\t\t\t// determine what the next state is\n\t\t\t\tswitch (lexer.next()) {\n\t\t\t\tcase '`':\n\t\t\t\t\treturn lexExpression;\n\t\t\t\tcase '\"':\n\t\t\t\t\treturn lexDoubleQuote;\n\t\t\t\tcase \"'\":\n\t\t\t\t\treturn lexSingleQuote;\n\t\t\t\tcase '[':\n\t\t\t\t\treturn lexSquareBracket;\n\t\t\t\tdefault:\n\t\t\t\t\treturn lexBareword;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction lexExpression(lexer) {\n\t\t\t\tif (slurpQuote(lexer, '`') === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated backquote expression');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.Expression);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexDoubleQuote(lexer) {\n\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated double quoted string');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.String);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexSingleQuote(lexer) {\n\t\t\t\tif (slurpQuote(lexer, \"'\") === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated single quoted string');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.String);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexSquareBracket(lexer) {\n\t\t\t\tconst imgMeta = '<>IiMmGg';\n\t\t\t\tlet what;\n\n\t\t\t\tif (lexer.accept(imgMeta)) {\n\t\t\t\t\twhat = 'image';\n\t\t\t\t\tlexer.acceptRun(imgMeta);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\twhat = 'link';\n\t\t\t\t}\n\n\t\t\t\tif (!lexer.accept('[')) {\n\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t}\n\n\t\t\t\tlexer.depth = 2; // account for both initial left square brackets\n\n\t\t\t\tloop: for (;;) {\n\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* falls through */\n\t\t\t\t\tcase EOF:\n\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\tcase '[':\n\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase ']':\n\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\tif (lexer.depth < 0) {\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, \"unexpected right square bracket ']'\");\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\tif (lexer.next() === ']') {\n\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.SquareBracket);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexBareword(lexer) {\n\t\t\t\tconst offset = lexer.source.slice(lexer.pos).search(spaceRe);\n\t\t\t\tlexer.pos = offset === EOF ? lexer.source.length : lexer.pos + offset;\n\t\t\t\tlexer.emit(Item.Bareword);\n\t\t\t\treturn offset === EOF ? null : lexSpace;\n\t\t\t}\n\n\t\t\t// Parse function.\n\t\t\tfunction parseMacroArgs(rawArgsString) {\n\t\t\t\t// Initialize the lexer.\n\t\t\t\tconst lexer = new Lexer(rawArgsString, lexSpace);\n\t\t\t\tconst args  = [];\n\n\t\t\t\t// Lex the raw argument string.\n\t\t\t\tlexer.run().forEach(item => {\n\t\t\t\t\tlet arg = item.text;\n\n\t\t\t\t\tswitch (item.type) {\n\t\t\t\t\tcase Item.Error:\n\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${item.message}`);\n\n\t\t\t\t\tcase Item.Bareword:\n\t\t\t\t\t\t// A variable, so substitute its value.\n\t\t\t\t\t\tif (varTest.test(arg)) {\n\t\t\t\t\t\t\targ = State.getVar(arg);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Property access on the settings or setup objects, so try to evaluate it.\n\t\t\t\t\t\telse if (/^(?:settings|setup)[.[]/.test(arg)) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\targ = Scripting.evalTwineScript(arg);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Null literal, so convert it into null.\n\t\t\t\t\t\telse if (arg === 'null') {\n\t\t\t\t\t\t\targ = null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Undefined literal, so convert it into undefined.\n\t\t\t\t\t\telse if (arg === 'undefined') {\n\t\t\t\t\t\t\targ = undefined;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Boolean true literal, so convert it into true.\n\t\t\t\t\t\telse if (arg === 'true') {\n\t\t\t\t\t\t\targ = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Boolean false literal, so convert it into false.\n\t\t\t\t\t\telse if (arg === 'false') {\n\t\t\t\t\t\t\targ = false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// NaN literal, so convert it into NaN.\n\t\t\t\t\t\telse if (arg === 'NaN') {\n\t\t\t\t\t\t\targ = NaN;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Attempt to convert it into a number, in case it's a numeric literal.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst argAsNum = Number(arg);\n\n\t\t\t\t\t\t\tif (!Number.isNaN(argAsNum)) {\n\t\t\t\t\t\t\t\targ = argAsNum;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.Expression:\n\t\t\t\t\t\targ = arg.slice(1, -1).trim(); // remove the backquotes and trim the expression\n\n\t\t\t\t\t\t// Empty backquotes.\n\t\t\t\t\t\tif (arg === '') {\n\t\t\t\t\t\t\targ = undefined;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Evaluate the expression.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tThe enclosing parenthesis here are necessary to force a code string\n\t\t\t\t\t\t\t\t\tconsisting solely of an object literal to be evaluated as such, rather\n\t\t\t\t\t\t\t\t\tthan as a code block.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\targ = Scripting.evalTwineScript(`(${arg})`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument expression \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.String:\n\t\t\t\t\t\t// Evaluate the string to handle escaped characters.\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\targ = Scripting.evalJavaScript(arg);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument string \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.SquareBracket:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\t\t\tsource     : arg,\n\t\t\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${markup.error}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (markup.pos < arg.length) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": unexpected character(s) \"${arg.slice(markup.pos)}\" (pos: ${markup.pos})`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert to a link or image object.\n\t\t\t\t\t\t\tif (markup.isLink) {\n\t\t\t\t\t\t\t\t// .isLink, [.text], [.forceInternal], .link, [.setter]\n\t\t\t\t\t\t\t\targ = { isLink : true };\n\t\t\t\t\t\t\t\targ.count    = markup.hasOwnProperty('text') ? 2 : 1;\n\t\t\t\t\t\t\t\targ.link     = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\t\t\t\t\t\targ.text     = markup.hasOwnProperty('text') ? Wikifier.helpers.evalText(markup.text) : arg.link;\n\t\t\t\t\t\t\t\targ.external = !markup.forceInternal && Wikifier.isExternalLink(arg.link);\n\t\t\t\t\t\t\t\targ.setFn    = markup.hasOwnProperty('setter')\n\t\t\t\t\t\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (markup.isImage) {\n\t\t\t\t\t\t\t\t// .isImage, [.align], [.title], .source, [.forceInternal], [.link], [.setter]\n\t\t\t\t\t\t\t\targ = (source => {\n\t\t\t\t\t\t\t\t\tconst imgObj = {\n\t\t\t\t\t\t\t\t\t\tsource,\n\t\t\t\t\t\t\t\t\t\tisImage : true\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t\t// Check for Twine 1.4 Base64 image passage transclusion.\n\t\t\t\t\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t\t\t\t\timgObj.source  = passage.text;\n\t\t\t\t\t\t\t\t\t\t\timgObj.passage = passage.title;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturn imgObj;\n\t\t\t\t\t\t\t\t})(Wikifier.helpers.evalPassageId(markup.source));\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('align')) {\n\t\t\t\t\t\t\t\t\targ.align = markup.align;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('text')) {\n\t\t\t\t\t\t\t\t\targ.title = Wikifier.helpers.evalText(markup.text);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('link')) {\n\t\t\t\t\t\t\t\t\targ.link     = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\t\t\t\t\t\t\targ.external = !markup.forceInternal && Wikifier.isExternalLink(arg.link);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\targ.setFn = markup.hasOwnProperty('setter')\n\t\t\t\t\t\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\targs.push(arg);\n\t\t\t\t});\n\n\t\t\t\treturn args;\n\t\t\t}\n\n\t\t\treturn parseMacroArgs;\n\t\t})()\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'link',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\[\\\\[[^[]',\n\n\t\thandler(w) {\n\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup(w);\n\n\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = markup.pos;\n\n\t\t\t// text=(text), forceInternal=(~), link=link, setter=(setter)\n\t\t\tconst link  = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\tconst text  = markup.hasOwnProperty('text') ? Wikifier.helpers.evalText(markup.text) : link;\n\t\t\tconst setFn = markup.hasOwnProperty('setter')\n\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t: null;\n\n\t\t\t// Debug view setup.\n\t\t\tconst output = (Config.debug\n\t\t\t\t? new DebugView(w.output, 'link-markup', '[[link]]', w.source.slice(w.matchStart, w.nextMatch))\n\t\t\t\t: w\n\t\t\t).output;\n\n\t\t\tif (markup.forceInternal || !Wikifier.isExternalLink(link)) {\n\t\t\t\tWikifier.createInternalLink(output, link, text, setFn);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tWikifier.createExternalLink(output, link, text);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'urlLink',\n\t\tprofiles : ['core'],\n\t\tmatch    : Patterns.url,\n\n\t\thandler(w) {\n\t\t\tw.outputText(Wikifier.createExternalLink(w.output, w.matchText), w.matchStart, w.nextMatch);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'image',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\[[<>]?[Ii][Mm][Gg]\\\\[',\n\n\t\thandler(w) {\n\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup(w);\n\n\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = markup.pos;\n\n\t\t\t// Debug view setup.\n\t\t\tlet debugView;\n\n\t\t\tif (Config.debug) {\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tw.output,\n\t\t\t\t\t'image-markup',\n\t\t\t\t\tmarkup.hasOwnProperty('link') ? '[img[][link]]' : '[img[]]',\n\t\t\t\t\tw.source.slice(w.matchStart, w.nextMatch)\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ block : true });\n\t\t\t}\n\n\t\t\t// align=(left|right), title=(title), source=source, forceInternal=(~), link=(link), setter=(setter)\n\t\t\tconst setFn = markup.hasOwnProperty('setter')\n\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t: null;\n\t\t\tlet el     = (Config.debug ? debugView : w).output;\n\t\t\tlet source;\n\n\t\t\tif (markup.hasOwnProperty('link')) {\n\t\t\t\tconst link = Wikifier.helpers.evalPassageId(markup.link);\n\n\t\t\t\tif (markup.forceInternal || !Wikifier.isExternalLink(link)) {\n\t\t\t\t\tel = Wikifier.createInternalLink(el, link, null, setFn);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tel = Wikifier.createExternalLink(el, link);\n\t\t\t\t}\n\n\t\t\t\tel.classList.add('link-image');\n\t\t\t}\n\n\t\t\tel = jQuery(document.createElement('img'))\n\t\t\t\t.appendTo(el)\n\t\t\t\t.get(0);\n\t\t\tsource = Wikifier.helpers.evalPassageId(markup.source);\n\n\t\t\t// Check for image passage transclusion.\n\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\tel.setAttribute('data-passage', passage.title);\n\t\t\t\t\tsource = passage.text.trim();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tel.src = source;\n\n\t\t\tif (markup.hasOwnProperty('text')) {\n\t\t\t\tel.title = Wikifier.helpers.evalText(markup.text);\n\t\t\t}\n\n\t\t\tif (markup.hasOwnProperty('align')) {\n\t\t\t\tel.align = markup.align;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'monospacedByBlock',\n\t\tprofiles  : ['block'],\n\t\tmatch     : '^\\\\{\\\\{\\\\{\\\\n',\n\t\tlookahead : /^\\{\\{\\{\\n((?:^[^\\n]*\\n)+?)(^\\}\\}\\}$\\n?)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tconst pre = jQuery(document.createElement('pre'));\n\t\t\t\tjQuery(document.createElement('code'))\n\t\t\t\t\t.text(match[1])\n\t\t\t\t\t.appendTo(pre);\n\t\t\t\tpre.appendTo(w.output);\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'formatByChar',\n\t\tprofiles : ['core'],\n\t\tmatch    : \"''|//|__|\\\\^\\\\^|~~|==|\\\\{\\\\{\\\\{\",\n\n\t\thandler(w) {\n\t\t\tswitch (w.matchText) {\n\t\t\tcase \"''\":\n\t\t\t\tw.subWikify(jQuery(document.createElement('strong')).appendTo(w.output).get(0), \"''\");\n\t\t\t\tbreak;\n\n\t\t\tcase '//':\n\t\t\t\tw.subWikify(jQuery(document.createElement('em')).appendTo(w.output).get(0), '//');\n\t\t\t\tbreak;\n\n\t\t\tcase '__':\n\t\t\t\tw.subWikify(jQuery(document.createElement('u')).appendTo(w.output).get(0), '__');\n\t\t\t\tbreak;\n\n\t\t\tcase '^^':\n\t\t\t\tw.subWikify(jQuery(document.createElement('sup')).appendTo(w.output).get(0), '\\\\^\\\\^');\n\t\t\t\tbreak;\n\n\t\t\tcase '~~':\n\t\t\t\tw.subWikify(jQuery(document.createElement('sub')).appendTo(w.output).get(0), '~~');\n\t\t\t\tbreak;\n\n\t\t\tcase '==':\n\t\t\t\tw.subWikify(jQuery(document.createElement('s')).appendTo(w.output).get(0), '==');\n\t\t\t\tbreak;\n\n\t\t\tcase '{{{':\n\t\t\t\t{\n\t\t\t\t\tconst lookahead = /\\{\\{\\{((?:.|\\n)*?)\\}\\}\\}/gm;\n\n\t\t\t\t\tlookahead.lastIndex = w.matchStart;\n\n\t\t\t\t\tconst match = lookahead.exec(w.source);\n\n\t\t\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\t\t\tjQuery(document.createElement('code'))\n\t\t\t\t\t\t\t.text(match[1])\n\t\t\t\t\t\t\t.appendTo(w.output);\n\t\t\t\t\t\tw.nextMatch = lookahead.lastIndex;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'customStyle',\n\t\tprofiles   : ['core'],\n\t\tmatch      : '@@',\n\t\tterminator : '@@',\n\t\tblockRe    : /\\s*\\n/gm,\n\n\t\thandler(w) {\n\t\t\tconst css = Wikifier.helpers.inlineCss(w);\n\n\t\t\tthis.blockRe.lastIndex = w.nextMatch; // must follow the call to `inlineCss()`\n\n\t\t\tconst blockMatch = this.blockRe.exec(w.source);\n\t\t\tconst blockLevel = blockMatch && blockMatch.index === w.nextMatch;\n\t\t\tconst $el        = jQuery(document.createElement(blockLevel ? 'div' : 'span'))\n\t\t\t\t.appendTo(w.output);\n\n\t\t\tif (css.classes.length === 0 && css.id === '' && Object.keys(css.styles).length === 0) {\n\t\t\t\t$el.addClass('marked');\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcss.classes.forEach(className => $el.addClass(className));\n\n\t\t\t\tif (css.id !== '') {\n\t\t\t\t\t$el.attr('id', css.id);\n\t\t\t\t}\n\n\t\t\t\t$el.css(css.styles);\n\t\t\t}\n\n\t\t\tif (blockLevel) {\n\t\t\t\t// Skip the leading and, if it exists, trailing newlines.\n\t\t\t\tw.nextMatch += blockMatch[0].length;\n\t\t\t\tw.subWikify($el[0], `\\\\n?${this.terminator}`);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tw.subWikify($el[0], this.terminator);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimText',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '\"{3}|<[Nn][Oo][Ww][Ii][Kk][Ii]>',\n\t\tlookahead : /(?:\"{3}((?:.|\\n)*?)\"{3})|(?:<[Nn][Oo][Ww][Ii][Kk][Ii]>((?:.|\\n)*?)<\\/[Nn][Oo][Ww][Ii][Kk][Ii]>)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tjQuery(document.createElement('span'))\n\t\t\t\t\t.addClass('verbatim')\n\t\t\t\t\t.text(match[1] || match[2])\n\t\t\t\t\t.appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'horizontalRule',\n\t\tprofiles : ['core'],\n\t\tmatch    : '^----+$\\\\n?|<[Hh][Rr]\\\\s*/?>\\\\n?',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createElement('hr')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'emdash',\n\t\tprofiles : ['core'],\n\t\tmatch    : '--',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createTextNode('\\u2014')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'doubleDollarSign',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\${2}', // eslint-disable-line no-template-curly-in-string\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createTextNode('$')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\t/*\n\t\t\tSupported syntax:\n\t\t\t\t$variable\n\t\t\t\t$variable.property\n\t\t\t\t$variable[numericIndex]\n\t\t\t\t$variable[\"property\"]\n\t\t\t\t$variable['property']\n\t\t\t\t$variable[$indexOrPropertyVariable]\n\t\t*/\n\t\tname     : 'nakedVariable',\n\t\tprofiles : ['core'],\n\t\tmatch    : `${Patterns.variable}(?:(?:\\\\.${Patterns.identifier})|(?:\\\\[\\\\d+\\\\])|(?:\\\\[\"(?:\\\\\\\\.|[^\"\\\\\\\\])+\"\\\\])|(?:\\\\['(?:\\\\\\\\.|[^'\\\\\\\\])+'\\\\])|(?:\\\\[${Patterns.variable}\\\\]))*`,\n\n\t\thandler(w) {\n\t\t\tconst result = toStringOrDefault(State.getVar(w.matchText), null);\n\n\t\t\tif (result === null) {\n\t\t\t\tjQuery(document.createTextNode(w.matchText)).appendTo(w.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnew Wikifier(\n\t\t\t\t\t(Config.debug\n\t\t\t\t\t\t? new DebugView(w.output, 'variable', w.matchText, w.matchText) // Debug view setup.\n\t\t\t\t\t\t: w\n\t\t\t\t\t).output,\n\t\t\t\t\tresult\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'template',\n\t\tprofiles : ['core'],\n\t\tmatch    : `\\\\?${Patterns.templateName}`,\n\n\t\thandler(w) {\n\t\t\tconst name = w.matchText.slice(1);\n\t\t\tlet template = Template.get(name);\n\t\t\tlet result   = null;\n\n\t\t\t// If we have an array of templates, randomly choose one.\n\t\t\tif (template instanceof Array) {\n\t\t\t\ttemplate = template.random();\n\t\t\t}\n\n\t\t\tswitch (typeof template) {\n\t\t\tcase 'function':\n\t\t\t\ttry {\n\t\t\t\t\tresult = toStringOrDefault(template.call({ name }), null);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot execute function template ?${name}: ${ex.message}`,\n\t\t\t\t\t\tw.source.slice(w.matchStart, w.nextMatch)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'string':\n\t\t\t\tresult = template;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (result === null) {\n\t\t\t\tjQuery(document.createTextNode(w.matchText)).appendTo(w.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnew Wikifier(\n\t\t\t\t\t(Config.debug\n\t\t\t\t\t\t? new DebugView(w.output, 'template', w.matchText, w.matchText) // Debug view setup.\n\t\t\t\t\t\t: w\n\t\t\t\t\t).output,\n\t\t\t\t\tresult\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'heading',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^!{1,6}',\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.subWikify(\n\t\t\t\tjQuery(document.createElement(`h${w.matchLength}`)).appendTo(w.output).get(0),\n\t\t\t\tthis.terminator\n\t\t\t);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname           : 'table',\n\t\tprofiles       : ['block'],\n\t\tmatch          : '^\\\\|(?:[^\\\\n]*)\\\\|(?:[fhck]?)$',\n\t\tlookahead      : /^\\|([^\\n]*)\\|([fhck]?)$/gm,\n\t\trowTerminator  : '\\\\|(?:[cfhk]?)$\\\\n?',\n\t\tcellPattern    : '(?:\\\\|([^\\\\n\\\\|]*)\\\\|)|(\\\\|[cfhk]?$\\\\n?)',\n\t\tcellTerminator : '(?:\\\\u0020*)\\\\|',\n\t\trowTypes       : { c : 'caption', f : 'tfoot', h : 'thead', '' : 'tbody' }, // eslint-disable-line id-length\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst table       = jQuery(document.createElement('table')).appendTo(w.output).get(0);\n\t\t\tconst prevColumns = [];\n\t\t\tlet curRowType    = null;\n\t\t\tlet $rowContainer = null;\n\t\t\tlet rowCount      = 0;\n\t\t\tlet matched;\n\n\t\t\tw.nextMatch = w.matchStart;\n\n\t\t\tdo {\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tconst nextRowType = match[2];\n\n\t\t\t\t\tif (nextRowType === 'k') {\n\t\t\t\t\t\ttable.className = match[1];\n\t\t\t\t\t\tw.nextMatch += match[0].length + 1;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (nextRowType !== curRowType) {\n\t\t\t\t\t\t\tcurRowType = nextRowType;\n\t\t\t\t\t\t\t$rowContainer = jQuery(document.createElement(this.rowTypes[nextRowType]))\n\t\t\t\t\t\t\t\t.appendTo(table);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (curRowType === 'c') {\n\t\t\t\t\t\t\t$rowContainer.css('caption-side', rowCount === 0 ? 'top' : 'bottom');\n\t\t\t\t\t\t\tw.nextMatch += 1;\n\t\t\t\t\t\t\tw.subWikify($rowContainer[0], this.rowTerminator);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tthis.rowHandler(\n\t\t\t\t\t\t\t\tw,\n\t\t\t\t\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t\t\t\t\t.appendTo($rowContainer)\n\t\t\t\t\t\t\t\t\t.get(0),\n\t\t\t\t\t\t\t\tprevColumns\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t++rowCount;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t},\n\n\t\trowHandler(w, rowEl, prevColumns) {\n\t\t\tconst cellRe = new RegExp(this.cellPattern, 'gm');\n\t\t\tlet col         = 0;\n\t\t\tlet curColCount = 1;\n\t\t\tlet matched;\n\n\t\t\tdo {\n\t\t\t\tcellRe.lastIndex = w.nextMatch;\n\n\t\t\t\tconst cellMatch = cellRe.exec(w.source);\n\n\t\t\t\tmatched = cellMatch && cellMatch.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tif (cellMatch[1] === '~') {\n\t\t\t\t\t\tconst last = prevColumns[col];\n\n\t\t\t\t\t\tif (last) {\n\t\t\t\t\t\t\t++last.rowCount;\n\t\t\t\t\t\t\tlast.$element\n\t\t\t\t\t\t\t\t.attr('rowspan', last.rowCount)\n\t\t\t\t\t\t\t\t.css('vertical-align', 'middle');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length - 1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (cellMatch[1] === '>') {\n\t\t\t\t\t\t++curColCount;\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length - 1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (cellMatch[2]) {\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t++w.nextMatch;\n\n\t\t\t\t\t\tconst css = Wikifier.helpers.inlineCss(w);\n\t\t\t\t\t\tlet spaceLeft  = false;\n\t\t\t\t\t\tlet spaceRight = false;\n\t\t\t\t\t\tlet $cell;\n\n\t\t\t\t\t\twhile (w.source.substr(w.nextMatch, 1) === ' ') {\n\t\t\t\t\t\t\tspaceLeft = true;\n\t\t\t\t\t\t\t++w.nextMatch;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (w.source.substr(w.nextMatch, 1) === '!') {\n\t\t\t\t\t\t\t$cell = jQuery(document.createElement('th')).appendTo(rowEl);\n\t\t\t\t\t\t\t++w.nextMatch;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t$cell = jQuery(document.createElement('td')).appendTo(rowEl);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tprevColumns[col] = {\n\t\t\t\t\t\t\trowCount : 1,\n\t\t\t\t\t\t\t$element : $cell\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (curColCount > 1) {\n\t\t\t\t\t\t\t$cell.attr('colspan', curColCount);\n\t\t\t\t\t\t\tcurColCount = 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tw.subWikify($cell[0], this.cellTerminator);\n\n\t\t\t\t\t\tif (w.matchText.substr(w.matchText.length - 2, 1) === ' ') {\n\t\t\t\t\t\t\tspaceRight = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcss.classes.forEach(className => $cell.addClass(className));\n\n\t\t\t\t\t\tif (css.id !== '') {\n\t\t\t\t\t\t\t$cell.attr('id', css.id);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (spaceLeft && spaceRight) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'center';\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (spaceLeft) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'right';\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (spaceRight) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'left';\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$cell.css(css.styles);\n\n\t\t\t\t\t\tw.nextMatch = w.nextMatch - 1;\n\t\t\t\t\t}\n\n\t\t\t\t\t++col;\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'list',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^(?:(?:\\\\*+)|(?:#+))',\n\t\tlookahead  : /^(?:(\\*+)|(#+))/gm,\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = w.matchStart;\n\n\t\t\tconst destStack = [w.output];\n\t\t\tlet curType  = null;\n\t\t\tlet curLevel = 0;\n\t\t\tlet matched;\n\t\t\tlet i;\n\n\t\t\tdo {\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tconst newType  = match[2] ? 'ol' : 'ul';\n\t\t\t\t\tconst newLevel = match[0].length;\n\n\t\t\t\t\tw.nextMatch += match[0].length;\n\n\t\t\t\t\tif (newLevel > curLevel) {\n\t\t\t\t\t\tfor (i = curLevel; i < newLevel; ++i) {\n\t\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\t\tjQuery(document.createElement(newType))\n\t\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (newLevel < curLevel) {\n\t\t\t\t\t\tfor (i = curLevel; i > newLevel; --i) {\n\t\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (newLevel === curLevel && newType !== curType) {\n\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\tjQuery(document.createElement(newType))\n\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tcurLevel = newLevel;\n\t\t\t\t\tcurType = newType;\n\t\t\t\t\tw.subWikify(\n\t\t\t\t\t\tjQuery(document.createElement('li'))\n\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t.get(0),\n\t\t\t\t\t\tthis.terminator\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'commentByBlock',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '(?:/(?:%|\\\\*))|(?:<!--)',\n\t\tlookahead : /(?:\\/(%|\\*)(?:(?:.|\\n)*?)\\1\\/)|(?:<!--(?:(?:.|\\n)*?)-->)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'lineContinuation',\n\t\tprofiles : ['core'],\n\n\t\t// WARNING: The ordering here is important: end-of-line, start-of-line, end-of-string, start-of-string.\n\t\tmatch : `\\\\\\\\${Patterns.spaceNoTerminator}*\\\\n|\\\\n${Patterns.spaceNoTerminator}*\\\\\\\\|\\\\n?\\\\\\\\${Patterns.spaceNoTerminator}*$|^${Patterns.spaceNoTerminator}*\\\\\\\\\\\\n?`,\n\n\t\thandler(w) {\n\t\t\tw.nextMatch = w.matchStart + w.matchLength;\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'lineBreak',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\n|<[Bb][Rr]\\\\s*/?>',\n\n\t\thandler(w) {\n\t\t\tif (!w.options.nobr) {\n\t\t\t\tjQuery(document.createElement('br')).appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'htmlCharacterReference',\n\t\tprofiles : ['core'],\n\t\tmatch    : '(?:(?:&#?[0-9A-Za-z]{2,8};|.)(?:&#?(?:x0*(?:3[0-6][0-9A-Fa-f]|1D[C-Fc-f][0-9A-Fa-f]|20[D-Fd-f][0-9A-Fa-f]|FE2[0-9A-Fa-f])|0*(?:76[89]|7[7-9][0-9]|8[0-7][0-9]|761[6-9]|76[2-7][0-9]|84[0-3][0-9]|844[0-7]|6505[6-9]|6506[0-9]|6507[0-1]));)+|&#?[0-9A-Za-z]{2,8};)',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t.append(w.matchText)\n\t\t\t\t.appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'xmlProlog',\n\t\tprofiles : ['core'],\n\t\tmatch    : '<\\\\?[Xx][Mm][Ll][^>]*\\\\?>',\n\n\t\thandler(w) {\n\t\t\tw.nextMatch = w.matchStart + w.matchLength;\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimHtml',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Hh][Tt][Mm][Ll]>',\n\t\tlookahead : /<[Hh][Tt][Mm][Ll]>((?:.|\\n)*?)<\\/[Hh][Tt][Mm][Ll]>/gm,\n\t\thandler   : _verbatimTagHandler\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimScriptTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Ss][Cc][Rr][Ii][Pp][Tt][^>]*>',\n\t\tlookahead : /(<[Ss][Cc][Rr][Ii][Pp][Tt]*>(?:.|\\n)*?<\\/[Ss][Cc][Rr][Ii][Pp][Tt]>)/gm,\n\t\thandler   : _verbatimTagHandler\n\t});\n\n\tWikifier.Parser.add({\n\t\tname           : 'styleTag',\n\t\tprofiles       : ['core'],\n\t\tmatch          : '<[Ss][Tt][Yy][Ll][Ee][^>]*>',\n\t\tlookahead      : /(<[Ss][Tt][Yy][Ll][Ee]*>)((?:.|\\n)*?)(<\\/[Ss][Tt][Yy][Ll][Ee]>)/gm,\n\t\timageMarkup    : new RegExp(Patterns.cssImage, 'g'),\n\t\thasImageMarkup : new RegExp(Patterns.cssImage),\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tlet css = match[2];\n\n\t\t\t\t// Check for wiki image transclusion.\n\t\t\t\tif (this.hasImageMarkup.test(css)) {\n\t\t\t\t\tthis.imageMarkup.lastIndex = 0;\n\n\t\t\t\t\tcss = css.replace(this.imageMarkup, wikiImage => {\n\t\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\t\tsource     : wikiImage,\n\t\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (markup.hasOwnProperty('error') || markup.pos < wikiImage.length) {\n\t\t\t\t\t\t\treturn wikiImage;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet source = markup.source;\n\n\t\t\t\t\t\t// Handle image passage transclusion.\n\t\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t\tsource = passage.text;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tThe source may be URI- or Base64-encoded, so we cannot use `encodeURIComponent()`\n\t\t\t\t\t\t\there.  Instead, we simply encode any double quotes, since the URI will be\n\t\t\t\t\t\t\tdelimited by them.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\treturn `url(\"${source.replace(/\"/g, '%22')}\")`;\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t\t.append(match[1] + css + match[3])\n\t\t\t\t\t.appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'svgTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Ss][Vv][Gg][^>]*>',\n\t\tlookahead : /(<[Ss][Vv][Gg][^>]*>(?:.|\\n)*?<\\/[Ss][Vv][Gg]>)/gm,\n\t\tnamespace : 'http://www.w3.org/2000/svg',\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tconst $frag = jQuery(document.createDocumentFragment()).append(match[1]);\n\n\t\t\t\t// Postprocess the relevant SVG element nodes.\n\t\t\t\t$frag.find('a[data-passage],image[data-passage]').each((_, el) => {\n\t\t\t\t\tconst tagName = el.tagName.toLowerCase();\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.processAttributeDirectives(el);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`svg|<${tagName}>: ${ex.message}`,\n\t\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (el.hasAttribute('data-passage')) {\n\t\t\t\t\t\tthis.processDataAttributes(el, tagName);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\t$frag.appendTo(w.output);\n\t\t\t}\n\t\t},\n\n\t\tprocessAttributeDirectives(el) {\n\t\t\t// NOTE: The `.attributes` property yields a live collection, so we\n\t\t\t// must make a non-live copy of it as we will be adding and removing\n\t\t\t// members of said collection if any directives are found.\n\t\t\t[...el.attributes].forEach(({ name, value }) => {\n\t\t\t\tconst evalShorthand = name[0] === '@';\n\n\t\t\t\tif (evalShorthand || name.startsWith('sc-eval:')) {\n\t\t\t\t\tconst newName = name.slice(evalShorthand ? 1 : 8); // Remove eval directive prefix.\n\n\t\t\t\t\tif (newName === 'data-setter') {\n\t\t\t\t\t\tthrow new Error(`evaluation directive is not allowed on the data-setter attribute: \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\t// Evaluate the value as TwineScript.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = Scripting.evalTwineScript(value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`bad evaluation from attribute directive \"${name}\": ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Assign the result to the new attribute and remove the old one.\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: Most browsers (ca. Nov 2017) have broken `setAttribute()`\n\t\t\t\t\t\t\tmethod implementations that throw on attribute names that start\n\t\t\t\t\t\t\twith, or contain, various symbols that are completely valid per\n\t\t\t\t\t\t\tthe specification.  Thus this code could fail if the user chooses\n\t\t\t\t\t\t\tattribute names that, after removing the directive prefix, are\n\t\t\t\t\t\t\tunpalatable to `setAttribute()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tel.setAttribute(newName, result);\n\t\t\t\t\t\tel.removeAttribute(name);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`cannot transform attribute directive \"${name}\" into attribute \"${newName}\"`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tprocessDataAttributes(el, tagName) {\n\t\t\tlet passage = el.getAttribute('data-passage');\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst evaluated = Wikifier.helpers.evalPassageId(passage);\n\n\t\t\tif (evaluated !== passage) {\n\t\t\t\tpassage = evaluated;\n\t\t\t\tel.setAttribute('data-passage', evaluated);\n\t\t\t}\n\n\t\t\tif (passage !== '') {\n\t\t\t\t// '<image>' element, so attempt media passage transclusion.\n\t\t\t\tif (tagName === 'image') {\n\t\t\t\t\tif (passage.slice(0, 5) !== 'data:' && Story.has(passage)) {\n\t\t\t\t\t\tpassage = Story.get(passage);\n\n\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t// NOTE: SVG `.href` IDL attribute is read-only,\n\t\t\t\t\t\t\t// so set its `href` content attribute instead.\n\t\t\t\t\t\t\tel.setAttribute('href', passage.text.trim());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Elsewise, assume a link element of some type—e.g., '<a>'.\n\t\t\t\telse {\n\t\t\t\t\tlet setter = el.getAttribute('data-setter');\n\t\t\t\t\tlet setFn;\n\n\t\t\t\t\tif (setter != null) { // lazy equality for null\n\t\t\t\t\t\tsetter = String(setter).trim();\n\n\t\t\t\t\t\tif (setter !== '') {\n\t\t\t\t\t\t\tsetFn = Wikifier.helpers.createShadowSetterCallback(Scripting.parse(setter));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tel.classList.add('link-internal');\n\n\t\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t\tel.classList.add('link-visited');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tel.classList.add('link-broken');\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery(el).ariaClick({ one : true }, function () {\n\t\t\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\t\t\tsetFn.call(this);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\t/*\n\t\t\tNOTE: This parser MUST come after any parser which handles HTML tag-\n\t\t\tlike constructs—e.g. 'verbatimText', 'horizontalRule', 'lineBreak',\n\t\t\t'xmlProlog', 'verbatimHtml', 'verbatimSvgTag', 'verbatimScriptTag',\n\t\t\tand 'styleTag'.\n\t\t*/\n\t\tname      : 'htmlTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<\\\\w+(?:\\\\s+[^\\\\u0000-\\\\u001F\\\\u007F-\\\\u009F\\\\s\"\\'>\\\\/=]+(?:\\\\s*=\\\\s*(?:\"[^\"]*?\"|\\'[^\\']*?\\'|[^\\\\s\"\\'=<>`]+))?)*\\\\s*\\\\/?>',\n\t\ttagRe     : /^<(\\w+)/,\n\t\tmediaTags : ['audio', 'img', 'source', 'track', 'video'], // NOTE: The `<picture>` element should not be in this list.\n\t\tnobrTags  : ['audio', 'colgroup', 'datalist', 'dl', 'figure', 'meter', 'ol', 'optgroup', 'picture', 'progress', 'ruby', 'select', 'table', 'tbody', 'tfoot', 'thead', 'tr', 'ul', 'video'],\n\t\tvoidTags  : ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'],\n\n\t\thandler(w) {\n\t\t\tconst tagMatch = this.tagRe.exec(w.matchText);\n\t\t\tconst tag      = tagMatch && tagMatch[1];\n\t\t\tconst tagName  = tag && tag.toLowerCase();\n\n\t\t\tif (tagName) {\n\t\t\t\tconst isVoid = this.voidTags.includes(tagName) || w.matchText.endsWith('/>');\n\t\t\t\tconst isNobr = this.nobrTags.includes(tagName);\n\t\t\t\tlet terminator;\n\t\t\t\tlet terminatorMatch;\n\n\t\t\t\tif (!isVoid) {\n\t\t\t\t\tterminator = `<\\\\/${tagName}\\\\s*>`;\n\n\t\t\t\t\tconst terminatorRe = new RegExp(terminator, 'gim'); // ignore case during match\n\n\t\t\t\t\tterminatorRe.lastIndex = w.matchStart;\n\t\t\t\t\tterminatorMatch = terminatorRe.exec(w.source);\n\t\t\t\t}\n\n\t\t\t\tif (isVoid || terminatorMatch) {\n\t\t\t\t\tlet output    = w.output;\n\t\t\t\t\tlet el        = document.createElement(w.output.tagName);\n\t\t\t\t\tlet debugView;\n\n\t\t\t\t\tel.innerHTML = w.matchText;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tNOTE: The use of a `while` statement here is curious, however,\n\t\t\t\t\t\tI'm hesitant to change it for fear of breaking some edge case.\n\t\t\t\t\t*/\n\t\t\t\t\twhile (el.firstChild) {\n\t\t\t\t\t\tel = el.firstChild;\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.processAttributeDirectives(el);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`<${tagName}>: ${ex.message}`,\n\t\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (el.hasAttribute('data-passage')) {\n\t\t\t\t\t\tthis.processDataAttributes(el, tagName);\n\n\t\t\t\t\t\t// Debug view setup.\n\t\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t`html-${tagName}`,\n\t\t\t\t\t\t\t\ttagName,\n\t\t\t\t\t\t\t\tw.matchText\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tdebugView.modes({\n\t\t\t\t\t\t\t\tblock   : tagName === 'img',\n\t\t\t\t\t\t\t\tnonvoid : terminatorMatch\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\toutput = debugView.output;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (terminatorMatch) {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists\n\t\t\t\t\t\t\tsolely to ensure that the options stack is properly restored in\n\t\t\t\t\t\t\tthe event that an uncaught exception is thrown during the call to\n\t\t\t\t\t\t\t`subWikify()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tWikifier.Option.push({ nobr : isNobr });\n\t\t\t\t\t\t\tw.subWikify(el, terminator, { ignoreTerminatorCase : true });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\tWikifier.Option.pop();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tDebug view modification.  If the current element has any debug\n\t\t\t\t\t\t\tview descendants who have \"block\" mode set, then set its debug\n\t\t\t\t\t\t\tview to the same.  It just makes things look a bit nicer.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tif (debugView && jQuery(el).find('.debug.block').length > 0) {\n\t\t\t\t\t\t\tdebugView.modes({ block : true });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tNOTE: The use of `cloneNode(true)` here for `<track>` elements\n\t\t\t\t\t\tis necessary to workaround a poorly understood rehoming issue.\n\t\t\t\t\t*/\n\t\t\t\t\toutput.appendChild(tagName === 'track' ? el.cloneNode(true) : el);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot find a closing tag for HTML <${tag}>`,\n\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tprocessAttributeDirectives(el) {\n\t\t\t// NOTE: The `.attributes` property yields a live collection, so we\n\t\t\t// must make a non-live copy of it as we will be adding and removing\n\t\t\t// members of said collection if any directives are found.\n\t\t\t[...el.attributes].forEach(({ name, value }) => {\n\t\t\t\tconst evalShorthand = name[0] === '@';\n\n\t\t\t\tif (evalShorthand || name.startsWith('sc-eval:')) {\n\t\t\t\t\tconst newName = name.slice(evalShorthand ? 1 : 8); // Remove eval directive prefix.\n\n\t\t\t\t\tif (newName === 'data-setter') {\n\t\t\t\t\t\tthrow new Error(`evaluation directive is not allowed on the data-setter attribute: \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\t// Evaluate the value as TwineScript.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = Scripting.evalTwineScript(value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`bad evaluation from attribute directive \"${name}\": ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Assign the result to the new attribute and remove the old one.\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: Most browsers (ca. Nov 2017) have broken `setAttribute()`\n\t\t\t\t\t\t\tmethod implementations that throw on attribute names that start\n\t\t\t\t\t\t\twith, or contain, various symbols that are completely valid per\n\t\t\t\t\t\t\tthe specification.  Thus this code could fail if the user chooses\n\t\t\t\t\t\t\tattribute names that, after removing the directive prefix, are\n\t\t\t\t\t\t\tunpalatable to `setAttribute()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tel.setAttribute(newName, result);\n\t\t\t\t\t\tel.removeAttribute(name);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`cannot transform attribute directive \"${name}\" into attribute \"${newName}\"`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tprocessDataAttributes(el, tagName) {\n\t\t\tlet passage = el.getAttribute('data-passage');\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst evaluated = Wikifier.helpers.evalPassageId(passage);\n\n\t\t\tif (evaluated !== passage) {\n\t\t\t\tpassage = evaluated;\n\t\t\t\tel.setAttribute('data-passage', evaluated);\n\t\t\t}\n\n\t\t\tif (passage !== '') {\n\t\t\t\t// Media element, so attempt media passage transclusion.\n\t\t\t\tif (this.mediaTags.includes(tagName)) {\n\t\t\t\t\tif (passage.slice(0, 5) !== 'data:' && Story.has(passage)) {\n\t\t\t\t\t\tpassage = Story.get(passage);\n\n\t\t\t\t\t\tlet parentName;\n\t\t\t\t\t\tlet twineTag;\n\n\t\t\t\t\t\tswitch (tagName) {\n\t\t\t\t\t\tcase 'audio':\n\t\t\t\t\t\tcase 'video':\n\t\t\t\t\t\t\ttwineTag = `Twine.${tagName}`;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'img':\n\t\t\t\t\t\t\ttwineTag = 'Twine.image';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'track':\n\t\t\t\t\t\t\ttwineTag = 'Twine.vtt';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'source':\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst $parent = $(el).closest('audio,picture,video');\n\n\t\t\t\t\t\t\t\tif ($parent.length) {\n\t\t\t\t\t\t\t\t\tparentName = $parent.get(0).tagName.toLowerCase();\n\t\t\t\t\t\t\t\t\ttwineTag = `Twine.${parentName === 'picture' ? 'image' : parentName}`;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (passage.tags.includes(twineTag)) {\n\t\t\t\t\t\t\tel[parentName === 'picture' ? 'srcset' : 'src'] = passage.text.trim();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Elsewise, assume a link element of some type—e.g., '<a>', '<area>', '<button>', etc.\n\t\t\t\telse {\n\t\t\t\t\tlet setter = el.getAttribute('data-setter');\n\t\t\t\t\tlet setFn;\n\n\t\t\t\t\tif (setter != null) { // lazy equality for null\n\t\t\t\t\t\tsetter = String(setter).trim();\n\n\t\t\t\t\t\tif (setter !== '') {\n\t\t\t\t\t\t\tsetFn = Wikifier.helpers.createShadowSetterCallback(Scripting.parse(setter));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tel.classList.add('link-internal');\n\n\t\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t\tel.classList.add('link-visited');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tel.classList.add('link-broken');\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery(el).ariaClick({ one : true }, function () {\n\t\t\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\t\t\tsetFn.call(this);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/template.js\n\n\tCopyright © 2019–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns */\n\nvar Template = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Template definitions.\n\tconst _templates = new Map();\n\n\t// Valid template name regular expression.\n\tconst _validNameRe = new RegExp(`^(?:${Patterns.templateName})$`);\n\n\t// Valid template type predicate.\n\tconst _validType = template => {\n\t\tconst templateType = typeof template;\n\t\treturn templateType === 'function' || templateType === 'string';\n\t};\n\n\n\t/*******************************************************************************\n\t\tTemplate Functions.\n\t*******************************************************************************/\n\n\tfunction templateAdd(name, template) {\n\t\tif (\n\t\t\t   !_validType(template)\n\t\t\t&& !(template instanceof Array && template.length > 0 && template.every(_validType))\n\t\t) {\n\t\t\tthrow new TypeError(`invalid template type (${name}); templates must be: functions, strings, or an array of either`);\n\t\t}\n\n\t\t(name instanceof Array ? name : [name]).forEach(name => {\n\t\t\tif (!_validNameRe.test(name)) {\n\t\t\t\tthrow new Error(`invalid template name \"${name}\"`);\n\t\t\t}\n\t\t\tif (_templates.has(name)) {\n\t\t\t\tthrow new Error(`cannot clobber existing template ?${name}`);\n\t\t\t}\n\n\t\t\t_templates.set(name, template);\n\t\t});\n\t}\n\n\tfunction templateDelete(name) {\n\t\t(name instanceof Array ? name : [name]).forEach(name => _templates.delete(name));\n\t}\n\n\tfunction templateGet(name) {\n\t\treturn _templates.has(name) ? _templates.get(name) : null;\n\t}\n\n\tfunction templateHas(name) {\n\t\treturn _templates.has(name);\n\t}\n\n\tfunction templateSize() {\n\t\treturn _templates.size;\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tadd    : { value : templateAdd },\n\t\tdelete : { value : templateDelete },\n\t\tget    : { value : templateGet },\n\t\thas    : { value : templateHas },\n\t\tsize   : { get : templateSize }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macro.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns, Scripting, clone, macros */\n\nvar Macro = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Macro definitions.\n\tconst _macros = {};\n\n\t// Map of all macro tags and their parents (key: 'tag name' => value: ['list of parent names']).\n\tconst _tags = {};\n\n\t// Valid macro name regular expression.\n\tconst _validNameRe = new RegExp(`^(?:${Patterns.macroName})$`);\n\n\n\t/*******************************************************************************************************************\n\t\tMacros Functions.\n\t*******************************************************************************************************************/\n\tfunction macrosAdd(name, def, deep) {\n\t\tif (Array.isArray(name)) {\n\t\t\tname.forEach(name => macrosAdd(name, def, deep));\n\t\t\treturn;\n\t\t}\n\n\t\tif (!_validNameRe.test(name)) {\n\t\t\tthrow new Error(`invalid macro name \"${name}\"`);\n\t\t}\n\n\t\tif (macrosHas(name)) {\n\t\t\tthrow new Error(`cannot clobber existing macro <<${name}>>`);\n\t\t}\n\t\telse if (tagsHas(name)) {\n\t\t\tthrow new Error(`cannot clobber child tag <<${name}>> of parent macro${_tags[name].length === 1 ? '' : 's'} <<${_tags[name].join('>>, <<')}>>`);\n\t\t}\n\n\t\ttry {\n\t\t\tif (typeof def === 'object') {\n\t\t\t\t// Add the macro definition.\n\t\t\t\t_macros[name] = deep ? clone(def) : def;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Add the macro alias.\n\t\t\t\tif (macrosHas(def)) {\n\t\t\t\t\t_macros[name] = deep ? clone(_macros[def]) : _macros[def];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new Error(`cannot create alias of nonexistent macro <<${def}>>`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tObject.defineProperty(_macros, name, { writable : false });\n\n\t\t\t/* legacy */\n\t\t\t/*\n\t\t\t\tSince `macrosGet()` may return legacy macros, we have to add a flag to (modern)\n\t\t\t\tAPI macros, so that the macro formatter will know how to call the macro.\n\t\t\t*/\n\t\t\t_macros[name]._MACRO_API = true;\n\t\t\t/* /legacy */\n\t\t}\n\t\tcatch (ex) {\n\t\t\tif (ex.name === 'TypeError') {\n\t\t\t\tthrow new Error(`cannot clobber protected macro <<${name}>>`);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error(`unknown error when attempting to add macro <<${name}>>: [${ex.name}] ${ex.message}`);\n\t\t\t}\n\t\t}\n\n\t\t// Tags post-processing.\n\t\tif (_macros[name].hasOwnProperty('tags')) {\n\t\t\tif (_macros[name].tags == null) { // lazy equality for null\n\t\t\t\ttagsRegister(name);\n\t\t\t}\n\t\t\telse if (Array.isArray(_macros[name].tags)) {\n\t\t\t\ttagsRegister(name, _macros[name].tags);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error(`bad value for \"tags\" property of macro <<${name}>>`);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction macrosDelete(name) {\n\t\tif (Array.isArray(name)) {\n\t\t\tname.forEach(name => macrosDelete(name));\n\t\t\treturn;\n\t\t}\n\n\t\tif (macrosHas(name)) {\n\t\t\t// Tags pre-processing.\n\t\t\tif (_macros[name].hasOwnProperty('tags')) {\n\t\t\t\ttagsUnregister(name);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t// Remove the macro definition.\n\t\t\t\tObject.defineProperty(_macros, name, { writable : true });\n\t\t\t\tdelete _macros[name];\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tthrow new Error(`unknown error removing macro <<${name}>>: ${ex.message}`);\n\t\t\t}\n\t\t}\n\t\telse if (tagsHas(name)) {\n\t\t\tthrow new Error(`cannot remove child tag <<${name}>> of parent macro <<${_tags[name]}>>`);\n\t\t}\n\t}\n\n\tfunction macrosIsEmpty() {\n\t\treturn Object.keys(_macros).length === 0;\n\t}\n\n\tfunction macrosHas(name) {\n\t\treturn _macros.hasOwnProperty(name);\n\t}\n\n\tfunction macrosGet(name) {\n\t\tlet macro = null;\n\n\t\tif (macrosHas(name) && typeof _macros[name].handler === 'function') {\n\t\t\tmacro = _macros[name];\n\t\t}\n\t\t/* legacy macro support */\n\t\telse if (macros.hasOwnProperty(name) && typeof macros[name].handler === 'function') {\n\t\t\tmacro = macros[name];\n\t\t}\n\t\t/* /legacy macro support */\n\n\t\treturn macro;\n\t}\n\n\tfunction macrosInit(handler = 'init') { // eslint-disable-line no-unused-vars\n\t\tObject.keys(_macros).forEach(name => {\n\t\t\tif (typeof _macros[name][handler] === 'function') {\n\t\t\t\t_macros[name][handler](name);\n\t\t\t}\n\t\t});\n\n\t\t/* legacy macro support */\n\t\tObject.keys(macros).forEach(name => {\n\t\t\tif (typeof macros[name][handler] === 'function') {\n\t\t\t\tmacros[name][handler](name);\n\t\t\t}\n\t\t});\n\t\t/* /legacy macro support */\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTags Functions.\n\t*******************************************************************************************************************/\n\tfunction tagsRegister(parent, bodyTags) {\n\t\tif (!parent) {\n\t\t\tthrow new Error('no parent specified');\n\t\t}\n\n\t\tconst endTags = [`/${parent}`, `end${parent}`]; // automatically create the closing tags\n\t\tconst allTags = [].concat(endTags, Array.isArray(bodyTags) ? bodyTags : []);\n\n\t\tfor (let i = 0; i < allTags.length; ++i) {\n\t\t\tconst tag = allTags[i];\n\n\t\t\tif (macrosHas(tag)) {\n\t\t\t\tthrow new Error('cannot register tag for an existing macro');\n\t\t\t}\n\n\t\t\tif (tagsHas(tag)) {\n\t\t\t\tif (!_tags[tag].includes(parent)) {\n\t\t\t\t\t_tags[tag].push(parent);\n\t\t\t\t\t_tags[tag].sort();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_tags[tag] = [parent];\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction tagsUnregister(parent) {\n\t\tif (!parent) {\n\t\t\tthrow new Error('no parent specified');\n\t\t}\n\n\t\tObject.keys(_tags).forEach(tag => {\n\t\t\tconst i = _tags[tag].indexOf(parent);\n\n\t\t\tif (i !== -1) {\n\t\t\t\tif (_tags[tag].length === 1) {\n\t\t\t\t\tdelete _tags[tag];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_tags[tag].splice(i, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction tagsHas(name) {\n\t\treturn _tags.hasOwnProperty(name);\n\t}\n\n\tfunction tagsGet(name) {\n\t\treturn tagsHas(name) ? _tags[name] : null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tMacro Functions.\n\t\t*/\n\t\tadd     : { value : macrosAdd },\n\t\tdelete  : { value : macrosDelete },\n\t\tisEmpty : { value : macrosIsEmpty },\n\t\thas     : { value : macrosHas },\n\t\tget     : { value : macrosGet },\n\t\tinit    : { value : macrosInit },\n\n\t\t/*\n\t\t\tTags Functions.\n\t\t*/\n\t\ttags : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tregister   : { value : tagsRegister },\n\t\t\t\tunregister : { value : tagsUnregister },\n\t\t\t\thas        : { value : tagsHas },\n\t\t\t\tget        : { value : tagsGet }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tevalStatements : { value : (...args) => Scripting.evalJavaScript(...args) } // SEE: `markup/scripting.js`.\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macrocontext.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, DebugView, Patterns, State, Wikifier, throwError */\n\nvar MacroContext = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tMacroContext Class.\n\t*******************************************************************************************************************/\n\tclass MacroContext {\n\t\tconstructor(contextData) {\n\t\t\tconst context = Object.assign({\n\t\t\t\tparent  : null,\n\t\t\t\tmacro   : null,\n\t\t\t\tname    : '',\n\t\t\t\targs    : null,\n\t\t\t\tpayload : null,\n\t\t\t\tparser  : null,\n\t\t\t\tsource  : ''\n\t\t\t}, contextData);\n\n\t\t\tif (context.macro === null || context.name === '' || context.parser === null) {\n\t\t\t\tthrow new TypeError('context object missing required properties');\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tself : {\n\t\t\t\t\tvalue : context.macro\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : context.name\n\t\t\t\t},\n\n\t\t\t\targs : {\n\t\t\t\t\tvalue : context.args\n\t\t\t\t},\n\n\t\t\t\tpayload : {\n\t\t\t\t\tvalue : context.payload\n\t\t\t\t},\n\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : context.source\n\t\t\t\t},\n\n\t\t\t\tparent : {\n\t\t\t\t\tvalue : context.parent\n\t\t\t\t},\n\n\t\t\t\tparser : {\n\t\t\t\t\tvalue : context.parser\n\t\t\t\t},\n\n\t\t\t\t_output : {\n\t\t\t\t\tvalue : context.parser.output\n\t\t\t\t},\n\n\t\t\t\t_shadows : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_debugView : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_debugViewEnabled : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : Config.debug\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tget output() {\n\t\t\treturn this._debugViewEnabled ? this.debugView.output : this._output;\n\t\t}\n\n\t\tget shadows() {\n\t\t\treturn [...this._shadows];\n\t\t}\n\n\t\tget shadowView() {\n\t\t\tconst view = new Set();\n\t\t\tthis.contextSelectAll(ctx => ctx._shadows)\n\t\t\t\t.forEach(ctx => ctx._shadows.forEach(name => view.add(name)));\n\t\t\treturn [...view];\n\t\t}\n\n\t\tget debugView() {\n\t\t\tif (this._debugViewEnabled) {\n\t\t\t\treturn this._debugView !== null ? this._debugView : this.createDebugView();\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tcontextHas(filter) {\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tcontextSelect(filter) {\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\treturn context;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tcontextSelectAll(filter) {\n\t\t\tconst result = [];\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\tresult.push(context);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\taddShadow(...names) {\n\t\t\tif (!this._shadows) {\n\t\t\t\tthis._shadows = new Set();\n\t\t\t}\n\n\t\t\tconst varRe = new RegExp(`^${Patterns.variable}$`);\n\n\t\t\tnames\n\t\t\t\t.flat(Infinity)\n\t\t\t\t.forEach(name => {\n\t\t\t\t\tif (typeof name !== 'string') {\n\t\t\t\t\t\tthrow new TypeError(`variable name must be a string; type: ${typeof name}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!varRe.test(name)) {\n\t\t\t\t\t\tthrow new Error(`invalid variable name \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._shadows.add(name);\n\t\t\t\t});\n\t\t}\n\n\t\tcreateShadowWrapper(callback, doneCallback, startCallback) {\n\t\t\tconst shadowContext = this;\n\t\t\tlet shadowStore;\n\n\t\t\tif (typeof callback === 'function') {\n\t\t\t\tshadowStore = {};\n\t\t\t\tthis.shadowView.forEach(varName => {\n\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\t\t\tshadowStore[varName] = store[varKey];\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn function (...args) {\n\t\t\t\tif (typeof startCallback === 'function') {\n\t\t\t\t\tstartCallback.apply(this, args);\n\t\t\t\t}\n\n\t\t\t\tif (typeof callback === 'function') {\n\t\t\t\t\tconst shadowNames = Object.keys(shadowStore);\n\t\t\t\t\tconst valueCache  = shadowNames.length > 0 ? {} : null;\n\t\t\t\t\tconst macroParser = Wikifier.Parser.get('macro');\n\t\t\t\t\tlet contextCache;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t\tcallback.\n\t\t\t\t\t*/\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tCache the existing values of the variables to be shadowed and assign the\n\t\t\t\t\t\t\tshadow values.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tstore[varKey] = shadowStore[varName];\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Cache the existing macro execution context and assign the shadow context.\n\t\t\t\t\t\tcontextCache = macroParser.context;\n\t\t\t\t\t\tmacroParser.context = shadowContext;\n\n\t\t\t\t\t\t// Call the callback function.\n\t\t\t\t\t\tcallback.apply(this, args);\n\t\t\t\t\t}\n\t\t\t\t\tfinally {\n\t\t\t\t\t\t// Revert the macro execution context shadowing.\n\t\t\t\t\t\tif (contextCache !== undefined) {\n\t\t\t\t\t\t\tmacroParser.context = contextCache;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Revert the variable shadowing.\n\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tUpdate the shadow store with the variable's current value, in case it\n\t\t\t\t\t\t\t\twas modified during the callback.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\n\t\t\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (typeof doneCallback === 'function') {\n\t\t\t\t\tdoneCallback.apply(this, args);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tcreateDebugView(name, title) {\n\t\t\tthis._debugView = new DebugView(\n\t\t\t\tthis._output,\n\t\t\t\t'macro',\n\t\t\t\tname ? name : this.name,\n\t\t\t\ttitle ? title : this.source\n\t\t\t);\n\n\t\t\tif (this.payload !== null && this.payload.length > 0) {\n\t\t\t\tthis._debugView.modes({ nonvoid : true });\n\t\t\t}\n\n\t\t\tthis._debugViewEnabled = true;\n\t\t\treturn this._debugView;\n\t\t}\n\n\t\tremoveDebugView() {\n\t\t\tif (this._debugView !== null) {\n\t\t\t\tthis._debugView.remove();\n\t\t\t\tthis._debugView = null;\n\t\t\t}\n\n\t\t\tthis._debugViewEnabled = false;\n\t\t}\n\n\t\terror(message, source, stack) {\n\t\t\treturn throwError(this._output, `<<${this.name}>>: ${message}`, source ? source : this.source, stack);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn MacroContext;\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macrolib.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, DebugView, Engine, Has, L10n, Macro, Patterns, Scripting, SimpleAudio, State, Story,\n\t       TempState, Util, Wikifier, postdisplay, prehistory, storage, toStringOrDefault\n*/\n\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tVariables Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<capture>>\n\t*/\n\tMacro.add('capture', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tif (this.args.raw.length === 0) {\n\t\t\t\treturn this.error('no story/temporary variable list specified');\n\t\t\t}\n\n\t\t\tconst valueCache = {};\n\n\t\t\t/*\n\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t`Wikifier` call.\n\t\t\t*/\n\t\t\ttry {\n\t\t\t\tconst varRe = new RegExp(`(${Patterns.variable})`,'g');\n\t\t\t\tlet match;\n\n\t\t\t\t/*\n\t\t\t\t\tCache the existing values of the variables and add a shadow.\n\t\t\t\t*/\n\t\t\t\twhile ((match = varRe.exec(this.args.raw)) !== null) {\n\t\t\t\t\tconst varName = match[1];\n\t\t\t\t\tconst varKey  = varName.slice(1);\n\t\t\t\t\tconst store   = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.addShadow(varName);\n\t\t\t\t}\n\n\t\t\t\tnew Wikifier(this.output, this.payload[0].contents);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\t// Revert the variable shadowing.\n\t\t\t\tthis.shadows.forEach(varName => {\n\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<set>>\n\t*/\n\tMacro.add('set', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<unset>>\n\t*/\n\tMacro.add('unset', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no story/temporary variable list specified');\n\t\t\t}\n\n\t\t\tconst re = new RegExp(\n\t\t\t\t`State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})`,\n\t\t\t\t'g'\n\t\t\t);\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst store = State[match[1]];\n\t\t\t\tconst name  = match[2];\n\n\t\t\t\tif (store.hasOwnProperty(name)) {\n\t\t\t\t\tdelete store[name];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<remember>>\n\t*/\n\tMacro.add('remember', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\tconst remember = storage.get('remember') || {};\n\t\t\tconst re       = new RegExp(`State\\\\.variables\\\\.(${Patterns.identifier})`, 'g');\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst name = match[1];\n\t\t\t\tremember[name] = State.variables[name];\n\t\t\t}\n\n\t\t\tif (!storage.set('remember', remember)) {\n\t\t\t\treturn this.error(`unknown error, cannot remember: ${this.args.raw}`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t},\n\n\t\tinit() {\n\t\t\tconst remember = storage.get('remember');\n\n\t\t\tif (remember) {\n\t\t\t\tObject.keys(remember).forEach(name => State.variables[name] = remember[name]);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<forget>>\n\t*/\n\tMacro.add('forget', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no story variable list specified');\n\t\t\t}\n\n\t\t\tconst remember = storage.get('remember');\n\t\t\tconst re       = new RegExp(`State\\\\.variables\\\\.(${Patterns.identifier})`, 'g');\n\t\t\tlet match;\n\t\t\tlet needStore = false;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst name = match[1];\n\n\t\t\t\tif (State.variables.hasOwnProperty(name)) {\n\t\t\t\t\tdelete State.variables[name];\n\t\t\t\t}\n\n\t\t\t\tif (remember && remember.hasOwnProperty(name)) {\n\t\t\t\t\tneedStore = true;\n\t\t\t\t\tdelete remember[name];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (needStore) {\n\t\t\t\tif (Object.keys(remember).length === 0) {\n\t\t\t\t\tif (!storage.delete('remember')) {\n\t\t\t\t\t\treturn this.error('unknown error, cannot update remember store');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (!storage.set('remember', remember)) {\n\t\t\t\t\treturn this.error('unknown error, cannot update remember store');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tScripting Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<run>>\n\t*/\n\tMacro.add('run', 'set'); // add <<run>> as an alias of <<set>>\n\n\t/*\n\t\t<<script>>\n\t*/\n\tMacro.add('script', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tconst output = document.createDocumentFragment();\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.payload[0].contents, output);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.createDebugView();\n\t\t\t}\n\n\t\t\tif (output.hasChildNodes()) {\n\t\t\t\tthis.output.appendChild(output);\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tDisplay Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<include>>\n\t*/\n\tMacro.add('include', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = this.args[0].link;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the passage name.\n\t\t\t\tpassage = this.args[0];\n\t\t\t}\n\n\t\t\tif (!Story.has(passage)) {\n\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tpassage = Story.get(passage);\n\t\t\tlet $el;\n\n\t\t\tif (this.args[1]) {\n\t\t\t\t$el = jQuery(document.createElement(this.args[1]))\n\t\t\t\t\t.addClass(`${passage.domId} macro-${this.name}`)\n\t\t\t\t\t.attr('data-passage', passage.title)\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$el = jQuery(this.output);\n\t\t\t}\n\n\t\t\t$el.wiki(passage.processText());\n\t\t}\n\t});\n\n\t/*\n\t\t<<nobr>>\n\t*/\n\tMacro.add('nobr', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\t/*\n\t\t\t\tWikify the contents, after removing all leading & trailing newlines and compacting\n\t\t\t\tall internal sequences of newlines into single spaces.\n\t\t\t*/\n\t\t\tnew Wikifier(this.output, this.payload[0].contents.replace(/^\\n+|\\n+$/g, '').replace(/\\n+/g, ' '));\n\t\t}\n\t});\n\n\t/*\n\t\t<<print>>, <<=>>, & <<->>\n\t*/\n\tMacro.add(['print', '=', '-'], {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = toStringOrDefault(Scripting.evalJavaScript(this.args.full), null);\n\n\t\t\t\tif (result !== null) {\n\t\t\t\t\tnew Wikifier(this.output, this.name === '-' ? Util.escape(result) : result);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<silently>>\n\t*/\n\tMacro.add('silently', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, this.payload[0].contents.trim());\n\n\t\t\tif (Config.debug) {\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tthis.debugView.modes({ block : true, hidden : true });\n\t\t\t\tthis.output.appendChild(frag);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Discard the output, unless there were errors.\n\t\t\t\tconst errList = [...frag.querySelectorAll('.error')].map(errEl => errEl.textContent);\n\n\t\t\t\tif (errList.length > 0) {\n\t\t\t\t\treturn this.error(`error${errList.length === 1 ? '' : 's'} within contents (${errList.join('; ')})`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] <<display>>\n\t*/\n\tMacro.add('display', 'include'); // add <<display>> as an alias of <<include>>\n\n\n\t/*******************************************************************************************************************\n\t\tControl Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<if>>, <<elseif>>, & <<else>>\n\t*/\n\tMacro.add('if', {\n\t\tskipArgs : true,\n\t\ttags     : ['elseif', 'else'],\n\n\t\thandler() {\n\t\t\tlet i;\n\n\t\t\ttry {\n\t\t\t\tconst len = this.payload.length;\n\n\t\t\t\t// Sanity checks.\n\t\t\t\tfor (/* declared previously */ i = 0; i < len; ++i) {\n\t\t\t\t\t/* eslint-disable prefer-template */\n\t\t\t\t\tswitch (this.payload[i].name) {\n\t\t\t\t\tcase 'else':\n\t\t\t\t\t\tif (this.payload[i].args.raw.length > 0) {\n\t\t\t\t\t\t\tif (/^\\s*if\\b/i.test(this.payload[i].args.raw)) {\n\t\t\t\t\t\t\t\treturn this.error(`whitespace is not allowed between the \"else\" and \"if\" in <<elseif>> clause${i > 0 ? ' (#' + i + ')' : ''}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn this.error(`<<else>> does not accept a conditional expression (perhaps you meant to use <<elseif>>), invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (i + 1 !== len) {\n\t\t\t\t\t\t\treturn this.error('<<else>> must be the final clause');\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif (this.payload[i].args.full.length === 0) {\n\t\t\t\t\t\t\treturn this.error(`no conditional expression specified for <<${this.payload[i].name}>> clause${i > 0 ? ' (#' + i + ')' : ''}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (\n\t\t\t\t\t\t\t   Config.macros.ifAssignmentError\n\t\t\t\t\t\t\t&& /[^!=&^|<>*/%+-]=[^=>]/.test(this.payload[i].args.full)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn this.error(`assignment operator found within <<${this.payload[i].name}>> clause${i > 0 ? ' (#' + i + ')' : ''} (perhaps you meant to use an equality operator: ==, ===, eq, is), invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable prefer-template */\n\t\t\t\t}\n\n\t\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\t\tlet success = false;\n\n\t\t\t\t// Evaluate the clauses.\n\t\t\t\tfor (/* declared previously */ i = 0; i < len; ++i) {\n\t\t\t\t\t// Custom debug view setup for the current clause.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({ nonvoid : false });\n\t\t\t\t\t}\n\n\t\t\t\t\t// Conditional test.\n\t\t\t\t\tif (this.payload[i].name === 'else' || !!evalJavaScript(this.payload[i].args.full)) {\n\t\t\t\t\t\tsuccess = true;\n\t\t\t\t\t\tnew Wikifier(this.output, this.payload[i].contents);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse if (Config.debug) {\n\t\t\t\t\t\t// Custom debug view setup for a failed conditional.\n\t\t\t\t\t\tthis.debugView.modes({\n\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup for the remaining clauses.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tfor (++i; i < len; ++i) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tFake a debug view for `<</if>>`.  We do this to aid the checking of nesting\n\t\t\t\t\t\tand as a quick indicator of if any of the clauses matched.\n\t\t\t\t\t*/\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : !success,\n\t\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad conditional expression in <<${i === 0 ? 'if' : 'elseif'}>> clause${i > 0 ? ' (#' + i + ')' : ''}: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack); // eslint-disable-line prefer-template\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<switch>>, <<case>>, & <<default>>\n\t*/\n\tMacro.add('switch', {\n\t\tskipArgs : ['switch'],\n\t\ttags     : ['case', 'default'],\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\tconst len = this.payload.length;\n\n\t\t\t// if (len === 1 || !this.payload.some(p => p.name === 'case')) {\n\t\t\tif (len === 1) {\n\t\t\t\treturn this.error('no cases specified');\n\t\t\t}\n\n\t\t\tlet i;\n\n\t\t\t// Sanity checks.\n\t\t\tfor (/* declared previously */ i = 1; i < len; ++i) {\n\t\t\t\tswitch (this.payload[i].name) {\n\t\t\t\tcase 'default':\n\t\t\t\t\tif (this.payload[i].args.length > 0) {\n\t\t\t\t\t\treturn this.error(`<<default>> does not accept values, invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (i + 1 !== len) {\n\t\t\t\t\t\treturn this.error('<<default>> must be the final case');\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tif (this.payload[i].args.length === 0) {\n\t\t\t\t\t\treturn this.error(`no value(s) specified for <<${this.payload[i].name}>> (#${i})`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet result;\n\n\t\t\ttry {\n\t\t\t\tresult = Scripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\tconst debugView = this.debugView; // cache it now, to be modified later\n\t\t\tlet success = false;\n\n\t\t\t// Initial debug view setup for `<<switch>>`.\n\t\t\tif (Config.debug) {\n\t\t\t\tdebugView\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true\n\t\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Evaluate the clauses.\n\t\t\tfor (/* declared previously */ i = 1; i < len; ++i) {\n\t\t\t\t// Custom debug view setup for the current case.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t.modes({ nonvoid : false });\n\t\t\t\t}\n\n\t\t\t\t// Case test(s).\n\t\t\t\tif (this.payload[i].name === 'default' || this.payload[i].args.some(val => val === result)) {\n\t\t\t\t\tsuccess = true;\n\t\t\t\t\tnew Wikifier(this.output, this.payload[i].contents);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (Config.debug) {\n\t\t\t\t\t// Custom debug view setup for a failed case.\n\t\t\t\t\tthis.debugView.modes({\n\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup for the remaining cases.\n\t\t\tif (Config.debug) {\n\t\t\t\tfor (++i; i < len; ++i) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t/*\n\t\t\t\t\tFinalize the debug view for `<<switch>>` and fake a debug view for `<</switch>>`.\n\t\t\t\t\tWe do both as a quick indicator of if any of the cases matched and the latter\n\t\t\t\t\tto aid the checking of nesting.\n\t\t\t\t*/\n\t\t\t\tdebugView\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true, // !success,\n\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t});\n\t\t\t\tthis\n\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true, // !success,\n\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<for>>, <<break>>, & <<continue>>\n\t*/\n\tMacro.add('for', {\n\t\t/* eslint-disable max-len */\n\t\tskipArgs    : true,\n\t\ttags        : null,\n\t\t_hasRangeRe : new RegExp(`^\\\\S${Patterns.anyChar}*?\\\\s+range\\\\s+\\\\S${Patterns.anyChar}*?$`),\n\t\t_rangeRe    : new RegExp(`^(?:State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})\\\\s*,\\\\s*)?State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})\\\\s+range\\\\s+(\\\\S${Patterns.anyChar}*?)$`),\n\t\t_3PartRe    : /^([^;]*?)\\s*;\\s*([^;]*?)\\s*;\\s*([^;]*?)$/,\n\t\t/* eslint-enable max-len */\n\n\t\thandler() {\n\t\t\tconst argsStr = this.args.full.trim();\n\t\t\tconst payload = this.payload[0].contents.replace(/\\n$/, '');\n\n\t\t\t// Empty form.\n\t\t\tif (argsStr.length === 0) {\n\t\t\t\tthis.self._handleFor.call(this, payload, null, true, null);\n\t\t\t}\n\n\t\t\t// Range form.\n\t\t\telse if (this.self._hasRangeRe.test(argsStr)) {\n\t\t\t\tconst parts = argsStr.match(this.self._rangeRe);\n\n\t\t\t\tif (parts === null) {\n\t\t\t\t\treturn this.error('invalid range form syntax, format: [index ,] value range collection');\n\t\t\t\t}\n\n\t\t\t\tthis.self._handleForRange.call(\n\t\t\t\t\tthis,\n\t\t\t\t\tpayload,\n\t\t\t\t\t{ type : parts[1], name : parts[2] },\n\t\t\t\t\t{ type : parts[3], name : parts[4] },\n\t\t\t\t\tparts[5]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Conditional forms.\n\t\t\telse {\n\t\t\t\tlet init;\n\t\t\t\tlet condition;\n\t\t\t\tlet post;\n\n\t\t\t\t// Conditional-only form.\n\t\t\t\tif (argsStr.indexOf(';') === -1) {\n\t\t\t\t\t// Sanity checks.\n\t\t\t\t\tif (/^\\S+\\s+in\\s+\\S+/i.test(argsStr)) {\n\t\t\t\t\t\treturn this.error('invalid syntax, for…in is not supported; see: for…range');\n\t\t\t\t\t}\n\t\t\t\t\telse if (/^\\S+\\s+of\\s+\\S+/i.test(argsStr)) {\n\t\t\t\t\t\treturn this.error('invalid syntax, for…of is not supported; see: for…range');\n\t\t\t\t\t}\n\n\t\t\t\t\tcondition = argsStr;\n\t\t\t\t}\n\n\t\t\t\t// 3-part conditional form.\n\t\t\t\telse {\n\t\t\t\t\tconst parts = argsStr.match(this.self._3PartRe);\n\n\t\t\t\t\tif (parts === null) {\n\t\t\t\t\t\treturn this.error('invalid 3-part conditional form syntax, format: [init] ; [condition] ; [post]');\n\t\t\t\t\t}\n\n\t\t\t\t\tinit      = parts[1];\n\t\t\t\t\tcondition = parts[2].trim();\n\t\t\t\t\tpost      = parts[3];\n\n\t\t\t\t\tif (condition.length === 0) {\n\t\t\t\t\t\tcondition = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis.self._handleFor.call(this, payload, init, condition, post);\n\t\t\t}\n\t\t},\n\n\t\t_handleFor(payload, init, condition, post) {\n\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\tlet first  = true;\n\t\t\tlet safety = Config.macros.maxLoopIterations;\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tTempState.break = null;\n\n\t\t\t\tif (init) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tevalJavaScript(init);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn this.error(`bad init expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\twhile (evalJavaScript(condition)) {\n\t\t\t\t\tif (--safety < 0) {\n\t\t\t\t\t\treturn this.error(`exceeded configured maximum loop iterations (${Config.macros.maxLoopIterations})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tnew Wikifier(this.output, first ? payload.replace(/^\\n/, '') : payload);\n\n\t\t\t\t\tif (first) {\n\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tif (TempState.break === 1) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (TempState.break === 2) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (post) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tevalJavaScript(post);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\treturn this.error(`bad post expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad conditional expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tTempState.break = null;\n\t\t\t}\n\t\t},\n\n\t\t_handleForRange(payload, indexVar, valueVar, rangeExp) {\n\t\t\tlet first     = true;\n\t\t\tlet rangeList;\n\n\t\t\ttry {\n\t\t\t\trangeList = this.self._toRangeList(rangeExp);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(ex.message);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tTempState.break = null;\n\n\t\t\t\tfor (let i = 0; i < rangeList.length; ++i) {\n\t\t\t\t\tif (indexVar.name) {\n\t\t\t\t\t\tState[indexVar.type][indexVar.name] = rangeList[i][0];\n\t\t\t\t\t}\n\n\t\t\t\t\tState[valueVar.type][valueVar.name] = rangeList[i][1];\n\n\t\t\t\t\tnew Wikifier(this.output, first ? payload.replace(/^\\n/, '') : payload);\n\n\t\t\t\t\tif (first) {\n\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tif (TempState.break === 1) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (TempState.break === 2) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tTempState.break = null;\n\t\t\t}\n\t\t},\n\n\t\t_toRangeList(rangeExp) {\n\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\tlet value;\n\n\t\t\ttry {\n\t\t\t\t/*\n\t\t\t\t\tNOTE: If the first character is the left curly brace, then we\n\t\t\t\t\tassume that it's part of an object literal and wrap it within\n\t\t\t\t\tparenthesis to ensure that it is not mistaken for a block\n\t\t\t\t\tduring evaluation—which would cause an error.\n\t\t\t\t*/\n\t\t\t\tvalue = evalJavaScript(rangeExp[0] === '{' ? `(${rangeExp})` : rangeExp);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tif (typeof ex !== 'object') {\n\t\t\t\t\tthrow new Error(`bad range expression: ${ex}`);\n\t\t\t\t}\n\n\t\t\t\tex.message = `bad range expression: ${ex.message}`;\n\t\t\t\tthrow ex;\n\t\t\t}\n\n\t\t\tlet list;\n\n\t\t\tswitch (typeof value) {\n\t\t\tcase 'string':\n\t\t\t\tlist = [];\n\t\t\t\tfor (let i = 0; i < value.length; /* empty */) {\n\t\t\t\t\tconst obj = Util.charAndPosAt(value, i);\n\t\t\t\t\tlist.push([i, obj.char]);\n\t\t\t\t\ti = 1 + obj.end;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'object':\n\t\t\t\tif (Array.isArray(value)) {\n\t\t\t\t\tlist = value.map((val, i) => [i, val]);\n\t\t\t\t}\n\t\t\t\telse if (value instanceof Set) {\n\t\t\t\t\tlist = [...value].map((val, i) => [i, val]);\n\t\t\t\t}\n\t\t\t\telse if (value instanceof Map) {\n\t\t\t\t\tlist = [...value.entries()];\n\t\t\t\t}\n\t\t\t\telse if (Util.toStringTag(value) === 'Object') {\n\t\t\t\t\tlist = Object.keys(value).map(key => [key, value[key]]);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new Error(`unsupported range expression type: ${Util.toStringTag(value)}`);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unsupported range expression type: ${typeof value}`);\n\t\t\t}\n\n\t\t\treturn list;\n\t\t}\n\t});\n\tMacro.add(['break', 'continue'], {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.contextHas(ctx => ctx.name === 'for')) {\n\t\t\t\tTempState.break = this.name === 'continue' ? 1 : 2;\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn this.error('must only be used in conjunction with its parent macro <<for>>');\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tInteractive Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<button>> & <<link>>\n\t*/\n\tMacro.add(['button', 'link'], {\n\t\tisAsync : true,\n\t\ttags    : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error(`no ${this.name === 'button' ? 'button' : 'link'} text specified`);\n\t\t\t}\n\n\t\t\tconst $link = jQuery(document.createElement(this.name === 'button' ? 'button' : 'a'));\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\tconst $image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t.attr('src', this.args[0].source)\n\t\t\t\t\t\t.appendTo($link);\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t}\n\n\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t$link.append(document.createTextNode(this.args[0].text));\n\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the link text.\n\t\t\t\t$link.wikiWithOptions({ profile : 'core' }, this.args[0]);\n\t\t\t\tpassage = this.args.length > 1 ? this.args[1] : undefined;\n\t\t\t}\n\n\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t$link.attr('data-passage', passage);\n\n\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t$link.addClass('link-internal');\n\n\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t$link.addClass('link-visited');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$link.addClass('link-broken');\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$link.addClass('link-internal');\n\t\t\t}\n\n\t\t\t$link\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tnamespace : '.macros',\n\t\t\t\t\tone       : passage != null // lazy equality for null\n\t\t\t\t}, this.createShadowWrapper(\n\t\t\t\t\tthis.payload[0].contents !== ''\n\t\t\t\t\t\t? () => Wikifier.wikifyEval(this.payload[0].contents.trim())\n\t\t\t\t\t\t: null,\n\t\t\t\t\tpassage != null // lazy equality for null\n\t\t\t\t\t\t? () => Engine.play(passage)\n\t\t\t\t\t\t: null\n\t\t\t\t))\n\t\t\t\t.appendTo(this.output);\n\t\t}\n\t});\n\n\t/*\n\t\t<<checkbox>>\n\t*/\n\tMacro.add('checkbox', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 3) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('unchecked value'); }\n\t\t\t\tif (this.args.length < 3) { errors.push('checked value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst uncheckValue = this.args[1];\n\t\t\tconst checkValue   = this.args[2];\n\t\t\tconst el           = document.createElement('input');\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'checkbox',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.checked ? checkValue : uncheckValue);\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and input element to the appropriate value and state, as requested.\n\t\t\t*/\n\t\t\tif (this.args.length > 3 && this.args[3] === 'checked') {\n\t\t\t\tel.checked = true;\n\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tState.setVar(varName, uncheckValue);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<cycle>>, <<listbox>>, <<option>>, & <<optionsfrom>>\n\t*/\n\tMacro.add(['cycle', 'listbox'], {\n\t\tisAsync  : true,\n\t\tskipArgs : ['optionsfrom'],\n\t\ttags     : ['option', 'optionsfrom'],\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no variable name specified');\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId = Util.slugify(varName);\n\t\t\tconst len   = this.payload.length;\n\n\t\t\tif (len === 1) {\n\t\t\t\treturn this.error('no options specified');\n\t\t\t}\n\n\t\t\tconst autoselect = this.args.length > 1 && this.args[1] === 'autoselect';\n\t\t\tconst options    = [];\n\t\t\tconst tagCount   = { option : 0, optionsfrom : 0 };\n\t\t\tlet selectedIdx = -1;\n\n\t\t\t// Get the options and selected index, if any.\n\t\t\tfor (let i = 1; i < len; ++i) {\n\t\t\t\tconst payload = this.payload[i];\n\n\t\t\t\t// <<option label value [selected]>>\n\t\t\t\tif (payload.name === 'option') {\n\t\t\t\t\t++tagCount.option;\n\n\t\t\t\t\tif (payload.args.length === 0) {\n\t\t\t\t\t\treturn this.error(`no arguments specified for <<${payload.name}>> (#${tagCount.option})`);\n\t\t\t\t\t}\n\n\t\t\t\t\toptions.push({\n\t\t\t\t\t\tlabel : String(payload.args[0]),\n\t\t\t\t\t\tvalue : payload.args.length === 1 ? payload.args[0] : payload.args[1]\n\t\t\t\t\t});\n\n\t\t\t\t\tif (payload.args.length > 2 && payload.args[2] === 'selected') {\n\t\t\t\t\t\tif (autoselect) {\n\t\t\t\t\t\t\treturn this.error('cannot specify both the autoselect and selected keywords');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (selectedIdx !== -1) {\n\t\t\t\t\t\t\treturn this.error(`multiple selected keywords specified for <<${payload.name}>> (#${selectedIdx + 1} & #${tagCount.option})`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tselectedIdx = options.length - 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// <<optionsfrom expression>>\n\t\t\t\telse {\n\t\t\t\t\t++tagCount.optionsfrom;\n\n\t\t\t\t\tif (payload.args.full.length === 0) {\n\t\t\t\t\t\treturn this.error(`no expression specified for <<${payload.name}>> (#${tagCount.optionsfrom})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: If the first character is the left curly brace, then we\n\t\t\t\t\t\t\tassume that it's part of an object literal and wrap it within\n\t\t\t\t\t\t\tparenthesis to ensure that it is not mistaken for a block\n\t\t\t\t\t\t\tduring evaluation—which would cause an error.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tconst exp = payload.args.full;\n\t\t\t\t\t\tresult = Scripting.evalJavaScript(exp[0] === '{' ? `(${exp})` : exp);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (typeof result !== 'object' || result === null) {\n\t\t\t\t\t\treturn this.error(`expression must yield a supported collection or generic object (type: ${result === null ? 'null' : typeof result})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (result instanceof Array || result instanceof Set) {\n\t\t\t\t\t\tresult.forEach(val => options.push({ label : String(val), value : val }));\n\t\t\t\t\t}\n\t\t\t\t\telse if (result instanceof Map) {\n\t\t\t\t\t\tresult.forEach((val, key) => options.push({ label : String(key), value : val }));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tconst oType = Util.toStringTag(result);\n\n\t\t\t\t\t\tif (oType !== 'Object') {\n\t\t\t\t\t\t\treturn this.error(`expression must yield a supported collection or generic object (object type: ${oType})`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tObject.keys(result).forEach(key => options.push({ label : key, value : result[key] }));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// No options were selected by the user, so we must select one.\n\t\t\tif (selectedIdx === -1) {\n\t\t\t\t// Attempt to automatically select an option by matching the variable's current value.\n\t\t\t\tif (autoselect) {\n\t\t\t\t\t// NOTE: This will usually fail for objects due to a variety of reasons.\n\t\t\t\t\tconst sameValueZero = Util.sameValueZero;\n\t\t\t\t\tconst curValue      = State.getVar(varName);\n\t\t\t\t\tconst curValueIdx   = options.findIndex(opt => sameValueZero(opt.value, curValue));\n\t\t\t\t\tselectedIdx = curValueIdx === -1 ? 0 : curValueIdx;\n\t\t\t\t}\n\n\t\t\t\t// Simply select the first option.\n\t\t\t\telse {\n\t\t\t\t\tselectedIdx = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set up and append the appropriate element to the output buffer.\n\t\t\tif (this.name === 'cycle') {\n\t\t\t\tlet cycleIdx = selectedIdx;\n\t\t\t\tjQuery(document.createElement('a'))\n\t\t\t\t\t.wikiWithOptions({ profile : 'core' }, options[selectedIdx].label)\n\t\t\t\t\t.attr('id', `${this.name}-${varId}`)\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.ariaClick({ namespace : '.macros' }, this.createShadowWrapper(function () {\n\t\t\t\t\t\tcycleIdx = (cycleIdx + 1) % options.length;\n\t\t\t\t\t\t$(this).empty().wikiWithOptions({ profile : 'core' }, options[cycleIdx].label);\n\t\t\t\t\t\tState.setVar(varName, options[cycleIdx].value);\n\t\t\t\t\t}))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\t\t\telse { // this.name === 'listbox'\n\t\t\t\tconst $select = jQuery(document.createElement('select'));\n\n\t\t\t\toptions.forEach((opt, i) => {\n\t\t\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t\t\t.val(i)\n\t\t\t\t\t\t.text(opt.label)\n\t\t\t\t\t\t.appendTo($select);\n\t\t\t\t});\n\n\t\t\t\t$select\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t\t})\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.val(selectedIdx)\n\t\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\t\tState.setVar(varName, options[Number(this.value)].value);\n\t\t\t\t\t}))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\n\t\t\t// Set the variable to the appropriate value, as requested.\n\t\t\tState.setVar(varName, options[selectedIdx].value);\n\t\t}\n\t});\n\n\t/*\n\t\t<<linkappend>>, <<linkprepend>>, & <<linkreplace>>\n\t*/\n\tMacro.add(['linkappend', 'linkprepend', 'linkreplace'], {\n\t\tisAsync : true,\n\t\ttags    : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no link text specified');\n\t\t\t}\n\n\t\t\tconst $link      = jQuery(document.createElement('a'));\n\t\t\tconst $insert    = jQuery(document.createElement('span'));\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\n\t\t\t$link\n\t\t\t\t.wikiWithOptions({ profile : 'core' }, this.args[0])\n\t\t\t\t.addClass(`link-internal macro-${this.name}`)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tnamespace : '.macros',\n\t\t\t\t\tone       : true\n\t\t\t\t}, this.createShadowWrapper(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tif (this.name === 'linkreplace') {\n\t\t\t\t\t\t\t$link.remove();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t$link\n\t\t\t\t\t\t\t\t.wrap(`<span class=\"macro-${this.name}\"></span>`)\n\t\t\t\t\t\t\t\t.replaceWith(() => $link.html());\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.payload[0].contents !== '') {\n\t\t\t\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\t\t\t\tnew Wikifier(frag, this.payload[0].contents);\n\t\t\t\t\t\t\t$insert.append(frag);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (transition) {\n\t\t\t\t\t\t\tsetTimeout(() => $insert.removeClass(`macro-${this.name}-in`), Engine.minDomActionDelay);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t$insert.addClass(`macro-${this.name}-insert`);\n\n\t\t\tif (transition) {\n\t\t\t\t$insert.addClass(`macro-${this.name}-in`);\n\t\t\t}\n\n\t\t\tif (this.name === 'linkprepend') {\n\t\t\t\t$insert.insertBefore($link);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$insert.insertAfter($link);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<radiobutton>>\n\t*/\n\tMacro.add('radiobutton', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('checked value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId      = Util.slugify(varName);\n\t\t\tconst checkValue = this.args[1];\n\t\t\tconst el         = document.createElement('input');\n\n\t\t\t/*\n\t\t\t\tSet up and initialize the group counter.\n\t\t\t*/\n\t\t\tif (!TempState.hasOwnProperty(this.name)) {\n\t\t\t\tTempState[this.name] = {};\n\t\t\t}\n\n\t\t\tif (!TempState[this.name].hasOwnProperty(varId)) {\n\t\t\t\tTempState[this.name][varId] = 0;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}-${TempState[this.name][varId]++}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'radio',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tif (this.checked) {\n\t\t\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable to the checked value and the input element to checked, if requested.\n\t\t\t*/\n\t\t\tif (this.args.length > 2 && this.args[2] === 'checked') {\n\t\t\t\tel.checked = true;\n\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<textarea>>\n\t*/\n\tMacro.add('textarea', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('default value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst defaultValue = this.args[1];\n\t\t\tconst autofocus    = this.args[2] === 'autofocus';\n\t\t\tconst el           = document.createElement('textarea');\n\n\t\t\t/*\n\t\t\t\tSet up and append the textarea element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\trows     : 4,\n\t\t\t\t\t// cols     : 68, // instead of setting \"cols\" we set the `min-width` in CSS\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.value);\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and textarea element to the default value.\n\t\t\t*/\n\t\t\tState.setVar(varName, defaultValue);\n\t\t\t// Ideally, we should be setting `.defaultValue` here, but IE doesn't support it,\n\t\t\t// so we have to use `.textContent`, which is equivalent.\n\t\t\tel.textContent = defaultValue;\n\n\t\t\t/*\n\t\t\t\tAutofocus the textarea element, if requested.\n\t\t\t*/\n\t\t\tif (autofocus) {\n\t\t\t\t// Set the element's \"autofocus\" attribute.\n\t\t\t\tel.setAttribute('autofocus', 'autofocus');\n\n\t\t\t\t// Set up a single-use post-display task to autofocus the element.\n\t\t\t\tpostdisplay[`#autofocus:${el.id}`] = task => {\n\t\t\t\t\tdelete postdisplay[task]; // single-use task\n\t\t\t\t\tsetTimeout(() => el.focus(), Engine.minDomActionDelay);\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<textbox>>\n\t*/\n\tMacro.add('textbox', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('default value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst defaultValue = this.args[1];\n\t\t\tconst el           = document.createElement('input');\n\t\t\tlet autofocus = false;\n\t\t\tlet passage;\n\n\t\t\tif (this.args.length > 3) {\n\t\t\t\tpassage   = this.args[2];\n\t\t\t\tautofocus = this.args[3] === 'autofocus';\n\t\t\t}\n\t\t\telse if (this.args.length > 2) {\n\t\t\t\tif (this.args[2] === 'autofocus') {\n\t\t\t\t\tautofocus = true;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tpassage = this.args[2];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (typeof passage === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = passage.link;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'text',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.value);\n\t\t\t\t}))\n\t\t\t\t.on('keypress.macros', this.createShadowWrapper(function (ev) {\n\t\t\t\t\t// If Return/Enter is pressed, set the variable and, optionally, forward to another passage.\n\t\t\t\t\tif (ev.which === 13) { // 13 is Return/Enter\n\t\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t\tState.setVar(varName, this.value);\n\n\t\t\t\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and input element to the default value.\n\t\t\t*/\n\t\t\tState.setVar(varName, defaultValue);\n\t\t\tel.value = defaultValue;\n\n\t\t\t/*\n\t\t\t\tAutofocus the input element, if requested.\n\t\t\t*/\n\t\t\tif (autofocus) {\n\t\t\t\t// Set the element's \"autofocus\" attribute.\n\t\t\t\tel.setAttribute('autofocus', 'autofocus');\n\n\t\t\t\t// Set up a single-use post-display task to autofocus the element.\n\t\t\t\tpostdisplay[`#autofocus:${el.id}`] = task => {\n\t\t\t\t\tdelete postdisplay[task]; // single-use task\n\t\t\t\t\tsetTimeout(() => el.focus(), Engine.minDomActionDelay);\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] <<click>>\n\t*/\n\tMacro.add('click', 'link'); // add <<click>> as an alias of <<link>>\n\n\n\t/*******************************************************************************************************************\n\t\tLinks Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<actions>>\n\t*/\n\tMacro.add('actions', {\n\t\thandler() {\n\t\t\tconst $list = jQuery(document.createElement('ul'))\n\t\t\t\t.addClass(this.name)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\tfor (let i = 0; i < this.args.length; ++i) {\n\t\t\t\tlet passage;\n\t\t\t\tlet text;\n\t\t\t\tlet $image;\n\t\t\t\tlet setFn;\n\n\t\t\t\tif (typeof this.args[i] === 'object') {\n\t\t\t\t\tif (this.args[i].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[i].source);\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[i].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[i].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[i].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tpassage = this.args[i].link;\n\t\t\t\t\t\tsetFn   = this.args[i].setFn;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\ttext    = this.args[i].text;\n\t\t\t\t\t\tpassage = this.args[i].link;\n\t\t\t\t\t\tsetFn   = this.args[i].setFn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\ttext = passage = this.args[i];\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\t   State.variables.hasOwnProperty('#actions')\n\t\t\t\t\t&& State.variables['#actions'].hasOwnProperty(passage)\n\t\t\t\t\t&& State.variables['#actions'][passage]\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tjQuery(Wikifier.createInternalLink(\n\t\t\t\t\tjQuery(document.createElement('li')).appendTo($list),\n\t\t\t\t\tpassage,\n\t\t\t\t\tnull,\n\t\t\t\t\t((passage, fn) => () => {\n\t\t\t\t\t\tif (!State.variables.hasOwnProperty('#actions')) {\n\t\t\t\t\t\t\tState.variables['#actions'] = {};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tState.variables['#actions'][passage] = true;\n\n\t\t\t\t\t\tif (typeof fn === 'function') {\n\t\t\t\t\t\t\tfn();\n\t\t\t\t\t\t}\n\t\t\t\t\t})(passage, setFn)\n\t\t\t\t))\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.append($image || document.createTextNode(text));\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<back>> & <<return>>\n\t*/\n\tMacro.add(['back', 'return'], {\n\t\thandler() {\n\t\t\t/* legacy */\n\t\t\tif (this.args.length > 1) {\n\t\t\t\treturn this.error('too many arguments specified, check the documentation for details');\n\t\t\t}\n\t\t\t/* /legacy */\n\n\t\t\tlet momentIndex = -1;\n\t\t\tlet passage;\n\t\t\tlet text;\n\t\t\tlet $image;\n\n\t\t\tif (this.args.length === 1) {\n\t\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[0].source);\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('link')) {\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\tif (this.args[0].count === 1) {\n\t\t\t\t\t\t\t// Simple link syntax: `[[...]]`.\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Pretty link syntax: `[[...|...]]`.\n\t\t\t\t\t\t\ttext    = this.args[0].text;\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (this.args.length === 1) {\n\t\t\t\t\t// Argument was simply the link text.\n\t\t\t\t\ttext = this.args[0];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\t/*\n\t\t\t\t\tFind the index and title of the most recent moment whose title does not match\n\t\t\t\t\tthat of the active (present) moment's.\n\t\t\t\t*/\n\t\t\t\tfor (let i = State.length - 2; i >= 0; --i) {\n\t\t\t\t\tif (State.history[i].title !== State.passage) {\n\t\t\t\t\t\tmomentIndex = i;\n\t\t\t\t\t\tpassage = State.history[i].title;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If we failed to find a passage and we're `<<return>>`, fallback to `State.expired`.\n\t\t\t\tif (passage == null && this.name === 'return') { // lazy equality for null\n\t\t\t\t\tfor (let i = State.expired.length - 1; i >= 0; --i) {\n\t\t\t\t\t\tif (State.expired[i] !== State.passage) {\n\t\t\t\t\t\t\tpassage = State.expired[i];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (!Story.has(passage)) {\n\t\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tif (this.name === 'back') {\n\t\t\t\t\t/*\n\t\t\t\t\t\tFind the index of the most recent moment whose title matches that of the\n\t\t\t\t\t\tspecified passage.\n\t\t\t\t\t*/\n\t\t\t\t\tfor (let i = State.length - 2; i >= 0; --i) {\n\t\t\t\t\t\tif (State.history[i].title === passage) {\n\t\t\t\t\t\t\tmomentIndex = i;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (momentIndex === -1) {\n\t\t\t\t\t\treturn this.error(`cannot find passage \"${passage}\" in the current story history`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn this.error('cannot find passage');\n\t\t\t}\n\n\t\t\t// if (this.name === \"back\" && momentIndex === -1) {\n\t\t\t// \t// no-op; we're already at the first passage in the current story history\n\t\t\t// \treturn;\n\t\t\t// }\n\n\t\t\tlet $el;\n\n\t\t\tif (this.name !== 'back' || momentIndex !== -1) {\n\t\t\t\t$el = jQuery(document.createElement('a'))\n\t\t\t\t\t.addClass('link-internal')\n\t\t\t\t\t.ariaClick(\n\t\t\t\t\t\t{ one : true },\n\t\t\t\t\t\tthis.name === 'return'\n\t\t\t\t\t\t\t? () => Engine.play(passage)\n\t\t\t\t\t\t\t: () => Engine.goTo(momentIndex)\n\t\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$el = jQuery(document.createElement('span'))\n\t\t\t\t\t.addClass('link-disabled');\n\t\t\t}\n\n\t\t\t$el\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.append($image || document.createTextNode(text || L10n.get(`macro${this.name.toUpperFirst()}Text`)))\n\t\t\t\t.appendTo(this.output);\n\t\t}\n\t});\n\n\t/*\n\t\t<<choice>>\n\t*/\n\tMacro.add('choice', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tconst choiceId = State.passage;\n\t\t\tlet passage;\n\t\t\tlet text;\n\t\t\tlet $image;\n\t\t\tlet setFn;\n\n\t\t\tif (this.args.length === 1) {\n\t\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[0].source);\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\tsetFn   = this.args[0].setFn;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\ttext    = this.args[0].text;\n\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\tsetFn   = this.args[0].setFn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\ttext = passage = this.args[0];\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// NOTE: The arguments here are backwards.\n\t\t\t\tpassage = this.args[0];\n\t\t\t\ttext    = this.args[1];\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t   State.variables.hasOwnProperty('#choice')\n\t\t\t\t&& State.variables['#choice'].hasOwnProperty(choiceId)\n\t\t\t\t&& State.variables['#choice'][choiceId]\n\t\t\t) {\n\t\t\t\tjQuery(document.createElement('span'))\n\t\t\t\t\t.addClass(`link-disabled macro-${this.name}`)\n\t\t\t\t\t.attr('tabindex', -1)\n\t\t\t\t\t.append($image || document.createTextNode(text))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tjQuery(Wikifier.createInternalLink(this.output, passage, null, () => {\n\t\t\t\tif (!State.variables.hasOwnProperty('#choice')) {\n\t\t\t\t\tState.variables['#choice'] = {};\n\t\t\t\t}\n\n\t\t\t\tState.variables['#choice'][choiceId] = true;\n\n\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\tsetFn();\n\t\t\t\t}\n\t\t\t}))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.append($image || document.createTextNode(text));\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tDOM Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<addclass>> & <<toggleclass>>\n\t*/\n\tMacro.add(['addclass', 'toggleclass'], {\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('selector'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('class names'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tswitch (this.name) {\n\t\t\tcase 'addclass':\n\t\t\t\t$targets.addClass(this.args[1].trim());\n\t\t\t\tbreak;\n\n\t\t\tcase 'toggleclass':\n\t\t\t\t$targets.toggleClass(this.args[1].trim());\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<removeclass>>\n\t*/\n\tMacro.add('removeclass', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tif (this.args.length > 1) {\n\t\t\t\t$targets.removeClass(this.args[1].trim());\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$targets.removeClass();\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<copy>>\n\t*/\n\tMacro.add('copy', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tjQuery(this.output).append($targets.html());\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<append>>, <<prepend>>, & <<replace>>\n\t*/\n\tMacro.add(['append', 'prepend', 'replace'], {\n\t\ttags : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tif (this.payload[0].contents !== '') {\n\t\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\t\tlet $insert;\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$insert = jQuery(document.createElement('span'));\n\t\t\t\t\t$insert.addClass(`macro-${this.name}-insert macro-${this.name}-in`);\n\t\t\t\t\tsetTimeout(() => $insert.removeClass(`macro-${this.name}-in`), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$insert = jQuery(document.createDocumentFragment());\n\t\t\t\t}\n\n\t\t\t\t$insert.wiki(this.payload[0].contents);\n\n\t\t\t\tswitch (this.name) {\n\t\t\t\tcase 'replace':\n\t\t\t\t\t$targets.empty();\n\t\t\t\t\t/* falls through */\n\n\t\t\t\tcase 'append':\n\t\t\t\t\t$targets.append($insert);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'prepend':\n\t\t\t\t\t$targets.prepend($insert);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (this.name === 'replace') {\n\t\t\t\t$targets.empty();\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<remove>>\n\t*/\n\tMacro.add('remove', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\t$targets.remove();\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAudio Macros.\n\t*******************************************************************************************************************/\n\tif (Has.audio) {\n\t\tconst errorOnePlaybackAction = (cur, prev) => `only one playback action allowed per invocation, \"${cur}\" cannot be combined with \"${prev}\"`;\n\n\t\t/*\n\t\t\t<<audio>>\n\t\t*/\n\t\tMacro.add('audio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\tconst errors = [];\n\t\t\t\t\tif (this.args.length < 1) { errors.push('track and/or group IDs'); }\n\t\t\t\t\tif (this.args.length < 2) { errors.push('actions'); }\n\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t}\n\n\t\t\t\tlet selected;\n\n\t\t\t\t// Process the track and/or group IDs.\n\t\t\t\ttry {\n\t\t\t\t\tselected = SimpleAudio.select(this.args[0]);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\tconst args = this.args.slice(1);\n\t\t\t\tlet action;\n\t\t\t\tlet fadeOver = 5;\n\t\t\t\tlet fadeTo;\n\t\t\t\tlet loop;\n\t\t\t\tlet mute;\n\t\t\t\tlet passage;\n\t\t\t\tlet time;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\tcase 'play':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadein':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 1;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeout':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 0;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('fadeto missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeoverto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length < 2) {\n\t\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\t\tif (args.length < 1) { errors.push('seconds'); }\n\t\t\t\t\t\t\tif (args.length < 2) { errors.push('level'); }\n\t\t\t\t\t\t\treturn this.error(`fadeoverto missing required ${errors.join(' and ')} value${errors.length > 1 ? 's' : ''}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeOver = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeOver) || !Number.isFinite(fadeOver)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'time':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('time missing required seconds value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\ttime = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(time) || !Number.isFinite(time)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse time: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'loop':\n\t\t\t\t\tcase 'unloop':\n\t\t\t\t\t\tloop = arg === 'loop';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'goto':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('goto missing required passage title');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\n\t\t\t\t\t\tif (typeof raw === 'object') {\n\t\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\t\tpassage = raw.link;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\t\t\tpassage = raw;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!Story.has(passage)) {\n\t\t\t\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tselected.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (time != null) { // lazy equality for null\n\t\t\t\t\t\tselected.time(time);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tselected.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (loop != null) { // lazy equality for null\n\t\t\t\t\t\tselected.loop(loop);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t\t\tconst nsEnded = `ended.macros.macro-${this.name}_goto`;\n\t\t\t\t\t\tselected\n\t\t\t\t\t\t\t.off(nsEnded)\n\t\t\t\t\t\t\t.one(nsEnded, () => {\n\t\t\t\t\t\t\t\tselected.off(nsEnded);\n\t\t\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'fade':\n\t\t\t\t\t\tselected.fade(fadeOver, fadeTo);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tselected.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\t\tselected.pause();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'play':\n\t\t\t\t\t\tselected.playWhenAllowed();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tselected.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tselected.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<cacheaudio track_id source_list>>\n\t\t*/\n\t\tMacro.add('cacheaudio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\tconst errors = [];\n\t\t\t\t\tif (this.args.length < 1) { errors.push('track ID'); }\n\t\t\t\t\tif (this.args.length < 2) { errors.push('sources'); }\n\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t}\n\n\t\t\t\tconst id       = String(this.args[0]).trim();\n\t\t\t\tconst oldFmtRe = /^format:\\s*([\\w-]+)\\s*;\\s*/i;\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.tracks.add(id, this.args.slice(1).map(source => {\n\t\t\t\t\t\t/* legacy */\n\t\t\t\t\t\t// Transform an old format specifier into the new style.\n\t\t\t\t\t\tif (oldFmtRe.test(source)) {\n\t\t\t\t\t\t\t// If in Test Mode, return an error.\n\t\t\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\t\t\treturn this.error(`track ID \"${id}\": format specifier migration required, \"format:formatId;\" \\u2192 \"formatId|\"`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tsource = source.replace(oldFmtRe, '$1|'); // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn source;\n\t\t\t\t\t\t/* /legacy */\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// If in Test Mode and no supported sources were specified, return an error.\n\t\t\t\tif (Config.debug && !SimpleAudio.tracks.get(id).hasSource()) {\n\t\t\t\t\treturn this.error(`track ID \"${id}\": no supported audio sources found`);\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<createaudiogroup group_id>>\n\t\t\t\t<<track track_id>>\n\t\t\t\t…\n\t\t\t<</createaudiogroup>>\n\t\t*/\n\t\tMacro.add('createaudiogroup', {\n\t\t\ttags : ['track'],\n\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no group ID specified');\n\t\t\t\t}\n\n\t\t\t\tif (this.payload.length === 1) {\n\t\t\t\t\treturn this.error('no tracks defined via <<track>>');\n\t\t\t\t}\n\n\t\t\t\t// Initial debug view setup for `<<createaudiogroup>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst groupId  = String(this.args[0]).trim();\n\t\t\t\tconst trackIds = [];\n\n\t\t\t\tfor (let i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\tif (this.payload[i].args.length < 1) {\n\t\t\t\t\t\treturn this.error('no track ID specified');\n\t\t\t\t\t}\n\n\t\t\t\t\ttrackIds.push(String(this.payload[i].args[0]).trim());\n\n\t\t\t\t\t// Custom debug view setup for the current `<<track>>`.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.groups.add(groupId, trackIds);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Custom fake debug view setup for `<</createaudiogroup>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<createplaylist list_id>>\n\t\t\t\t<<track track_id action_list>>\n\t\t\t\t…\n\t\t\t<</createplaylist>>\n\t\t*/\n\t\tMacro.add('createplaylist', {\n\t\t\ttags : ['track'],\n\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no list ID specified');\n\t\t\t\t}\n\n\t\t\t\tif (this.payload.length === 1) {\n\t\t\t\t\treturn this.error('no tracks defined via <<track>>');\n\t\t\t\t}\n\n\t\t\t\tconst playlist = Macro.get('playlist');\n\n\t\t\t\tif (playlist.from !== null && playlist.from !== 'createplaylist') {\n\t\t\t\t\treturn this.error('a playlist has already been defined with <<setplaylist>>');\n\t\t\t\t}\n\n\t\t\t\t// Initial debug view setup for `<<createplaylist>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst listId    = String(this.args[0]).trim();\n\t\t\t\tconst trackObjs = [];\n\n\t\t\t\tfor (let i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\tif (this.payload[i].args.length === 0) {\n\t\t\t\t\t\treturn this.error('no track ID specified');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst trackObj = { id : String(this.payload[i].args[0]).trim() };\n\t\t\t\t\tconst args     = this.payload[i].args.slice(1);\n\n\t\t\t\t\t// Process arguments.\n\t\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\t\tlet raw;\n\t\t\t\t\t\tlet parsed;\n\n\t\t\t\t\t\tswitch (arg) {\n\t\t\t\t\t\tcase 'copy': // [DEPRECATED]\n\t\t\t\t\t\tcase 'own':\n\t\t\t\t\t\t\ttrackObj.own = true;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'rate':\n\t\t\t\t\t\t\t// if (args.length === 0) {\n\t\t\t\t\t\t\t// \treturn this.error('rate missing required speed value');\n\t\t\t\t\t\t\t// }\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// raw = args.shift();\n\t\t\t\t\t\t\t// parsed = Number.parseFloat(raw);\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// if (Number.isNaN(parsed) || !Number.isFinite(parsed)) {\n\t\t\t\t\t\t\t// \treturn this.error(`cannot parse rate: ${raw}`);\n\t\t\t\t\t\t\t// }\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// trackObj.rate = parsed;\n\t\t\t\t\t\t\tif (args.length > 0) {\n\t\t\t\t\t\t\t\targs.shift();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\t\tparsed = Number.parseFloat(raw);\n\n\t\t\t\t\t\t\tif (Number.isNaN(parsed) || !Number.isFinite(parsed)) {\n\t\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ttrackObj.volume = parsed;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\ttrackObjs.push(trackObj);\n\n\t\t\t\t\t// Custom debug view setup for the current `<<track>>`.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.lists.add(listId, trackObjs);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Lock `<<playlist>>` into our syntax.\n\t\t\t\tif (playlist.from === null) {\n\t\t\t\t\tplaylist.from = 'createplaylist';\n\t\t\t\t}\n\n\t\t\t\t// Custom fake debug view setup for `<</createplaylist>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<masteraudio action_list>>\n\t\t*/\n\t\tMacro.add('masteraudio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no actions specified');\n\t\t\t\t}\n\n\t\t\t\tconst args = this.args.slice(0);\n\t\t\t\tlet action;\n\t\t\t\tlet mute;\n\t\t\t\tlet muteOnHide;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'muteonhide':\n\t\t\t\t\tcase 'nomuteonhide':\n\t\t\t\t\t\tmuteOnHide = arg === 'muteonhide';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (muteOnHide != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.muteOnHidden(muteOnHide);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tSimpleAudio.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tSimpleAudio.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tSimpleAudio.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<playlist list_id action_list>>  ← <<createplaylist>> syntax\n\t\t\t<<playlist action_list>>          ← <<setplaylist>> syntax\n\t\t*/\n\t\tMacro.add('playlist', {\n\t\t\tfrom : null,\n\n\t\t\thandler() {\n\t\t\t\tconst from = this.self.from;\n\n\t\t\t\tif (from === null) {\n\t\t\t\t\treturn this.error('no playlists have been created');\n\t\t\t\t}\n\n\t\t\t\tlet list;\n\t\t\t\tlet args;\n\n\t\t\t\tif (from === 'createplaylist') {\n\t\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\tif (this.args.length < 1) { errors.push('list ID'); }\n\t\t\t\t\t\tif (this.args.length < 2) { errors.push('actions'); }\n\t\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\t\tif (!SimpleAudio.lists.has(id)) {\n\t\t\t\t\t\treturn this.error(`playlist \"${id}\" does not exist`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlist = SimpleAudio.lists.get(id);\n\t\t\t\t\targs = this.args.slice(1);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\t\treturn this.error('no actions specified');\n\t\t\t\t\t}\n\n\t\t\t\t\tlist = SimpleAudio.lists.get('setplaylist');\n\t\t\t\t\targs = this.args.slice(0);\n\t\t\t\t}\n\n\t\t\t\tlet action;\n\t\t\t\tlet fadeOver = 5;\n\t\t\t\tlet fadeTo;\n\t\t\t\tlet loop;\n\t\t\t\tlet mute;\n\t\t\t\tlet shuffle;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\tcase 'play':\n\t\t\t\t\tcase 'skip':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadein':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 1;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeout':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 0;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('fadeto missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeoverto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length < 2) {\n\t\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\t\tif (args.length < 1) { errors.push('seconds'); }\n\t\t\t\t\t\t\tif (args.length < 2) { errors.push('level'); }\n\t\t\t\t\t\t\treturn this.error(`fadeoverto missing required ${errors.join(' and ')} value${errors.length > 1 ? 's' : ''}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeOver = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeOver) || !Number.isFinite(fadeOver)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'loop':\n\t\t\t\t\tcase 'unloop':\n\t\t\t\t\t\tloop = arg === 'loop';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'shuffle':\n\t\t\t\t\tcase 'unshuffle':\n\t\t\t\t\t\tshuffle = arg === 'shuffle';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tlist.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tlist.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (loop != null) { // lazy equality for null\n\t\t\t\t\t\tlist.loop(loop);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (shuffle != null) { // lazy equality for null\n\t\t\t\t\t\tlist.shuffle(shuffle);\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'fade':\n\t\t\t\t\t\tlist.fade(fadeOver, fadeTo);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tlist.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\t\tlist.pause();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'play':\n\t\t\t\t\t\tlist.playWhenAllowed();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'skip':\n\t\t\t\t\t\tlist.skip();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tlist.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tlist.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<removeaudiogroup group_id>>\n\t\t*/\n\t\tMacro.add('removeaudiogroup', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no group ID specified');\n\t\t\t\t}\n\n\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\tif (!SimpleAudio.groups.has(id)) {\n\t\t\t\t\treturn this.error(`group \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tSimpleAudio.groups.delete(id);\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<removeplaylist list_id>>\n\t\t*/\n\t\tMacro.add('removeplaylist', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no list ID specified');\n\t\t\t\t}\n\n\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\tif (!SimpleAudio.lists.has(id)) {\n\t\t\t\t\treturn this.error(`playlist \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tSimpleAudio.lists.delete(id);\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<waitforaudio>>\n\t\t*/\n\t\tMacro.add('waitforaudio', {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\tSimpleAudio.loadWithScreen();\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t[DEPRECATED] <<setplaylist track_id_list>>\n\t\t*/\n\t\tMacro.add('setplaylist', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no track ID(s) specified');\n\t\t\t\t}\n\n\t\t\t\tconst playlist = Macro.get('playlist');\n\n\t\t\t\tif (playlist.from !== null && playlist.from !== 'setplaylist') {\n\t\t\t\t\treturn this.error('playlists have already been defined with <<createplaylist>>');\n\t\t\t\t}\n\n\t\t\t\t// Create the new playlist.\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.lists.add('setplaylist', this.args.slice(0));\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Lock `<<playlist>>` into our syntax.\n\t\t\t\tif (playlist.from === null) {\n\t\t\t\t\tplaylist.from = 'setplaylist';\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t[DEPRECATED] <<stopallaudio>>\n\t\t*/\n\t\tMacro.add('stopallaudio', {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\tSimpleAudio.select(':all').stop();\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\telse {\n\t\t/* The HTML5 <audio> API appears to be missing or disabled, set up no-op macros. */\n\t\tMacro.add([\n\t\t\t'audio',\n\t\t\t'cacheaudio',\n\t\t\t'createaudiogroup',\n\t\t\t'createplaylist',\n\t\t\t'masteraudio',\n\t\t\t'playlist',\n\t\t\t'removeaudiogroup',\n\t\t\t'removeplaylist',\n\t\t\t'waitforaudio',\n\n\t\t\t// Deprecated.\n\t\t\t'setplaylist',\n\t\t\t'stopallaudio'\n\t\t], {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\t/* no-op */\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMiscellaneous Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<goto>>\n\t*/\n\tMacro.add('goto', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = this.args[0].link;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the passage name.\n\t\t\t\tpassage = this.args[0];\n\t\t\t}\n\n\t\t\tif (!Story.has(passage)) {\n\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tCall `Engine.play()` asynchronously.\n\n\t\t\t\tNOTE: This does not terminate the current Wikifier call chain,\n\t\t\t\tthough, ideally, it should.  Doing so would not be trivial, however,\n\t\t\t\tand there's also the question of whether that behavior would be\n\t\t\t\tunwanted by users, who are used to the current behavior from\n\t\t\t\tsimilar macros and constructs.\n\t\t\t*/\n\t\t\tsetTimeout(() => Engine.play(passage), Engine.minDomActionDelay);\n\t\t}\n\t});\n\n\t/*\n\t\t<<repeat>> & <<stop>>\n\t*/\n\tMacro.add('repeat', {\n\t\tisAsync : true,\n\t\ttags    : null,\n\t\ttimers  : new Set(),\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no time value specified');\n\t\t\t}\n\n\t\t\tlet delay;\n\n\t\t\ttry {\n\t\t\t\tdelay = Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.args[0]));\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(ex.message);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\tconst $wrapper   = jQuery(document.createElement('span'))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t// Register the timer.\n\t\t\tthis.self.registerInterval(this.createShadowWrapper(() => {\n\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(frag, this.payload[0].contents);\n\n\t\t\t\tlet $output = $wrapper;\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$output = jQuery(document.createElement('span'))\n\t\t\t\t\t\t.addClass('macro-repeat-insert macro-repeat-in')\n\t\t\t\t\t\t.appendTo($output);\n\t\t\t\t}\n\n\t\t\t\t$output.append(frag);\n\n\t\t\t\tif (transition) {\n\t\t\t\t\tsetTimeout(() => $output.removeClass('macro-repeat-in'), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t}), delay);\n\t\t},\n\n\t\tregisterInterval(callback, delay) {\n\t\t\tif (typeof callback !== 'function') {\n\t\t\t\tthrow new TypeError('callback parameter must be a function');\n\t\t\t}\n\n\t\t\tconst turnId = State.turns;\n\t\t\tconst timers = this.timers;\n\t\t\tlet timerId = null;\n\n\t\t\t// Set up the interval.\n\t\t\ttimerId = setInterval(() => {\n\t\t\t\t// Terminate the timer if the turn IDs do not match.\n\t\t\t\tif (turnId !== State.turns) {\n\t\t\t\t\tclearInterval(timerId);\n\t\t\t\t\ttimers.delete(timerId);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet timerIdCache;\n\t\t\t\t/*\n\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t`Wikifier` call.\n\t\t\t\t*/\n\t\t\t\ttry {\n\t\t\t\t\tTempState.break = null;\n\n\t\t\t\t\t// Set up the `repeatTimerId` value, caching the existing value, if necessary.\n\t\t\t\t\tif (TempState.hasOwnProperty('repeatTimerId')) {\n\t\t\t\t\t\ttimerIdCache = TempState.repeatTimerId;\n\t\t\t\t\t}\n\n\t\t\t\t\tTempState.repeatTimerId = timerId;\n\n\t\t\t\t\t// Execute the callback.\n\t\t\t\t\tcallback.call(this);\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\t// Teardown the `repeatTimerId` property, restoring the cached value, if necessary.\n\t\t\t\t\tif (typeof timerIdCache !== 'undefined') {\n\t\t\t\t\t\tTempState.repeatTimerId = timerIdCache;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdelete TempState.repeatTimerId;\n\t\t\t\t\t}\n\n\t\t\t\t\tTempState.break = null;\n\t\t\t\t}\n\t\t\t}, delay);\n\t\t\ttimers.add(timerId);\n\n\t\t\t// Set up a single-use `prehistory` task to remove pending timers.\n\t\t\tif (!prehistory.hasOwnProperty('#repeat-timers-cleanup')) {\n\t\t\t\tprehistory['#repeat-timers-cleanup'] = task => {\n\t\t\t\t\tdelete prehistory[task]; // single-use task\n\t\t\t\t\ttimers.forEach(timerId => clearInterval(timerId));\n\t\t\t\t\ttimers.clear();\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\tMacro.add('stop', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (!TempState.hasOwnProperty('repeatTimerId')) {\n\t\t\t\treturn this.error('must only be used in conjunction with its parent macro <<repeat>>');\n\t\t\t}\n\n\t\t\tconst timers  = Macro.get('repeat').timers;\n\t\t\tconst timerId = TempState.repeatTimerId;\n\t\t\tclearInterval(timerId);\n\t\t\ttimers.delete(timerId);\n\t\t\tTempState.break = 2;\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<timed>> & <<next>>\n\t*/\n\tMacro.add('timed', {\n\t\tisAsync : true,\n\t\ttags    : ['next'],\n\t\ttimers  : new Set(),\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no time value specified in <<timed>>');\n\t\t\t}\n\n\t\t\tconst items = [];\n\n\t\t\ttry {\n\t\t\t\titems.push({\n\t\t\t\t\tname    : this.name,\n\t\t\t\t\tsource  : this.source,\n\t\t\t\t\tdelay   : Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.args[0])),\n\t\t\t\t\tcontent : this.payload[0].contents\n\t\t\t\t});\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`${ex.message} in <<timed>>`);\n\t\t\t}\n\n\t\t\tif (this.payload.length > 1) {\n\t\t\t\tlet i;\n\n\t\t\t\ttry {\n\t\t\t\t\tlet len;\n\n\t\t\t\t\tfor (i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\t\titems.push({\n\t\t\t\t\t\t\tname   : this.payload[i].name,\n\t\t\t\t\t\t\tsource : this.payload[i].source,\n\t\t\t\t\t\t\tdelay  : this.payload[i].args.length === 0\n\t\t\t\t\t\t\t\t? items[items.length - 1].delay\n\t\t\t\t\t\t\t\t: Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.payload[i].args[0])),\n\t\t\t\t\t\t\tcontent : this.payload[i].contents\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`${ex.message} in <<next>> (#${i})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\tconst $wrapper   = jQuery(document.createElement('span'))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t// Register the timer.\n\t\t\tthis.self.registerTimeout(this.createShadowWrapper(item => {\n\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(frag, item.content);\n\n\t\t\t\t// Output.\n\t\t\t\tlet $output = $wrapper;\n\n\t\t\t\t// Custom debug view setup for `<<next>>`.\n\t\t\t\tif (Config.debug && item.name === 'next') {\n\t\t\t\t\t$output = jQuery((new DebugView( // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t$output[0],\n\t\t\t\t\t\t'macro',\n\t\t\t\t\t\titem.name,\n\t\t\t\t\t\titem.source\n\t\t\t\t\t)).output);\n\t\t\t\t}\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$output = jQuery(document.createElement('span'))\n\t\t\t\t\t\t.addClass('macro-timed-insert macro-timed-in')\n\t\t\t\t\t\t.appendTo($output);\n\t\t\t\t}\n\n\t\t\t\t$output.append(frag);\n\n\t\t\t\tif (transition) {\n\t\t\t\t\tsetTimeout(() => $output.removeClass('macro-timed-in'), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t}), items);\n\t\t},\n\n\t\tregisterTimeout(callback, items) {\n\t\t\tif (typeof callback !== 'function') {\n\t\t\t\tthrow new TypeError('callback parameter must be a function');\n\t\t\t}\n\n\t\t\tconst turnId = State.turns;\n\t\t\tconst timers = this.timers;\n\t\t\tlet timerId  = null;\n\t\t\tlet nextItem = items.shift();\n\n\t\t\tconst worker = function () {\n\t\t\t\t// Bookkeeping.\n\t\t\t\ttimers.delete(timerId);\n\n\t\t\t\tif (turnId !== State.turns) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Set the current item and set up the next worker, if any.\n\t\t\t\tconst curItem = nextItem;\n\n\t\t\t\tif ((nextItem = items.shift()) != null) { // lazy equality for null\n\t\t\t\t\ttimerId = setTimeout(worker, nextItem.delay);\n\t\t\t\t\ttimers.add(timerId);\n\t\t\t\t}\n\n\t\t\t\t// Execute the callback.\n\t\t\t\tcallback.call(this, curItem);\n\t\t\t};\n\n\t\t\t// Setup the timeout.\n\t\t\ttimerId = setTimeout(worker, nextItem.delay);\n\t\t\ttimers.add(timerId);\n\n\t\t\t// Set up a single-use `prehistory` task to remove pending timers.\n\t\t\tif (!prehistory.hasOwnProperty('#timed-timers-cleanup')) {\n\t\t\t\tprehistory['#timed-timers-cleanup'] = task => {\n\t\t\t\t\tdelete prehistory[task]; // single-use task\n\t\t\t\t\ttimers.forEach(timerId => clearTimeout(timerId)); // eslint-disable-line no-shadow\n\t\t\t\t\ttimers.clear();\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<widget>>\n\t*/\n\tMacro.add('widget', {\n\t\ttags : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no widget name specified');\n\t\t\t}\n\n\t\t\tconst widgetName = this.args[0];\n\n\t\t\tif (Macro.has(widgetName)) {\n\t\t\t\tif (!Macro.get(widgetName).isWidget) {\n\t\t\t\t\treturn this.error(`cannot clobber existing macro \"${widgetName}\"`);\n\t\t\t\t}\n\n\t\t\t\t// Delete the existing widget.\n\t\t\t\tMacro.delete(widgetName);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tMacro.add(widgetName, {\n\t\t\t\t\tisWidget : true,\n\t\t\t\t\thandler  : (function (contents) {\n\t\t\t\t\t\treturn function () {\n\t\t\t\t\t\t\tlet argsCache;\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t// Cache the existing value of the `$args` variable, if necessary.\n\t\t\t\t\t\t\t\tif (State.variables.hasOwnProperty('args')) {\n\t\t\t\t\t\t\t\t\targsCache = State.variables.args;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Set up the widget `$args` variable and add a shadow.\n\t\t\t\t\t\t\t\tState.variables.args = [...this.args];\n\t\t\t\t\t\t\t\tState.variables.args.raw = this.args.raw;\n\t\t\t\t\t\t\t\tState.variables.args.full = this.args.full;\n\t\t\t\t\t\t\t\tthis.addShadow('$args');\n\n\t\t\t\t\t\t\t\t// Set up the error trapping variables.\n\t\t\t\t\t\t\t\tconst resFrag = document.createDocumentFragment();\n\t\t\t\t\t\t\t\tconst errList = [];\n\n\t\t\t\t\t\t\t\t// Wikify the widget contents.\n\t\t\t\t\t\t\t\tnew Wikifier(resFrag, contents);\n\n\t\t\t\t\t\t\t\t// Carry over the output, unless there were errors.\n\t\t\t\t\t\t\t\tArray.from(resFrag.querySelectorAll('.error')).forEach(errEl => {\n\t\t\t\t\t\t\t\t\terrList.push(errEl.textContent);\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tif (errList.length === 0) {\n\t\t\t\t\t\t\t\t\tthis.output.appendChild(resFrag);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\treturn this.error(`error${errList.length > 1 ? 's' : ''} within widget contents (${errList.join('; ')})`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\treturn this.error(`cannot execute widget: ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t// Revert the `$args` variable shadowing.\n\t\t\t\t\t\t\t\tif (typeof argsCache !== 'undefined') {\n\t\t\t\t\t\t\t\t\tState.variables.args = argsCache;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tdelete State.variables.args;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t})(this.payload[0].contents)\n\t\t\t\t});\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`cannot create widget macro \"${widgetName}\": ${ex.message}`);\n\t\t\t}\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tdialog.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Has, L10n, safeActiveElement */\n\nvar Dialog = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Dialog element caches.\n\tlet _$overlay       = null;\n\tlet _$dialog        = null;\n\tlet _$dialogTitle   = null;\n\tlet _$dialogBody    = null;\n\n\t// The last active/focused non-dialog element.\n\tlet _lastActive     = null;\n\n\t// The width of the browser's scrollbars.\n\tlet _scrollbarWidth = 0;\n\n\t// Dialog mutation resize handler.\n\tlet _dialogObserver = null;\n\n\n\t/*******************************************************************************\n\t\tDialog Functions.\n\t*******************************************************************************/\n\n\t/*\n\t\t[DEPRECATED] Adds a click hander to the target element(s) which opens the dialog modal.\n\t*/\n\tfunction dialogAddClickHandler(targets, options, startFn, doneFn, closeFn) {\n\t\treturn jQuery(targets).ariaClick(ev => {\n\t\t\tev.preventDefault();\n\n\t\t\t// Call the start function.\n\t\t\tif (typeof startFn === 'function') {\n\t\t\t\tstartFn(ev);\n\t\t\t}\n\n\t\t\t// Open the dialog.\n\t\t\tdialogOpen(options, closeFn);\n\n\t\t\t// Call the done function.\n\t\t\tif (typeof doneFn === 'function') {\n\t\t\t\tdoneFn(ev);\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction dialogBodyAppend(...args) {\n\t\t_$dialogBody.append(...args);\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogBody() {\n\t\treturn _$dialogBody.get(0);\n\t}\n\n\tfunction dialogClose(ev) {\n\t\t// Trigger a `:dialogclosing` event on the dialog body.\n\t\t_$dialogBody.trigger(':dialogclosing');\n\n\t\t// Largely reverse the actions taken in `dialogOpen()`.\n\t\tjQuery(document)\n\t\t\t.off('.dialog-close');\n\t\tif (_dialogObserver) {\n\t\t\t_dialogObserver.disconnect();\n\t\t\t_dialogObserver = null;\n\t\t}\n\t\telse {\n\t\t\t_$dialogBody\n\t\t\t\t.off('.dialog-resize');\n\t\t}\n\t\tjQuery(window)\n\t\t\t.off('.dialog-resize');\n\t\t_$dialog\n\t\t\t.removeClass('open')\n\t\t\t.css({ left : '', right : '', top : '', bottom : '' });\n\n\t\tjQuery('#ui-bar,#story')\n\t\t\t.find('[tabindex=-2]')\n\t\t\t.removeAttr('aria-hidden')\n\t\t\t.attr('tabindex', 0);\n\t\tjQuery('body>[tabindex=-3]')\n\t\t\t.removeAttr('aria-hidden')\n\t\t\t.removeAttr('tabindex');\n\n\t\t_$overlay\n\t\t\t.removeClass('open');\n\t\tjQuery(document.documentElement)\n\t\t\t.removeAttr('data-dialog');\n\n\t\t// Clear the dialog's content.\n\t\t_$dialogTitle\n\t\t\t.empty();\n\t\t_$dialogBody\n\t\t\t.empty()\n\t\t\t.removeClass();\n\n\t\t// Attempt to restore focus to whichever element had it prior to opening the dialog.\n\t\tif (_lastActive !== null) {\n\t\t\tjQuery(_lastActive).focus();\n\t\t\t_lastActive = null;\n\t\t}\n\n\t\t// Call the given \"on close\" callback function, if any.\n\t\tif (ev && ev.data && typeof ev.data.closeFn === 'function') {\n\t\t\tev.data.closeFn(ev);\n\t\t}\n\n\t\t// Trigger a `:dialogclosed` event on the dialog body.\n\t\t/* legacy */\n\t\t_$dialogBody.trigger(':dialogclose');\n\t\t/* /legacy */\n\t\t_$dialogBody.trigger(':dialogclosed');\n\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogInit() {\n\t\tif (DEBUG) { console.log('[Dialog/dialogInit()]'); }\n\n\t\tif (document.getElementById('ui-dialog')) {\n\t\t\treturn;\n\t\t}\n\n\t\t/*\n\t\t\tCalculate and cache the width of scrollbars.\n\t\t*/\n\t\t_scrollbarWidth = (() => {\n\t\t\tlet scrollbarWidth;\n\n\t\t\ttry {\n\t\t\t\tconst inner = document.createElement('p');\n\t\t\t\tconst outer = document.createElement('div');\n\n\t\t\t\tinner.style.width      = '100%';\n\t\t\t\tinner.style.height     = '200px';\n\t\t\t\touter.style.position   = 'absolute';\n\t\t\t\touter.style.left       = '0px';\n\t\t\t\touter.style.top        = '0px';\n\t\t\t\touter.style.width      = '100px';\n\t\t\t\touter.style.height     = '100px';\n\t\t\t\touter.style.visibility = 'hidden';\n\t\t\t\touter.style.overflow   = 'hidden';\n\n\t\t\t\touter.appendChild(inner);\n\t\t\t\tdocument.body.appendChild(outer);\n\n\t\t\t\tconst w1 = inner.offsetWidth;\n\t\t\t\t/*\n\t\t\t\t\tThe `overflow: scroll` style property value does not work consistently\n\t\t\t\t\twith scrollbars which are styled with `::-webkit-scrollbar`, so we use\n\t\t\t\t\t`overflow: auto` with dimensions guaranteed to force a scrollbar.\n\t\t\t\t*/\n\t\t\t\touter.style.overflow = 'auto';\n\t\t\t\tlet w2 = inner.offsetWidth;\n\n\t\t\t\tif (w1 === w2) {\n\t\t\t\t\tw2 = outer.clientWidth;\n\t\t\t\t}\n\n\t\t\t\tdocument.body.removeChild(outer);\n\n\t\t\t\tscrollbarWidth = w1 - w2;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn scrollbarWidth || 17; // 17px is a reasonable failover\n\t\t})();\n\n\t\t/*\n\t\t\tGenerate the dialog elements.\n\t\t*/\n\t\tconst $elems = jQuery(document.createDocumentFragment())\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  '<div id=\"ui-overlay\" class=\"ui-close\"></div>'\n\t\t\t\t+ '<div id=\"ui-dialog\" tabindex=\"0\" role=\"dialog\" aria-labelledby=\"ui-dialog-title\">'\n\t\t\t\t+     '<div id=\"ui-dialog-titlebar\">'\n\t\t\t\t+         '<h1 id=\"ui-dialog-title\"></h1>'\n\t\t\t\t+         `<button id=\"ui-dialog-close\" class=\"ui-close\" tabindex=\"0\" aria-label=\"${L10n.get('close')}\">\\uE804</button>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div id=\"ui-dialog-body\"></div>'\n\t\t\t\t+ '</div>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t);\n\n\t\t/*\n\t\t\tCache the dialog elements, since they're going to be used often.\n\n\t\t\tNOTE: We rewrap the elements themselves, rather than simply using\n\t\t\tthe results of `find()`, so that we cache uncluttered jQuery-wrappers\n\t\t\t(i.e. `context` refers to the elements and there is no `prevObject`).\n\t\t*/\n\t\t_$overlay     = jQuery($elems.find('#ui-overlay').get(0));\n\t\t_$dialog      = jQuery($elems.find('#ui-dialog').get(0));\n\t\t_$dialogTitle = jQuery($elems.find('#ui-dialog-title').get(0));\n\t\t_$dialogBody  = jQuery($elems.find('#ui-dialog-body').get(0));\n\n\t\t/*\n\t\t\tInsert the dialog elements into the page before the main script.\n\t\t*/\n\t\t$elems.insertBefore('body>script#script-sugarcube');\n\t}\n\n\tfunction dialogIsOpen(classNames) {\n\t\treturn _$dialog.hasClass('open')\n\t\t\t&& (classNames ? classNames.splitOrEmpty(/\\s+/).every(cn => _$dialogBody.hasClass(cn)) : true);\n\t}\n\n\tfunction dialogOpen(options, closeFn) {\n\t\t// Trigger a `:dialogopening` event on the dialog body.\n\t\t_$dialogBody.trigger(':dialogopening');\n\n\t\t// Grab the options we care about.\n\t\tconst { top } = jQuery.extend({ top : 50 }, options);\n\n\t\t// Record the last active/focused non-dialog element.\n\t\tif (!dialogIsOpen()) {\n\t\t\t_lastActive = safeActiveElement();\n\t\t}\n\n\t\t// Add the `data-dialog` attribute to <html> (mostly used to style <body>).\n\t\tjQuery(document.documentElement)\n\t\t\t.attr('data-dialog', 'open');\n\n\t\t// Display the overlay.\n\t\t_$overlay\n\t\t\t.addClass('open');\n\n\t\t/*\n\t\t\tAdd the imagesLoaded handler to the dialog body, if necessary.\n\n\t\t\tNOTE: We use `querySelector()` here as jQuery has no simple way to\n\t\t\tcheck if, and only if, at least one element of the specified type\n\t\t\texists.  The best that jQuery offers is analogous to `querySelectorAll()`,\n\t\t\twhich enumerates all elements of the specified type.\n\t\t*/\n\t\tif (_$dialogBody[0].querySelector('img') !== null) {\n\t\t\t_$dialogBody\n\t\t\t\t.imagesLoaded()\n\t\t\t\t.always(() => _resizeHandler({ data : { top } }));\n\t\t}\n\n\t\t// Add `aria-hidden=true` to all direct non-dialog-children of <body> to\n\t\t// hide the underlying page from screen readers while the dialog is open.\n\t\tjQuery('body>:not(script,#store-area,tw-storydata,#ui-bar,#ui-overlay,#ui-dialog)')\n\t\t\t.attr('tabindex', -3)\n\t\t\t.attr('aria-hidden', true);\n\t\tjQuery('#ui-bar,#story')\n\t\t\t.find('[tabindex]:not([tabindex^=-])')\n\t\t\t.attr('tabindex', -2)\n\t\t\t.attr('aria-hidden', true);\n\n\t\t// Display the dialog.\n\t\t_$dialog\n\t\t\t.css(_calcPosition(top))\n\t\t\t.addClass('open')\n\t\t\t.focus();\n\n\t\t// Add the UI resize handler.\n\t\tjQuery(window)\n\t\t\t.on('resize.dialog-resize', null, { top }, jQuery.throttle(40, _resizeHandler));\n\n\t\t// Add the dialog mutation resize handler.\n\t\tif (Has.mutationObserver) {\n\t\t\t_dialogObserver = new MutationObserver(mutations => {\n\t\t\t\tfor (let i = 0; i < mutations.length; ++i) {\n\t\t\t\t\tif (mutations[i].type === 'childList') {\n\t\t\t\t\t\t_resizeHandler({ data : { top } });\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t_dialogObserver.observe(_$dialogBody[0], {\n\t\t\t\tchildList : true,\n\t\t\t\tsubtree   : true\n\t\t\t});\n\t\t}\n\t\telse {\n\t\t\t_$dialogBody\n\t\t\t\t.on(\n\t\t\t\t\t'DOMNodeInserted.dialog-resize DOMNodeRemoved.dialog-resize',\n\t\t\t\t\tnull,\n\t\t\t\t\t{ top },\n\t\t\t\t\tjQuery.throttle(40, _resizeHandler)\n\t\t\t\t);\n\t\t}\n\n\t\t// Set up the delegated UI close handler.\n\t\tjQuery(document)\n\t\t\t.on('click.dialog-close', '.ui-close', { closeFn }, dialogClose)\n\t\t\t.on('keypress.dialog-close', '.ui-close', function (ev) {\n\t\t\t\t// 13 is Enter/Return, 32 is Space.\n\t\t\t\tif (ev.which === 13 || ev.which === 32) {\n\t\t\t\t\tjQuery(this).trigger('click');\n\t\t\t\t}\n\t\t\t});\n\n\t\t// Trigger a `:dialogopened` event on the dialog body.\n\t\t/* legacy */\n\t\t_$dialogBody.trigger(':dialogopen');\n\t\t/* /legacy */\n\t\t_$dialogBody.trigger(':dialogopened');\n\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogResize(data) {\n\t\treturn _resizeHandler(typeof data === 'object' ? { data } : undefined);\n\t}\n\n\tfunction dialogSetup(title, classNames) {\n\t\t_$dialogBody\n\t\t\t.empty()\n\t\t\t.removeClass();\n\n\t\tif (classNames != null) { // lazy equality for null\n\t\t\t_$dialogBody.addClass(classNames);\n\t\t}\n\n\t\t_$dialogTitle\n\t\t\t.empty()\n\t\t\t.append((title != null ? String(title) : '') || '\\u00A0'); // lazy equality for null\n\n\t\t// TODO: In v3 this should return `Dialog` for chaining.\n\t\treturn _$dialogBody.get(0);\n\t}\n\n\tfunction dialogBodyWiki(...args) {\n\t\t_$dialogBody.wiki(...args);\n\t\treturn Dialog;\n\t}\n\n\n\t/*******************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************/\n\n\tfunction _calcPosition(topPos) {\n\t\tconst top       = topPos != null ? topPos : 50; // lazy equality for null\n\t\tconst $parent   = jQuery(window);\n\t\tconst dialogPos = { left : '', right : '', top : '', bottom : '' };\n\n\t\t// Unset the dialog's positional properties before checking its dimensions.\n\t\t_$dialog.css(dialogPos);\n\n\t\tlet horzSpace = $parent.width() - _$dialog.outerWidth(true) - 1;   // -1 to address a Firefox issue\n\t\tlet vertSpace = $parent.height() - _$dialog.outerHeight(true) - 1; // -1 to address a Firefox issue\n\n\t\tif (horzSpace <= 32 + _scrollbarWidth) {\n\t\t\tvertSpace -= _scrollbarWidth;\n\t\t}\n\n\t\tif (vertSpace <= 32 + _scrollbarWidth) {\n\t\t\thorzSpace -= _scrollbarWidth;\n\t\t}\n\n\t\tif (horzSpace <= 32) {\n\t\t\tdialogPos.left = dialogPos.right = 16;\n\t\t}\n\t\telse {\n\t\t\tdialogPos.left = dialogPos.right = horzSpace / 2 >> 0;\n\t\t}\n\n\t\tif (vertSpace <= 32) {\n\t\t\tdialogPos.top = dialogPos.bottom = 16;\n\t\t}\n\t\telse {\n\t\t\tif (vertSpace / 2 > top) {\n\t\t\t\tdialogPos.top = top;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdialogPos.top = dialogPos.bottom = vertSpace / 2 >> 0;\n\t\t\t}\n\t\t}\n\n\t\tObject.keys(dialogPos).forEach(key => {\n\t\t\tif (dialogPos[key] !== '') {\n\t\t\t\tdialogPos[key] += 'px';\n\t\t\t}\n\t\t});\n\n\t\treturn dialogPos;\n\t}\n\n\tfunction _resizeHandler(ev) {\n\t\tconst top = ev && ev.data && typeof ev.data.top !== 'undefined' ? ev.data.top : 50;\n\n\t\tif (_$dialog.css('display') === 'block') {\n\t\t\t// Stow the dialog.\n\t\t\t_$dialog.css({ display : 'none' });\n\n\t\t\t// Restore the dialog with its new positional properties.\n\t\t\t_$dialog.css(jQuery.extend({ display : '' }, _calcPosition(top)));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tappend : { value : dialogBodyAppend },\n\t\tbody   : { value : dialogBody },\n\t\tclose  : { value : dialogClose },\n\t\tinit   : { value : dialogInit },\n\t\tisOpen : { value : dialogIsOpen },\n\t\topen   : { value : dialogOpen },\n\t\tresize : { value : dialogResize },\n\t\tsetup  : { value : dialogSetup },\n\t\twiki   : { value : dialogBodyWiki },\n\n\t\t// Legacy Functions.\n\t\taddClickHandler : { value : dialogAddClickHandler }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tengine.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Config, DebugView, Dialog, Has, LoadScreen, Save, State, Story, StyleWrapper, UI, UIBar, Util,\n\t       Wikifier, postdisplay, postrender, predisplay, prehistory, prerender, setDisplayTitle\n*/\n\nvar Engine = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Engine state types object (pseudo-enumeration).\n\tconst States = Util.toEnum({\n\t\tIdle      : 'idle',\n\t\tPlaying   : 'playing',\n\t\tRendering : 'rendering'\n\t});\n\n\t// Minimum delay for DOM actions (in milliseconds).\n\tconst minDomActionDelay = 40;\n\n\t// Current state of the engine (default: `Engine.States.Idle`).\n\tlet _state = States.Idle;\n\n\t// Last time `enginePlay()` was called (in milliseconds).\n\tlet _lastPlay = null;\n\n\t// Cache of the debug view for the StoryInit special passage.\n\tlet _storyInitDebugView = null;\n\n\t// Cache of the outline patching <style> element (`StyleWrapper`-wrapped).\n\tlet _outlinePatch = null;\n\n\t// List of objects describing `StoryInterface` elements to update via passages during navigation.\n\tlet _updating = null;\n\n\n\t/*******************************************************************************************************************\n\t\tEngine Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tInitialize the core story elements and perform some bookkeeping.\n\t*/\n\tfunction engineInit() {\n\t\tif (DEBUG) { console.log('[Engine/engineInit()]'); }\n\n\t\t/*\n\t\t\tRemove #init-no-js & #init-lacking from #init-screen.\n\t\t*/\n\t\tjQuery('#init-no-js,#init-lacking').remove();\n\n\t\t/*\n\t\t\tGenerate the core story elements and insert them into the page before the store area.\n\t\t*/\n\t\t(() => {\n\t\t\tconst $elems = jQuery(document.createDocumentFragment());\n\t\t\tconst markup = Story.has('StoryInterface') && Story.get('StoryInterface').text.trim();\n\n\t\t\tif (markup) {\n\t\t\t\t// Remove the UI bar, its styles, and events.\n\t\t\t\tUIBar.destroy();\n\n\t\t\t\t// Remove the core display area styles.\n\t\t\t\tjQuery(document.head).find('#style-core-display').remove();\n\n\t\t\t\t$elems.append(markup);\n\n\t\t\t\tif ($elems.find('#passages').length === 0) {\n\t\t\t\t\tthrow new Error('no element with ID \"passages\" found within \"StoryInterface\" special passage');\n\t\t\t\t}\n\n\t\t\t\tconst updating = [];\n\n\t\t\t\t$elems.find('[data-passage]').each((i, el) => {\n\t\t\t\t\tif (el.id === 'passages') {\n\t\t\t\t\t\tthrow new Error(`\"StoryInterface\" element <${el.nodeName.toLowerCase()} id=\"passages\"> must not contain a \"data-passage\" content attribute`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst passage = el.getAttribute('data-passage').trim();\n\n\t\t\t\t\tif (el.firstElementChild !== null) {\n\t\t\t\t\t\tthrow new Error(`\"StoryInterface\" element <${el.nodeName.toLowerCase()} data-passage=\"${passage}\"> contains child elements`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tupdating.push({\n\t\t\t\t\t\t\tpassage,\n\t\t\t\t\t\t\telement : el\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (updating.length > 0) {\n\t\t\t\t\t_updating = updating;\n\t\t\t\t}\n\n\t\t\t\tConfig.ui.updateStoryElements = false;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$elems.append('<div id=\"story\" role=\"main\"><div id=\"passages\"></div></div>');\n\t\t\t}\n\n\t\t\t// Insert the core UI elements into the page before the main script.\n\t\t\t$elems.insertBefore('body>script#script-sugarcube');\n\t\t})();\n\n\t\t/*\n\t\t\tGenerate and cache the ARIA outlines <style> element (`StyleWrapper`-wrapped)\n\t\t\tand set up the handler to manipulate the outlines.\n\n\t\t\tIDEA: http://www.paciellogroup.com/blog/2012/04/how-to-remove-css-outlines-in-an-accessible-manner/\n\t\t*/\n\t\t_outlinePatch = new StyleWrapper((\n\t\t\t() => jQuery(document.createElement('style'))\n\t\t\t\t.attr({\n\t\t\t\t\tid   : 'style-aria-outlines',\n\t\t\t\t\ttype : 'text/css'\n\t\t\t\t})\n\t\t\t\t.appendTo(document.head)\n\t\t\t\t.get(0) // return the <style> element itself\n\t\t)());\n\t\tlet _lastOutlineEvent;\n\t\tjQuery(document).on(\n\t\t\t'mousedown.aria-outlines keydown.aria-outlines',\n\t\t\tev => {\n\t\t\t\tif (ev.type !== _lastOutlineEvent) {\n\t\t\t\t\t_lastOutlineEvent = ev.type;\n\n\t\t\t\t\tif (ev.type === 'keydown') {\n\t\t\t\t\t\t_showOutlines();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t_hideOutlines();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\t/*\n\t\tStarts the story.\n\t*/\n\tfunction engineStart() {\n\t\tif (DEBUG) { console.log('[Engine/engineStart()]'); }\n\n\t\t/*\n\t\t\tExecute the StoryInit special passage.\n\t\t*/\n\t\tif (Story.has('StoryInit')) {\n\t\t\ttry {\n\t\t\t\tconst debugBuffer = Wikifier.wikifyEval(Story.get('StoryInit').text);\n\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tconst debugView = new DebugView(\n\t\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t\t'special',\n\t\t\t\t\t\t'StoryInit',\n\t\t\t\t\t\t'StoryInit'\n\t\t\t\t\t);\n\t\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\t\tdebugView.append(debugBuffer);\n\t\t\t\t\t_storyInitDebugView = debugView.output;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('StoryInit', ex.message);\n\t\t\t}\n\t\t}\n\n\t\t// Sanity checks.\n\t\tif (Config.passages.start == null) { // lazy equality for null\n\t\t\tthrow new Error('starting passage not selected');\n\t\t}\n\t\tif (!Story.has(Config.passages.start)) {\n\t\t\tthrow new Error(`starting passage (\"${Config.passages.start}\") not found`);\n\t\t}\n\n\t\t// Focus the document element initially.\n\t\tjQuery(document.documentElement).focus();\n\n\t\t/*\n\t\t\tAttempt to restore an active session.  Failing that, attempt to autoload the autosave,\n\t\t\tif requested.  Failing that, display the starting passage.\n\t\t*/\n\t\tif (State.restore()) {\n\t\t\tengineShow();\n\t\t}\n\t\telse {\n\t\t\tlet loadStart = true;\n\n\t\t\tswitch (typeof Config.saves.autoload) {\n\t\t\tcase 'boolean':\n\t\t\t\tif (Config.saves.autoload && Save.autosave.ok() && Save.autosave.has()) {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\t\tloadStart = !Save.autosave.load();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'string':\n\t\t\t\tif (Config.saves.autoload === 'prompt' && Save.autosave.ok() && Save.autosave.has()) {\n\t\t\t\t\tloadStart = false;\n\t\t\t\t\tUI.buildAutoload();\n\t\t\t\t\tDialog.open();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'function':\n\t\t\t\tif (Save.autosave.ok() && Save.autosave.has() && !!Config.saves.autoload()) {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\t\tloadStart = !Save.autosave.load();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (loadStart) {\n\t\t\t\tif (DEBUG) { console.log(`\\tstarting passage: \"${Config.passages.start}\"`); }\n\n\t\t\t\tenginePlay(Config.passages.start);\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t\tRestarts the story.\n\t*/\n\tfunction engineRestart() {\n\t\tif (DEBUG) { console.log('[Engine/engineRestart()]'); }\n\n\t\t/*\n\t\t\tShow the loading screen to hide any unsightly rendering shenanigans during the\n\t\t\tpage reload.\n\t\t*/\n\t\tLoadScreen.show();\n\n\t\t/*\n\t\t\tScroll the window to the top.\n\n\t\t\tThis is required by most browsers for the starting passage or it will remain at\n\t\t\twhatever its current scroll position is after the page reload.  We do it generally,\n\t\t\trather than only for the currently set starting passage, since the starting passage\n\t\t\tmay be dynamically manipulated.\n\t\t*/\n\t\twindow.scroll(0, 0);\n\n\t\t/*\n\t\t\tDelete the active session.\n\t\t*/\n\t\tState.reset();\n\n\t\t/*\n\t\t\tTrigger an ':enginerestart' event.\n\t\t*/\n\t\tjQuery.event.trigger(':enginerestart');\n\n\t\t/*\n\t\t\tReload the page.\n\t\t*/\n\t\twindow.location.reload();\n\t}\n\n\t/*\n\t\tReturns the current state of the engine.\n\t*/\n\tfunction engineState() {\n\t\treturn _state;\n\t}\n\n\t/*\n\t\tReturns whether the engine is idle.\n\t*/\n\tfunction engineIsIdle() {\n\t\treturn _state === States.Idle;\n\t}\n\n\t/*\n\t\tReturns whether the engine is playing.\n\t*/\n\tfunction engineIsPlaying() {\n\t\treturn _state !== States.Idle;\n\t}\n\n\t/*\n\t\tReturns whether the engine is rendering.\n\t*/\n\tfunction engineIsRendering() {\n\t\treturn _state === States.Rendering;\n\t}\n\n\t/*\n\t\tReturns a timestamp representing the last time `Engine.play()` was called.\n\t*/\n\tfunction engineLastPlay() {\n\t\treturn _lastPlay;\n\t}\n\n\t/*\n\t\tActivate the moment at the given index within the state history and show it.\n\t*/\n\tfunction engineGoTo(idx) {\n\t\tconst succeded = State.goTo(idx);\n\n\t\tif (succeded) {\n\t\t\tengineShow();\n\t\t}\n\n\t\treturn succeded;\n\t}\n\n\t/*\n\t\tActivate the moment at the given offset from the active moment within the state history\n\t\tand show it.\n\t*/\n\tfunction engineGo(offset) {\n\t\tconst succeded = State.go(offset);\n\n\t\tif (succeded) {\n\t\t\tengineShow();\n\t\t}\n\n\t\treturn succeded;\n\t}\n\n\t/*\n\t\tGo to the moment which directly precedes the active moment and show it.\n\t*/\n\tfunction engineBackward() {\n\t\treturn engineGo(-1);\n\t}\n\n\t/*\n\t\tGo to the moment which directly follows the active moment and show it.\n\t*/\n\tfunction engineForward() {\n\t\treturn engineGo(1);\n\t}\n\n\t/*\n\t\tRenders and displays the active (present) moment's associated passage without adding\n\t\ta new moment to the history.\n\t*/\n\tfunction engineShow() {\n\t\treturn enginePlay(State.passage, true);\n\t}\n\n\t/*\n\t\tRenders and displays the passage referenced by the given title, optionally without\n\t\tadding a new moment to the history.\n\t*/\n\tfunction enginePlay(title, noHistory) {\n\t\tif (DEBUG) { console.log(`[Engine/enginePlay(title: \"${title}\", noHistory: ${noHistory})]`); }\n\n\t\tlet passageTitle = title;\n\n\t\t// Update the engine state.\n\t\t_state = States.Playing;\n\n\t\t// Reset the temporary state and variables objects.\n\t\tTempState = {}; // eslint-disable-line no-undef\n\t\tState.clearTemporary();\n\n\t\t// Debug view setup.\n\t\tlet passageReadyOutput;\n\t\tlet passageDoneOutput;\n\n\t\t// Execute the navigation override callback.\n\t\tif (typeof Config.navigation.override === 'function') {\n\t\t\ttry {\n\t\t\t\tconst overrideTitle = Config.navigation.override(passageTitle);\n\n\t\t\t\tif (overrideTitle) {\n\t\t\t\t\tpassageTitle = overrideTitle;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\t\t}\n\n\t\t// Retrieve the passage by the given title.\n\t\t//\n\t\t// NOTE: The values of the `title` parameter and `passageTitle` variable\n\t\t// may be empty, strings, or numbers (though using a number as reference\n\t\t// to a numeric title should be discouraged), so after loading the passage,\n\t\t// always refer to `passage.title` and never to the others.\n\t\tconst passage = Story.get(passageTitle);\n\n\t\t// Execute the pre-history events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype : ':passageinit',\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(prehistory).forEach(task => {\n\t\t\tif (typeof prehistory[task] === 'function') {\n\t\t\t\tprehistory[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\t// Create a new entry in the history.\n\t\tif (!noHistory) {\n\t\t\tState.create(passage.title);\n\t\t}\n\n\t\t// Clear the document body's classes.\n\t\tif (document.body.className) {\n\t\t\tdocument.body.className = '';\n\t\t}\n\n\t\t// Update the last play time.\n\t\t//\n\t\t// NOTE: This is mostly for event, task, and special passage code,\n\t\t// though the likelihood of it being needed this early is low.  This\n\t\t// will be updated again later at the end.\n\t\t_lastPlay = Util.now();\n\n\t\t// Execute pre-display tasks and the `PassageReady` special passage.\n\t\tObject.keys(predisplay).forEach(task => {\n\t\t\tif (typeof predisplay[task] === 'function') {\n\t\t\t\tpredisplay[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\tif (Story.has('PassageReady')) {\n\t\t\ttry {\n\t\t\t\tpassageReadyOutput = Wikifier.wikifyEval(Story.get('PassageReady').text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('PassageReady', ex.message);\n\t\t\t}\n\t\t}\n\n\t\t// Update the engine state.\n\t\t_state = States.Rendering;\n\n\t\t// Get the passage's tags as a string, or `null` if there aren't any.\n\t\tconst dataTags = passage.tags.length > 0 ? passage.tags.join(' ') : null;\n\n\t\t// Create and set up the incoming passage element.\n\t\tconst passageEl = document.createElement('div');\n\t\tjQuery(passageEl)\n\t\t\t.attr({\n\t\t\t\tid             : passage.domId,\n\t\t\t\t'data-passage' : passage.title,\n\t\t\t\t'data-tags'    : dataTags\n\t\t\t})\n\t\t\t.addClass(`passage ${passage.className}`);\n\n\t\t// Add the passage's classes and tags to the document body.\n\t\tjQuery(document.body)\n\t\t\t.attr('data-tags', dataTags)\n\t\t\t.addClass(passage.className);\n\n\t\t// Add the passage's tags to the document element.\n\t\tjQuery(document.documentElement)\n\t\t\t.attr('data-tags', dataTags);\n\n\t\t// Execute pre-render events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagestart',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(prerender).forEach(task => {\n\t\t\tif (typeof prerender[task] === 'function') {\n\t\t\t\tprerender[task].call(passage, passageEl, task);\n\t\t\t}\n\t\t});\n\n\t\t// Render the `PassageHeader` passage, if it exists, into the passage element.\n\t\tif (Story.has('PassageHeader')) {\n\t\t\tnew Wikifier(passageEl, Story.get('PassageHeader').processText());\n\t\t}\n\n\t\t// Render the passage into its element.\n\t\tpassageEl.appendChild(passage.render());\n\n\t\t// Render the `PassageFooter` passage, if it exists, into the passage element.\n\t\tif (Story.has('PassageFooter')) {\n\t\t\tnew Wikifier(passageEl, Story.get('PassageFooter').processText());\n\t\t}\n\n\t\t// Execute post-render events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagerender',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(postrender).forEach(task => {\n\t\t\tif (typeof postrender[task] === 'function') {\n\t\t\t\tpostrender[task].call(passage, passageEl, task);\n\t\t\t}\n\t\t});\n\n\t\t// Cache the passage container.\n\t\tconst containerEl = document.getElementById('passages');\n\n\t\t// Empty the passage container.\n\t\tif (containerEl.hasChildNodes()) {\n\t\t\tif (\n\t\t\t\t   typeof Config.passages.transitionOut === 'number'\n\t\t\t\t|| typeof Config.passages.transitionOut === 'string'\n\t\t\t\t&& Config.passages.transitionOut !== ''\n\t\t\t\t&& Has.transitionEndEvent\n\t\t\t) {\n\t\t\t\t[...containerEl.childNodes].forEach(outgoing => {\n\t\t\t\t\tconst $outgoing = jQuery(outgoing);\n\n\t\t\t\t\tif (outgoing.nodeType === Node.ELEMENT_NODE && $outgoing.hasClass('passage')) {\n\t\t\t\t\t\tif ($outgoing.hasClass('passage-out')) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$outgoing\n\t\t\t\t\t\t\t.attr('id', `out-${$outgoing.attr('id')}`)\n\t\t\t\t\t\t\t.addClass('passage-out');\n\n\t\t\t\t\t\tif (typeof Config.passages.transitionOut === 'string') {\n\t\t\t\t\t\t\t$outgoing.on(Has.transitionEndEvent, ev => {\n\t\t\t\t\t\t\t\tif (ev.originalEvent.propertyName === Config.passages.transitionOut) {\n\t\t\t\t\t\t\t\t\t$outgoing.remove();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tsetTimeout(\n\t\t\t\t\t\t\t\t() => $outgoing.remove(),\n\t\t\t\t\t\t\t\tMath.max(minDomActionDelay, Config.passages.transitionOut)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t$outgoing.remove();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery(containerEl).empty();\n\t\t\t}\n\t\t}\n\n\t\t// Append the passage element to the passage container and set up its transition.\n\t\tjQuery(passageEl)\n\t\t\t.addClass('passage-in')\n\t\t\t.appendTo(containerEl);\n\t\tsetTimeout(() => jQuery(passageEl).removeClass('passage-in'), minDomActionDelay);\n\n\t\t// Update the story display title, if necessary.\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\t// NOTE: We don't have an `else` here because that case will be handled later (below).\n\t\t\tif (_updating !== null || !Config.ui.updateStoryElements) {\n\t\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t\t}\n\t\t}\n\t\telse if (Config.passages.displayTitles && passage.title !== Config.passages.start) {\n\t\t\tdocument.title = `${passage.title} | ${Story.title}`;\n\t\t}\n\n\t\t// Scroll the window to the top.\n\t\twindow.scroll(0, 0);\n\n\t\t// Update the engine state.\n\t\t_state = States.Playing;\n\n\t\t// Execute post-display events, tasks, and the `PassageDone` special passage.\n\t\tif (Story.has('PassageDone')) {\n\t\t\ttry {\n\t\t\t\tpassageDoneOutput = Wikifier.wikifyEval(Story.get('PassageDone').text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('PassageDone', ex.message);\n\t\t\t}\n\t\t}\n\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagedisplay',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(postdisplay).forEach(task => {\n\t\t\tif (typeof postdisplay[task] === 'function') {\n\t\t\t\tpostdisplay[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\t// Update the other interface elements, if necessary.\n\t\tif (_updating !== null) {\n\t\t\t_updating.forEach(pair => {\n\t\t\t\tjQuery(pair.element).empty();\n\t\t\t\tnew Wikifier(pair.element, Story.get(pair.passage).processText().trim());\n\t\t\t});\n\t\t}\n\t\telse if (Config.ui.updateStoryElements) {\n\t\t\tUIBar.update();\n\t\t}\n\n\t\t// Add the completed debug views for `StoryInit`, `PassageReady`, and `PassageDone`\n\t\t// to the incoming passage element.\n\t\tif (Config.debug) {\n\t\t\tlet debugView;\n\n\t\t\t// Prepend the `PassageReady` debug view.\n\t\t\tif (passageReadyOutput != null) { // lazy equality for null\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t'special',\n\t\t\t\t\t'PassageReady',\n\t\t\t\t\t'PassageReady'\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\tdebugView.append(passageReadyOutput);\n\t\t\t\tjQuery(passageEl).prepend(debugView.output);\n\t\t\t}\n\n\t\t\t// Append the `PassageDone` debug view.\n\t\t\tif (passageDoneOutput != null) { // lazy equality for null\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t'special',\n\t\t\t\t\t'PassageDone',\n\t\t\t\t\t'PassageDone'\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\tdebugView.append(passageDoneOutput);\n\t\t\t\tjQuery(passageEl).append(debugView.output);\n\t\t\t}\n\n\t\t\t// Prepend the cached `StoryInit` debug view, if we're showing the first moment/turn.\n\t\t\tif (State.turns === 1 && _storyInitDebugView != null) { // lazy equality for null\n\t\t\t\tjQuery(passageEl).prepend(_storyInitDebugView);\n\t\t\t}\n\t\t}\n\n\t\t// Last second post-processing for accessibility and other things.\n\t\t_hideOutlines(); // initially hide outlines\n\t\tjQuery('#story')\n\t\t\t// Add `link-external` to all `href` bearing `<a>` elements which don't have it.\n\t\t\t.find('a[href]:not(.link-external)')\n\t\t\t.addClass('link-external')\n\t\t\t.end()\n\t\t\t// Add `tabindex=0` to all interactive elements which don't have it.\n\t\t\t.find('a,link,button,input,select,textarea')\n\t\t\t.not('[tabindex]')\n\t\t\t.attr('tabindex', 0);\n\n\t\t// Handle autosaves.\n\t\tswitch (typeof Config.saves.autosave) {\n\t\tcase 'boolean':\n\t\t\tif (Config.saves.autosave) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'object':\n\t\t\tif (passage.tags.some(tag => Config.saves.autosave.includes(tag))) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'function':\n\t\t\tif (Config.saves.autosave()) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// Execute post-play events.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passageend',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\n\t\t// Reset the engine state.\n\t\t_state = States.Idle;\n\n\t\t// Update the last play time.\n\t\t_lastPlay = Util.now();\n\n\t\treturn passageEl;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tLegacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Play the given passage, optionally without altering the history.\n\t*/\n\tfunction engineDisplay(title, link, option) {\n\t\tif (DEBUG) { console.log('[Engine/engineDisplay()]'); }\n\n\t\tlet noHistory = false;\n\n\t\t// Process the option parameter.\n\t\tswitch (option) {\n\t\tcase undefined:\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'replace':\n\t\tcase 'back':\n\t\t\tnoHistory = true;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new Error(`Engine.display option parameter called with obsolete value \"${option}\"; please notify the developer`);\n\t\t}\n\n\t\tenginePlay(title, noHistory);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _hideOutlines() {\n\t\t_outlinePatch.set('*:focus{outline:none;}');\n\t}\n\n\tfunction _showOutlines() {\n\t\t_outlinePatch.clear();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tConstants.\n\t\t*/\n\t\tStates            : { value : States },\n\t\tminDomActionDelay : { value : minDomActionDelay },\n\n\t\t/*\n\t\t\tCore Functions.\n\t\t*/\n\t\tinit        : { value : engineInit },\n\t\tstart       : { value : engineStart },\n\t\trestart     : { value : engineRestart },\n\t\tstate       : { get : engineState },\n\t\tisIdle      : { value : engineIsIdle },\n\t\tisPlaying   : { value : engineIsPlaying },\n\t\tisRendering : { value : engineIsRendering },\n\t\tlastPlay    : { get : engineLastPlay },\n\t\tgoTo        : { value : engineGoTo },\n\t\tgo          : { value : engineGo },\n\t\tbackward    : { value : engineBackward },\n\t\tforward     : { value : engineForward },\n\t\tshow        : { value : engineShow },\n\t\tplay        : { value : enginePlay },\n\n\t\t/*\n\t\t\tLegacy Functions.\n\t\t*/\n\t\tdisplay : { value : engineDisplay }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tpassage.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, L10n, Util, Wikifier */\n\nvar Passage = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tlet _tagsToSkip;\n\tlet _twine1Unescape;\n\n\t/*\n\t\tTags which should not be transformed into classes:\n\t\t\tdebug      → special tag\n\t\t\tnobr       → special tag\n\t\t\tpassage    → the default class\n\t\t\tscript     → special tag (only in Twine 1)\n\t\t\tstylesheet → special tag (only in Twine 1)\n\t\t\ttwine.*    → special tag\n\t\t\twidget     → special tag\n\t*/\n\t// For Twine 1\n\tif (TWINE1) {\n\t\t_tagsToSkip = /^(?:debug|nobr|passage|script|stylesheet|widget|twine\\..*)$/i;\n\t}\n\t// For Twine 2\n\telse {\n\t\t_tagsToSkip = /^(?:debug|nobr|passage|widget|twine\\..*)$/i;\n\t}\n\n\t// For Twine 1\n\tif (TWINE1) {\n\t\t/*\n\t\t\tReturns a decoded version of the passed Twine 1 passage store encoded string.\n\t\t*/\n\t\tconst _twine1EscapesRe    = /(?:\\\\n|\\\\t|\\\\s|\\\\|\\r)/g;\n\t\tconst _hasTwine1EscapesRe = new RegExp(_twine1EscapesRe.source); // to drop the global flag\n\t\tconst _twine1EscapesMap   = Object.freeze({\n\t\t\t'\\\\n' : '\\n',\n\t\t\t'\\\\t' : '\\t',\n\t\t\t'\\\\s' : '\\\\',\n\t\t\t'\\\\'  : '\\\\',\n\t\t\t'\\r'  : ''\n\t\t});\n\n\t\t_twine1Unescape = function (str) {\n\t\t\tif (str == null) { // lazy equality for null\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tconst val = String(str);\n\t\t\treturn val && _hasTwine1EscapesRe.test(val)\n\t\t\t\t? val.replace(_twine1EscapesRe, esc => _twine1EscapesMap[esc])\n\t\t\t\t: val;\n\t\t};\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPassage Class.\n\t*******************************************************************************************************************/\n\tclass Passage {\n\t\tconstructor(title, el) {\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// Passage title/ID.\n\t\t\t\ttitle : {\n\t\t\t\t\tvalue : Util.unescape(title)\n\t\t\t\t},\n\n\t\t\t\t// Passage data element (within the story data element; i.e. T1: '[tiddler]', T2: 'tw-passagedata').\n\t\t\t\telement : {\n\t\t\t\t\tvalue : el || null\n\t\t\t\t},\n\n\t\t\t\t// Passage tags array (sorted and unique).\n\t\t\t\ttags : {\n\t\t\t\t\tvalue : Object.freeze(el && el.hasAttribute('tags')\n\t\t\t\t\t\t? el.getAttribute('tags')\n\t\t\t\t\t\t\t.trim()\n\t\t\t\t\t\t\t.splitOrEmpty(/\\s+/)\n\t\t\t\t\t\t\t.sort()\n\t\t\t\t\t\t\t.filter((tag, i, aref) => i === 0 || aref[i - 1] !== tag)\n\t\t\t\t\t\t: [])\n\t\t\t\t},\n\n\t\t\t\t// Passage excerpt.  Used by the `description()` method.\n\t\t\t\t_excerpt : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Properties dependant upon the above set.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// Passage DOM-compatible ID.\n\t\t\t\tdomId : {\n\t\t\t\t\tvalue : `passage-${Util.slugify(this.title)}`\n\t\t\t\t},\n\n\t\t\t\t// Passage classes array (sorted and unique).\n\t\t\t\tclasses : {\n\t\t\t\t\tvalue : Object.freeze(this.tags.length === 0 ? [] : (() =>\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tReturn the sorted list of unique classes.\n\n\t\t\t\t\t\t\tNOTE: The `this.tags` array is already sorted and unique,\n\t\t\t\t\t\t\tso we only need to filter and map here.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tthis.tags\n\t\t\t\t\t\t\t.filter(tag => !_tagsToSkip.test(tag))\n\t\t\t\t\t\t\t.map(tag => Util.slugify(tag))\n\t\t\t\t\t)())\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// Getters.\n\t\tget className() {\n\t\t\treturn this.classes.join(' ');\n\t\t}\n\n\t\t// TODO: (v3) This should be → `get source`.\n\t\tget text() {\n\t\t\tif (this.element == null) { // lazy equality for null\n\t\t\t\tconst passage = Util.escape(this.title);\n\t\t\t\tconst mesg    = `${L10n.get('errorTitle')}: ${L10n.get('errorNonexistentPassage', { passage })}`;\n\t\t\t\treturn `<div class=\"error-view\"><span class=\"error\">${mesg}</span></div>`;\n\t\t\t}\n\n\t\t\t// For Twine 1\n\t\t\tif (TWINE1) {\n\t\t\t\treturn _twine1Unescape(this.element.textContent);\n\t\t\t}\n\t\t\t// For Twine 2\n\t\t\telse { // eslint-disable-line no-else-return\n\t\t\t\treturn this.element.textContent.replace(/\\r/g, '');\n\t\t\t}\n\t\t}\n\n\t\tdescription() {\n\t\t\tconst descriptions = Config.passages.descriptions;\n\n\t\t\tif (descriptions != null) { // lazy equality for null\n\t\t\t\tswitch (typeof descriptions) {\n\t\t\t\tcase 'boolean':\n\t\t\t\t\tif (descriptions) {\n\t\t\t\t\t\treturn this.title;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\tif (descriptions instanceof Map && descriptions.has(this.title)) {\n\t\t\t\t\t\treturn descriptions.get(this.title);\n\t\t\t\t\t}\n\t\t\t\t\telse if (descriptions.hasOwnProperty(this.title)) {\n\t\t\t\t\t\treturn descriptions[this.title];\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'function':\n\t\t\t\t\t{\n\t\t\t\t\t\tconst result = descriptions.call(this);\n\n\t\t\t\t\t\tif (result) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new TypeError('Config.passages.descriptions must be a boolean, object, or function');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Initialize the excerpt cache from the raw passage text, if necessary.\n\t\t\tif (this._excerpt === null) {\n\t\t\t\tthis._excerpt = Passage.getExcerptFromText(this.text);\n\t\t\t}\n\n\t\t\treturn this._excerpt;\n\t\t}\n\n\t\t// TODO: (v3) This should be → `get text`.\n\t\tprocessText() {\n\t\t\tif (this.element == null) { // lazy equality for null\n\t\t\t\treturn this.text;\n\t\t\t}\n\n\t\t\t// Handle image passage transclusion.\n\t\t\tif (this.tags.includes('Twine.image')) {\n\t\t\t\treturn `[img[${this.text}]]`;\n\t\t\t}\n\n\t\t\tlet processed = this.text;\n\n\t\t\t// Handle `Config.passages.onProcess`.\n\t\t\tif (Config.passages.onProcess) {\n\t\t\t\tprocessed = Config.passages.onProcess.call(null, {\n\t\t\t\t\ttitle : this.title,\n\t\t\t\t\ttags  : this.tags,\n\t\t\t\t\ttext  : processed\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Handle `Config.passages.nobr` and the `nobr` tag.\n\t\t\tif (Config.passages.nobr || this.tags.includes('nobr')) {\n\t\t\t\t// Remove all leading & trailing newlines and compact all internal sequences\n\t\t\t\t// of newlines into single spaces.\n\t\t\t\tprocessed = processed.replace(/^\\n+|\\n+$/g, '').replace(/\\n+/g, ' ');\n\t\t\t}\n\n\t\t\treturn processed;\n\t\t}\n\n\t\trender(options) {\n\t\t\t// Wikify the passage into a document fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, this.processText(), options);\n\n\t\t\t// Update the excerpt cache to reflect the rendered text, if we need it for the passage description\n\t\t\tif (Config.passages.descriptions == null) {\n\t\t\t\tthis._excerpt = Passage.getExcerptFromNode(frag);\n\t\t\t}\n\n\t\t\treturn frag;\n\t\t}\n\n\t\tstatic getExcerptFromNode(node, count) {\n\t\t\tif (!node.hasChildNodes()) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tlet excerpt = node.textContent.trim();\n\n\t\t\tif (excerpt !== '') {\n\t\t\t\tconst excerptRe = new RegExp(`(\\\\S+(?:\\\\s+\\\\S+){0,${count > 0 ? count - 1 : 7}})`);\n\t\t\t\texcerpt = excerpt\n\t\t\t\t\t// Compact whitespace.\n\t\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t\t// Attempt to match the excerpt regexp.\n\t\t\t\t\t.match(excerptRe);\n\t\t\t}\n\n\t\t\treturn excerpt ? `${excerpt[1]}\\u2026` : '\\u2026'; // horizontal ellipsis\n\t\t}\n\n\t\tstatic getExcerptFromText(text, count) {\n\t\t\tif (text === '') {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tconst excerptRe = new RegExp(`(\\\\S+(?:\\\\s+\\\\S+){0,${count > 0 ? count - 1 : 7}})`);\n\t\t\tconst excerpt   = text\n\t\t\t\t// Strip macro tags (replace with a space).\n\t\t\t\t.replace(/<<.*?>>/g, ' ')\n\t\t\t\t// Strip html tags (replace with a space).\n\t\t\t\t.replace(/<.*?>/g, ' ')\n\t\t\t\t// The above might have left problematic whitespace, so trim.\n\t\t\t\t.trim()\n\t\t\t\t// Strip table markup.\n\t\t\t\t.replace(/^\\s*\\|.*\\|.*?$/gm, '')\n\t\t\t\t// Strip image markup.\n\t\t\t\t.replace(/\\[[<>]?img\\[[^\\]]*\\]\\]/g, '')\n\t\t\t\t// Clean link markup (remove all but the link text).\n\t\t\t\t.replace(/\\[\\[([^|\\]]*?)(?:(?:\\||->|<-)[^\\]]*)?\\]\\]/g, '$1')\n\t\t\t\t// Clean heading markup.\n\t\t\t\t.replace(/^\\s*!+(.*?)$/gm, '$1')\n\t\t\t\t// Clean bold/italic/underline/highlight styles.\n\t\t\t\t.replace(/'{2}|\\/{2}|_{2}|@{2}/g, '')\n\t\t\t\t// A final trim.\n\t\t\t\t.trim()\n\t\t\t\t// Compact whitespace.\n\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t// Attempt to match the excerpt regexp.\n\t\t\t\t.match(excerptRe);\n\t\t\treturn excerpt ? `${excerpt[1]}\\u2026` : '\\u2026'; // horizontal ellipsis\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Passage;\n})();\n\n/***********************************************************************************************************************\n\n\tsave.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Dialog, Engine, L10n, State, Story, UI, storage */\n\nvar Save = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// The upper bound of the saves slots.\n\tlet _slotsUBound = -1;\n\n\n\t/*******************************************************************************************************************\n\t\tSaves Functions.\n\t*******************************************************************************************************************/\n\tfunction savesInit() {\n\t\tif (DEBUG) { console.log('[Save/savesInit()]'); }\n\n\t\t// Disable save slots and the autosave when Web Storage is unavailable.\n\t\tif (storage.name === 'cookie') {\n\t\t\tsavesObjClear();\n\t\t\tConfig.saves.autoload = undefined;\n\t\t\tConfig.saves.autosave = undefined;\n\t\t\tConfig.saves.slots = 0;\n\t\t\treturn false;\n\t\t}\n\n\t\tlet saves   = savesObjGet();\n\t\tlet updated = false;\n\n\t\t/* legacy */\n\t\t// Convert an ancient saves array into a new saves object.\n\t\tif (Array.isArray(saves)) {\n\t\t\tsaves = {\n\t\t\t\tautosave : null,\n\t\t\t\tslots    : saves\n\t\t\t};\n\t\t\tupdated = true;\n\t\t}\n\t\t/* /legacy */\n\n\t\t// Handle the author changing the number of save slots.\n\t\tif (Config.saves.slots !== saves.slots.length) {\n\t\t\tif (Config.saves.slots < saves.slots.length) {\n\t\t\t\t// Attempt to decrease the number of slots; this will only compact\n\t\t\t\t// the slots array, by removing empty slots, no saves will be deleted.\n\t\t\t\tsaves.slots.reverse();\n\n\t\t\t\tsaves.slots = saves.slots.filter(function (val) {\n\t\t\t\t\tif (val === null && this.count > 0) {\n\t\t\t\t\t\t--this.count;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\t\t\t\t}, { count : saves.slots.length - Config.saves.slots });\n\n\t\t\t\tsaves.slots.reverse();\n\t\t\t}\n\t\t\telse if (Config.saves.slots > saves.slots.length) {\n\t\t\t\t// Attempt to increase the number of slots.\n\t\t\t\t_appendSlots(saves.slots, Config.saves.slots - saves.slots.length);\n\t\t\t}\n\n\t\t\tupdated = true;\n\t\t}\n\n\t\t/* legacy */\n\t\t// Update saves with old/obsolete properties.\n\t\tif (_savesObjUpdate(saves.autosave)) {\n\t\t\tupdated = true;\n\t\t}\n\n\t\tfor (let i = 0; i < saves.slots.length; ++i) {\n\t\t\tif (_savesObjUpdate(saves.slots[i])) {\n\t\t\t\tupdated = true;\n\t\t\t}\n\t\t}\n\n\t\t// Remove save stores which are empty.\n\t\tif (_savesObjIsEmpty(saves)) {\n\t\t\tstorage.delete('saves');\n\t\t\tupdated = false;\n\t\t}\n\t\t/* /legacy */\n\n\t\t// If the saves object was updated, then update the store.\n\t\tif (updated) {\n\t\t\t_savesObjSave(saves);\n\t\t}\n\n\t\t_slotsUBound = saves.slots.length - 1;\n\n\t\treturn true;\n\t}\n\n\tfunction savesObjCreate() {\n\t\treturn {\n\t\t\tautosave : null,\n\t\t\tslots    : _appendSlots([], Config.saves.slots)\n\t\t};\n\t}\n\n\tfunction savesObjGet() {\n\t\tconst saves = storage.get('saves');\n\t\treturn saves === null ? savesObjCreate() : saves;\n\t}\n\n\tfunction savesObjClear() {\n\t\tstorage.delete('saves');\n\t\treturn true;\n\t}\n\n\tfunction savesOk() {\n\t\treturn autosaveOk() || slotsOk();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAutosave Functions.\n\t*******************************************************************************************************************/\n\tfunction autosaveOk() {\n\t\treturn storage.name !== 'cookie' && typeof Config.saves.autosave !== 'undefined';\n\t}\n\n\tfunction autosaveHas() {\n\t\tconst saves = savesObjGet();\n\n\t\tif (saves.autosave === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction autosaveGet() {\n\t\tconst saves = savesObjGet();\n\t\treturn saves.autosave;\n\t}\n\n\tfunction autosaveLoad() {\n\t\tconst saves = savesObjGet();\n\n\t\tif (saves.autosave === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn _unmarshal(saves.autosave);\n\t}\n\n\tfunction autosaveSave(title, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves        = savesObjGet();\n\t\tconst supplemental = {\n\t\t\ttitle : title || Story.get(State.passage).description(),\n\t\t\tdate  : Date.now()\n\t\t};\n\n\t\tif (metadata != null) { // lazy equality for null\n\t\t\tsupplemental.metadata = metadata;\n\t\t}\n\n\t\tsaves.autosave = _marshal(supplemental);\n\n\t\treturn _savesObjSave(saves);\n\t}\n\n\tfunction autosaveDelete() {\n\t\tconst saves = savesObjGet();\n\t\tsaves.autosave = null;\n\t\treturn _savesObjSave(saves);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSlots Functions.\n\t*******************************************************************************************************************/\n\tfunction slotsOk() {\n\t\treturn storage.name !== 'cookie' && _slotsUBound !== -1;\n\t}\n\n\tfunction slotsLength() {\n\t\treturn _slotsUBound + 1;\n\t}\n\n\tfunction slotsCount() {\n\t\tif (!slotsOk()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\t\tlet count = 0;\n\n\t\tfor (let i = 0, iend = saves.slots.length; i < iend; ++i) {\n\t\t\tif (saves.slots[i] !== null) {\n\t\t\t\t++count;\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n\n\tfunction slotsIsEmpty() {\n\t\treturn slotsCount() === 0;\n\t}\n\n\tfunction slotsHas(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length || saves.slots[slot] === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction slotsGet(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn saves.slots[slot];\n\t}\n\n\tfunction slotsLoad(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length || saves.slots[slot] === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn _unmarshal(saves.slots[slot]);\n\t}\n\n\tfunction slotsSave(slot, title, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst supplemental = {\n\t\t\ttitle : title || Story.get(State.passage).description(),\n\t\t\tdate  : Date.now()\n\t\t};\n\n\t\tif (metadata != null) { // lazy equality for null\n\t\t\tsupplemental.metadata = metadata;\n\t\t}\n\n\t\tsaves.slots[slot] = _marshal(supplemental);\n\n\t\treturn _savesObjSave(saves);\n\t}\n\n\tfunction slotsDelete(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tsaves.slots[slot] = null;\n\t\treturn _savesObjSave(saves);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tDisk Import/Export Functions.\n\t*******************************************************************************************************************/\n\tfunction exportToDisk(filename, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tfunction datestamp() {\n\t\t\tconst now = new Date();\n\t\t\tlet MM = now.getMonth() + 1;\n\t\t\tlet DD = now.getDate();\n\t\t\tlet hh = now.getHours();\n\t\t\tlet mm = now.getMinutes();\n\t\t\tlet ss = now.getSeconds();\n\n\t\t\tif (MM < 10) { MM = `0${MM}`; }\n\t\t\tif (DD < 10) { DD = `0${DD}`; }\n\t\t\tif (hh < 10) { hh = `0${hh}`; }\n\t\t\tif (mm < 10) { mm = `0${mm}`; }\n\t\t\tif (ss < 10) { ss = `0${ss}`; }\n\n\t\t\treturn `${now.getFullYear()}${MM}${DD}-${hh}${mm}${ss}`;\n\t\t}\n\n\t\tfunction legalizeName(str) {\n\t\t\t/*\n\t\t\t\tNOTE: The range of illegal characters consists of: C0 controls, double quote,\n\t\t\t\tnumber, dollar, percent, ampersand, single quote, asterisk, plus, comma,\n\t\t\t\tforward slash, colon, semi-colon, less-than, equals, greater-than, question,\n\t\t\t\tbackslash, caret, backquote/grave, pipe/vertical-bar, delete, C1 controls.\n\t\t\t*/\n\t\t\treturn String(str).trim()\n\t\t\t\t.replace(/[\\x00-\\x1f\"#$%&'*+,/:;<=>?\\\\^`|\\x7f-\\x9f]+/g, '') // eslint-disable-line no-control-regex\n\t\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-'); // legacy\n\t\t}\n\n\t\tconst baseName     = filename == null ? Story.domId : legalizeName(filename); // lazy equality for null\n\t\tconst saveName     = `${baseName}-${datestamp()}.save`;\n\t\tconst supplemental = metadata == null ? {} : { metadata }; // lazy equality for null\n\t\tconst saveObj      = LZString.compressToBase64(JSON.stringify(_marshal(supplemental)));\n\t\tsaveAs(new Blob([saveObj], { type : 'text/plain;charset=UTF-8' }), saveName);\n\t}\n\n\tfunction importFromDisk(event) {\n\t\tconst file   = event.target.files[0];\n\t\tconst reader = new FileReader();\n\n\t\t// Add the handler that will capture the file information once the load is finished.\n\t\tjQuery(reader).on('load', ev => {\n\t\t\tconst target = ev.currentTarget;\n\n\t\t\tif (!target.result) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet saveObj;\n\n\t\t\ttry {\n\t\t\t\tsaveObj = JSON.parse(\n\t\t\t\t\t/* legacy */ /\\.json$/i.test(file.name) || /^\\{/.test(target.result)\n\t\t\t\t\t\t? target.result\n\t\t\t\t\t\t: /* /legacy */ LZString.decompressFromBase64(target.result)\n\t\t\t\t);\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op; `_unmarshal()` will handle the error */ }\n\n\t\t\t_unmarshal(saveObj);\n\t\t});\n\n\t\t// Initiate the file load.\n\t\treader.readAsText(file);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSerialization Functions.\n\t*******************************************************************************************************************/\n\tfunction serialize(metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tconst supplemental = metadata == null ? {} : { metadata }; // lazy equality for null\n\t\treturn LZString.compressToBase64(JSON.stringify(_marshal(supplemental)));\n\t}\n\n\tfunction deserialize(base64Str) {\n\t\t/*\n\t\t\tNOTE: We purposefully do not attempt to catch parameter shenanigans\n\t\t\there, instead relying on `_unmarshal()` to do the heavy lifting.\n\t\t*/\n\n\t\tlet saveObj;\n\n\t\ttry {\n\t\t\tsaveObj = JSON.parse(LZString.decompressFromBase64(base64Str));\n\t\t}\n\t\tcatch (ex) { /* no-op; `_unmarshal()` will handle the error */ }\n\n\t\tif (!_unmarshal(saveObj)) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn saveObj.metadata;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _appendSlots(array, num) {\n\t\tfor (let i = 0; i < num; ++i) {\n\t\t\tarray.push(null);\n\t\t}\n\n\t\treturn array;\n\t}\n\n\tfunction _savesObjIsEmpty(saves) {\n\t\tconst slots = saves.slots;\n\t\tlet isSlotsEmpty = true;\n\n\t\tfor (let i = 0, iend = slots.length; i < iend; ++i) {\n\t\t\tif (slots[i] !== null) {\n\t\t\t\tisSlotsEmpty = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn saves.autosave === null && isSlotsEmpty;\n\t}\n\n\tfunction _savesObjSave(saves) {\n\t\tif (_savesObjIsEmpty(saves)) {\n\t\t\tstorage.delete('saves');\n\t\t\treturn true;\n\t\t}\n\n\t\treturn storage.set('saves', saves);\n\t}\n\n\tfunction _savesObjUpdate(saveObj) {\n\t\tif (saveObj == null || typeof saveObj !== 'object') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tlet updated = false;\n\n\t\t/* eslint-disable no-param-reassign */\n\t\tif (\n\t\t\t   !saveObj.hasOwnProperty('state')\n\t\t\t|| !saveObj.state.hasOwnProperty('delta')\n\t\t\t|| !saveObj.state.hasOwnProperty('index')\n\t\t) {\n\t\t\tif (saveObj.hasOwnProperty('data')) {\n\t\t\t\tdelete saveObj.mode;\n\t\t\t\tsaveObj.state = {\n\t\t\t\t\tdelta : State.deltaEncode(saveObj.data)\n\t\t\t\t};\n\t\t\t\tdelete saveObj.data;\n\t\t\t}\n\t\t\telse if (!saveObj.state.hasOwnProperty('delta')) {\n\t\t\t\tdelete saveObj.state.mode;\n\t\t\t\tsaveObj.state.delta = State.deltaEncode(saveObj.state.history);\n\t\t\t\tdelete saveObj.state.history;\n\t\t\t}\n\t\t\telse if (!saveObj.state.hasOwnProperty('index')) {\n\t\t\t\tdelete saveObj.state.mode;\n\t\t\t}\n\n\t\t\tsaveObj.state.index = saveObj.state.delta.length - 1;\n\t\t\tupdated = true;\n\t\t}\n\n\t\tif (saveObj.state.hasOwnProperty('rseed')) {\n\t\t\tsaveObj.state.seed = saveObj.state.rseed;\n\t\t\tdelete saveObj.state.rseed;\n\n\t\t\tsaveObj.state.delta.forEach((_, i, delta) => {\n\t\t\t\tif (delta[i].hasOwnProperty('rcount')) {\n\t\t\t\t\tdelta[i].pull = delta[i].rcount;\n\t\t\t\t\tdelete delta[i].rcount;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tupdated = true;\n\t\t}\n\n\t\tif (\n\t\t\t   saveObj.state.hasOwnProperty('expired') && typeof saveObj.state.expired === 'number'\n\t\t\t||  saveObj.state.hasOwnProperty('unique')\n\t\t\t||  saveObj.state.hasOwnProperty('last')\n\t\t) {\n\t\t\tif (saveObj.state.hasOwnProperty('expired') && typeof saveObj.state.expired === 'number') {\n\t\t\t\tdelete saveObj.state.expired;\n\t\t\t}\n\n\t\t\tif (saveObj.state.hasOwnProperty('unique') || saveObj.state.hasOwnProperty('last')) {\n\t\t\t\tsaveObj.state.expired = [];\n\n\t\t\t\tif (saveObj.state.hasOwnProperty('unique')) {\n\t\t\t\t\tsaveObj.state.expired.push(saveObj.state.unique);\n\t\t\t\t\tdelete saveObj.state.unique;\n\t\t\t\t}\n\n\t\t\t\tif (saveObj.state.hasOwnProperty('last')) {\n\t\t\t\t\tsaveObj.state.expired.push(saveObj.state.last);\n\t\t\t\t\tdelete saveObj.state.last;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tupdated = true;\n\t\t}\n\t\t/* eslint-enable no-param-reassign */\n\n\t\treturn updated;\n\t}\n\n\tfunction _marshal(supplemental) {\n\t\tif (DEBUG) { console.log('[Save/_marshal()]'); }\n\n\t\tif (supplemental != null && typeof supplemental !== 'object') { // lazy equality for null\n\t\t\tthrow new Error('supplemental parameter must be an object');\n\t\t}\n\n\t\tconst saveObj = Object.assign({}, supplemental, {\n\t\t\tid    : Config.saves.id,\n\t\t\tstate : State.marshalForSave()\n\t\t});\n\n\t\tif (Config.saves.version) {\n\t\t\tsaveObj.version = Config.saves.version;\n\t\t}\n\n\t\tif (typeof Config.saves.onSave === 'function') {\n\t\t\tConfig.saves.onSave(saveObj);\n\t\t}\n\n\t\t// Delta encode the state history and delete the non-encoded property.\n\t\tsaveObj.state.delta = State.deltaEncode(saveObj.state.history);\n\t\tdelete saveObj.state.history;\n\n\t\treturn saveObj;\n\t}\n\n\tfunction _unmarshal(saveObj) {\n\t\tif (DEBUG) { console.log('[Save/_unmarshal()]'); }\n\n\t\ttry {\n\t\t\t/* eslint-disable no-param-reassign */\n\t\t\t/* legacy */\n\t\t\t// Update saves with old/obsolete properties.\n\t\t\t_savesObjUpdate(saveObj);\n\t\t\t/* /legacy */\n\n\t\t\tif (!saveObj || !saveObj.hasOwnProperty('id') || !saveObj.hasOwnProperty('state')) {\n\t\t\t\tthrow new Error(L10n.get('errorSaveMissingData'));\n\t\t\t}\n\n\t\t\t// Delta decode the state history and delete the encoded property.\n\t\t\tsaveObj.state.history = State.deltaDecode(saveObj.state.delta);\n\t\t\tdelete saveObj.state.delta;\n\n\t\t\tif (typeof Config.saves.onLoad === 'function') {\n\t\t\t\tConfig.saves.onLoad(saveObj);\n\t\t\t}\n\n\t\t\tif (saveObj.id !== Config.saves.id) {\n\t\t\t\tthrow new Error(L10n.get('errorSaveIdMismatch'));\n\t\t\t}\n\n\t\t\t// Restore the state.\n\t\t\tState.unmarshalForSave(saveObj.state); // may also throw exceptions\n\n\t\t\t// Show the active moment.\n\t\t\tEngine.show();\n\t\t\t/* eslint-enable no-param-reassign */\n\t\t}\n\t\tcatch (ex) {\n\t\t\tUI.alert(`${ex.message.toUpperFirst()}.</p><p>${L10n.get('aborting')}.`);\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tSave Functions.\n\t\t*/\n\t\tinit  : { value : savesInit },\n\t\tget   : { value : savesObjGet },\n\t\tclear : { value : savesObjClear },\n\t\tok    : { value : savesOk },\n\n\t\t/*\n\t\t\tAutosave Functions.\n\t\t*/\n\t\tautosave : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tok     : { value : autosaveOk },\n\t\t\t\thas    : { value : autosaveHas },\n\t\t\t\tget    : { value : autosaveGet },\n\t\t\t\tload   : { value : autosaveLoad },\n\t\t\t\tsave   : { value : autosaveSave },\n\t\t\t\tdelete : { value : autosaveDelete }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tSlots Functions.\n\t\t*/\n\t\tslots : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tok      : { value : slotsOk },\n\t\t\t\tlength  : { get : slotsLength },\n\t\t\t\tisEmpty : { value : slotsIsEmpty },\n\t\t\t\tcount   : { value : slotsCount },\n\t\t\t\thas     : { value : slotsHas },\n\t\t\t\tget     : { value : slotsGet },\n\t\t\t\tload    : { value : slotsLoad },\n\t\t\t\tsave    : { value : slotsSave },\n\t\t\t\tdelete  : { value : slotsDelete }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tDisk Import/Export Functions.\n\t\t*/\n\t\texport : { value : exportToDisk },\n\t\timport : { value : importFromDisk },\n\n\t\t/*\n\t\t\tSerialization Functions.\n\t\t*/\n\t\tserialize   : { value : serialize },\n\t\tdeserialize : { value : deserialize }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tsetting.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util, settings:true, storage */\n\nvar Setting = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Setting control types object (pseudo-enumeration).\n\tconst Types = Util.toEnum({\n\t\tHeader : 0,\n\t\tToggle : 1,\n\t\tList   : 2,\n\t\tRange  : 3\n\t});\n\n\t// Setting definition array.\n\tconst _definitions = [];\n\n\n\t/*******************************************************************************************************************\n\t\tSettings Functions.\n\t*******************************************************************************************************************/\n\tfunction settingsInit() {\n\t\tif (DEBUG) { console.log('[Setting/settingsInit()]'); }\n\n\t\t/* legacy */\n\t\t// Attempt to migrate an existing `options` store to `settings`.\n\t\tif (storage.has('options')) {\n\t\t\tconst old = storage.get('options');\n\n\t\t\tif (old !== null) {\n\t\t\t\twindow.SugarCube.settings = settings = Object.assign(settingsCreate(), old);\n\t\t\t}\n\n\t\t\tsettingsSave();\n\t\t\tstorage.delete('options');\n\t\t}\n\t\t/* /legacy */\n\n\t\t// Load existing settings.\n\t\tsettingsLoad();\n\n\t\t// Execute `onInit` callbacks.\n\t\t_definitions.forEach(def => {\n\t\t\tif (def.hasOwnProperty('onInit')) {\n\t\t\t\tconst thisArg = {\n\t\t\t\t\tname    : def.name,\n\t\t\t\t\tvalue   : settings[def.name],\n\t\t\t\t\tdefault : def.default\n\t\t\t\t};\n\n\t\t\t\tif (def.hasOwnProperty('list')) {\n\t\t\t\t\tthisArg.list = def.list;\n\t\t\t\t}\n\n\t\t\t\tdef.onInit.call(thisArg);\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction settingsCreate() {\n\t\treturn Object.create(null);\n\t}\n\n\tfunction settingsSave() {\n\t\tconst savedSettings = settingsCreate();\n\n\t\tif (Object.keys(settings).length > 0) {\n\t\t\t_definitions\n\t\t\t\t.filter(def => def.type !== Types.Header && settings[def.name] !== def.default)\n\t\t\t\t.forEach(def => savedSettings[def.name] = settings[def.name]);\n\t\t}\n\n\t\tif (Object.keys(savedSettings).length === 0) {\n\t\t\tstorage.delete('settings');\n\t\t\treturn true;\n\t\t}\n\n\t\treturn storage.set('settings', savedSettings);\n\t}\n\n\tfunction settingsLoad() {\n\t\tconst defaultSettings = settingsCreate();\n\t\tconst loadedSettings  = storage.get('settings') || settingsCreate();\n\n\t\t// Load the defaults.\n\t\t_definitions\n\t\t\t.filter(def => def.type !== Types.Header)\n\t\t\t.forEach(def => defaultSettings[def.name] = def.default);\n\n\t\t// Assign to the `settings` object while overwriting the defaults with the loaded settings.\n\t\twindow.SugarCube.settings = settings = Object.assign(defaultSettings, loadedSettings);\n\t}\n\n\tfunction settingsClear() {\n\t\twindow.SugarCube.settings = settings = settingsCreate();\n\t\tstorage.delete('settings');\n\t\treturn true;\n\t}\n\n\tfunction settingsReset(name) {\n\t\tif (arguments.length === 0) {\n\t\t\tsettingsClear();\n\t\t\tsettingsLoad();\n\t\t}\n\t\telse {\n\t\t\tif (name == null || !definitionsHas(name)) { // lazy equality for null\n\t\t\t\tthrow new Error(`nonexistent setting \"${name}\"`);\n\t\t\t}\n\n\t\t\tconst def = definitionsGet(name);\n\n\t\t\tif (def.type !== Types.Header) {\n\t\t\t\tsettings[name] = def.default;\n\t\t\t}\n\t\t}\n\n\t\treturn settingsSave();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tDefinitions Functions.\n\t*******************************************************************************************************************/\n\tfunction definitionsForEach(callback, thisArg) {\n\t\t_definitions.forEach(callback, thisArg);\n\t}\n\n\tfunction definitionsAdd(type, name, def) {\n\t\tif (arguments.length < 3) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('type'); }\n\t\t\tif (arguments.length < 2) { errors.push('name'); }\n\t\t\tif (arguments.length < 3) { errors.push('definition'); }\n\t\t\tthrow new Error(`missing parameters, no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tif (typeof def !== 'object') {\n\t\t\tthrow new TypeError('definition parameter must be an object');\n\t\t}\n\n\t\tif (definitionsHas(name)) {\n\t\t\tthrow new Error(`cannot clobber existing setting \"${name}\"`);\n\t\t}\n\n\t\t/*\n\t\t\tDefinition object properties and types:\n\t\t\t\ttype      →  (all)   → Setting.Types\n\t\t\t\tname      →  (all)   → string\n\t\t\t\tlabel     →  (all)   → string\n\t\t\t\tdesc      →  (all)   → string\n\t\t\t\tdefault\n\t\t\t\t\t(if defined)\n \t\t\t\t\t\t  →  Toggle  → boolean\n\t\t\t\t\t\t  →  List    → Array\n\t\t\t\t\t\t  →  Range   → number\n\t\t\t\t\t(if undefined)\n\t\t\t\t\t\t  →  Toggle  → false\n\t\t\t\t\t\t  →  List    → list[0]\n\t\t\t\t\t\t  →  Range   → max\n\t\t\t\tlist      →  List    → Array\n\t\t\t\tmin       →  Range   → number\n\t\t\t\tmax       →  Range   → number\n\t\t\t\tstep      →  Range   → number\n\t\t\t\tonInit    →  (all)   → function\n\t\t\t\tonChange  →  (all)   → function\n\t\t*/\n\t\tconst definition = {\n\t\t\ttype,\n\t\t\tname,\n\t\t\tlabel : typeof def.label === 'string' ? def.label.trim() : ''\n\t\t};\n\n\t\tif (typeof def.desc === 'string') {\n\t\t\tconst desc = def.desc.trim();\n\n\t\t\tif (desc !== '') {\n\t\t\t\tdefinition.desc = desc;\n\t\t\t}\n\t\t}\n\n\t\tswitch (type) {\n\t\tcase Types.Header:\n\t\t\tbreak;\n\n\t\tcase Types.Toggle:\n\t\t\tdefinition.default = !!def.default;\n\t\t\tbreak;\n\n\t\tcase Types.List:\n\t\t\tif (!def.hasOwnProperty('list')) {\n\t\t\t\tthrow new Error('no list specified');\n\t\t\t}\n\t\t\telse if (!Array.isArray(def.list)) {\n\t\t\t\tthrow new TypeError('list must be an array');\n\t\t\t}\n\t\t\telse if (def.list.length === 0) {\n\t\t\t\tthrow new Error('list must not be empty');\n\t\t\t}\n\n\t\t\tdefinition.list = Object.freeze(def.list);\n\n\t\t\tif (def.default == null) { // lazy equality for null\n\t\t\t\tdefinition.default = def.list[0];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst defaultIndex = def.list.indexOf(def.default);\n\n\t\t\t\tif (defaultIndex === -1) {\n\t\t\t\t\tthrow new Error('list does not contain default');\n\t\t\t\t}\n\n\t\t\t\tdefinition.default = def.list[defaultIndex];\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase Types.Range:\n\t\t\tif (!def.hasOwnProperty('min')) {\n\t\t\t\tthrow new Error('no min specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.min !== 'number'\n\t\t\t\t|| Number.isNaN(def.min)\n\t\t\t\t|| !Number.isFinite(def.min)\n\t\t\t) {\n\t\t\t\tthrow new TypeError('min must be a finite number');\n\t\t\t}\n\n\t\t\tif (!def.hasOwnProperty('max')) {\n\t\t\t\tthrow new Error('no max specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.max !== 'number'\n\t\t\t\t|| Number.isNaN(def.max)\n\t\t\t\t|| !Number.isFinite(def.max)\n\t\t\t) {\n\t\t\t\tthrow new TypeError('max must be a finite number');\n\t\t\t}\n\n\t\t\tif (!def.hasOwnProperty('step')) {\n\t\t\t\tthrow new Error('no step specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.step !== 'number'\n\t\t\t\t|| Number.isNaN(def.step)\n\t\t\t\t|| !Number.isFinite(def.step)\n\t\t\t\t|| def.step <= 0\n\t\t\t) {\n\t\t\t\tthrow new TypeError('step must be a finite number greater than zero');\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Determine how many fractional digits we need to be concerned with based on the step value.\n\t\t\t\tconst fracDigits = (() => {\n\t\t\t\t\tconst str = String(def.step);\n\t\t\t\t\tconst pos = str.lastIndexOf('.');\n\t\t\t\t\treturn pos === -1 ? 0 : str.length - pos - 1;\n\t\t\t\t})();\n\n\t\t\t\t// Set up a function to validate a given value against the step value.\n\t\t\t\tfunction stepValidate(value) {\n\t\t\t\t\tif (fracDigits > 0) {\n\t\t\t\t\t\tconst ma = Number(`${def.min}e${fracDigits}`);\n\t\t\t\t\t\tconst sa = Number(`${def.step}e${fracDigits}`);\n\t\t\t\t\t\tconst va = Number(`${value}e${fracDigits}`) - ma;\n\t\t\t\t\t\treturn Number(`${va - va % sa + ma}e-${fracDigits}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst va = value - def.min;\n\t\t\t\t\treturn va - va % def.step + def.min;\n\t\t\t\t}\n\n\t\t\t\t// Sanity check the max value against the step value.\n\t\t\t\tif (stepValidate(def.max) !== def.max) {\n\t\t\t\t\tthrow new RangeError(`max (${def.max}) is not a multiple of the step (${def.step}) plus the min (${def.min})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdefinition.max = def.max;\n\t\t\tdefinition.min = def.min;\n\t\t\tdefinition.step = def.step;\n\n\t\t\tif (def.default == null) { // lazy equality for null\n\t\t\t\tdefinition.default = def.max;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (\n\t\t\t\t\t   typeof def.default !== 'number'\n\t\t\t\t\t|| Number.isNaN(def.default)\n\t\t\t\t\t|| !Number.isFinite(def.default)\n\t\t\t\t) {\n\t\t\t\t\tthrow new TypeError('default must be a finite number');\n\t\t\t\t}\n\t\t\t\telse if (def.default < def.min) {\n\t\t\t\t\tthrow new RangeError(`default (${def.default}) is less than min (${def.min})`);\n\t\t\t\t}\n\t\t\t\telse if (def.default > def.max) {\n\t\t\t\t\tthrow new RangeError(`default (${def.default}) is greater than max (${def.max})`);\n\t\t\t\t}\n\n\t\t\t\tdefinition.default = def.default;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new Error(`unknown Setting type: ${type}`);\n\t\t}\n\n\t\tif (typeof def.onInit === 'function') {\n\t\t\tdefinition.onInit = Object.freeze(def.onInit);\n\t\t}\n\n\t\tif (typeof def.onChange === 'function') {\n\t\t\tdefinition.onChange = Object.freeze(def.onChange);\n\t\t}\n\n\t\t_definitions.push(Object.freeze(definition));\n\t}\n\n\tfunction definitionsAddHeader(name, desc) {\n\t\tdefinitionsAdd(Types.Header, name, { desc });\n\t}\n\n\tfunction definitionsAddToggle(...args) {\n\t\tdefinitionsAdd(Types.Toggle, ...args);\n\t}\n\n\tfunction definitionsAddList(...args) {\n\t\tdefinitionsAdd(Types.List, ...args);\n\t}\n\n\tfunction definitionsAddRange(...args) {\n\t\tdefinitionsAdd(Types.Range, ...args);\n\t}\n\n\tfunction definitionsIsEmpty() {\n\t\treturn _definitions.length === 0;\n\t}\n\n\tfunction definitionsHas(name) {\n\t\treturn _definitions.some(definition => definition.name === name);\n\t}\n\n\tfunction definitionsGet(name) {\n\t\treturn _definitions.find(definition => definition.name === name);\n\t}\n\n\tfunction definitionsDelete(name) {\n\t\tif (definitionsHas(name)) {\n\t\t\tdelete settings[name];\n\t\t}\n\n\t\tfor (let i = 0; i < _definitions.length; ++i) {\n\t\t\tif (_definitions[i].name === name) {\n\t\t\t\t_definitions.splice(i, 1);\n\t\t\t\tdefinitionsDelete(name);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tEnumerations.\n\t\t*/\n\t\tTypes : { value : Types },\n\n\t\t/*\n\t\t\tSettings Functions.\n\t\t*/\n\t\tinit   : { value : settingsInit },\n\t\tcreate : { value : settingsCreate },\n\t\tsave   : { value : settingsSave },\n\t\tload   : { value : settingsLoad },\n\t\tclear  : { value : settingsClear },\n\t\treset  : { value : settingsReset },\n\n\t\t/*\n\t\t\tDefinitions Functions.\n\t\t*/\n\t\tforEach   : { value : definitionsForEach },\n\t\tadd       : { value : definitionsAdd },\n\t\taddHeader : { value : definitionsAddHeader },\n\t\taddToggle : { value : definitionsAddToggle },\n\t\taddList   : { value : definitionsAddList },\n\t\taddRange  : { value : definitionsAddRange },\n\t\tisEmpty   : { value : definitionsIsEmpty },\n\t\thas       : { value : definitionsHas },\n\t\tget       : { value : definitionsGet },\n\t\tdelete    : { value : definitionsDelete }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tstory.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Alert, Config, Passage, Scripting, StyleWrapper, Util, Wikifier */\n\nvar Story = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Map of normal passages.\n\tconst _passages = {};\n\n\t// List of script passages.\n\tconst _scripts = [];\n\n\t// List of style passages.\n\tconst _styles = [];\n\n\t// List of widget passages.\n\tconst _widgets = [];\n\n\t// Story title.\n\tlet _title = '';\n\n\t// Story IFID.\n\tlet _ifId = '';\n\n\t// DOM-compatible ID.\n\tlet _domId = '';\n\n\n\t/*******************************************************************************************************************\n\t\tStory Functions.\n\t*******************************************************************************************************************/\n\tfunction storyLoad() {\n\t\tif (DEBUG) { console.log('[Story/storyLoad()]'); }\n\n\t\tconst validationCodeTags = [\n\t\t\t'widget'\n\t\t];\n\t\tconst validationNoCodeTagPassages = [\n\t\t\t'PassageDone',\n\t\t\t'PassageFooter',\n\t\t\t'PassageHeader',\n\t\t\t'PassageReady',\n\t\t\t'StoryAuthor',\n\t\t\t'StoryBanner',\n\t\t\t'StoryCaption',\n\t\t\t'StoryInit',\n\t\t\t'StoryMenu',\n\t\t\t'StoryShare',\n\t\t\t'StorySubtitle'\n\t\t];\n\n\t\tfunction validateStartingPassage(passage) {\n\t\t\tif (passage.tags.includesAny(validationCodeTags)) {\n\t\t\t\tthrow new Error(`starting passage \"${passage.title}\" contains illegal tags; invalid: \"${passage.tags.filter(tag => validationCodeTags.includes(tag)).sort().join('\", \"')}\"`);\n\t\t\t}\n\t\t}\n\n\t\tfunction validateSpecialPassages(passage) {\n\t\t\tif (validationNoCodeTagPassages.includes(passage.title) && passage.tags.includesAny(validationCodeTags)) {\n\t\t\t\tthrow new Error(`special passage \"${passage.title}\" contains illegal tags; invalid: \"${passage.tags.filter(tag => validationCodeTags.includes(tag)).sort().join('\", \"')}\"`);\n\t\t\t}\n\t\t}\n\n\t\t// For Twine 1.\n\t\tif (TWINE1) {\n\t\t\t/*\n\t\t\t\tAdditional Twine 1 validation setup.\n\t\t\t*/\n\t\t\tvalidationCodeTags.unshift('script', 'stylesheet');\n\t\t\tvalidationNoCodeTagPassages.push('StoryTitle');\n\n\t\t\tfunction validateTwine1CodePassages(passage) {\n\t\t\t\tconst codeTags  = [...validationCodeTags];\n\t\t\t\tconst foundTags = [];\n\n\t\t\t\tpassage.tags.forEach(tag => {\n\t\t\t\t\tif (codeTags.includes(tag)) {\n\t\t\t\t\t\tfoundTags.push(...codeTags.delete(tag));\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (foundTags.length > 1) {\n\t\t\t\t\tthrow new Error(`code passage \"${passage.title}\" contains multiple code tags; invalid: \"${foundTags.sort().join('\", \"')}\"`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet the default starting passage.\n\t\t\t*/\n\t\t\tConfig.passages.start = (() => {\n\t\t\t\t/*\n\t\t\t\t\tHandle the Twine 1.4+ Test Play From Here feature.\n\n\t\t\t\t\tWARNING: Do not remove the `String()` wrapper from or change the quote\n\t\t\t\t\tstyle of the `\"START_AT\"` replacement target.  The former is there to\n\t\t\t\t\tkeep UglifyJS from pruning the code into oblivion—i.e. minifying the\n\t\t\t\t\tcode into something broken.  The latter is there because the Twine 1\n\t\t\t\t\tpattern that matches it depends upon the double quotes.\n\n\t\t\t\t*/\n\t\t\t\tconst testPlay = String(\"START_AT\"); // eslint-disable-line quotes\n\n\t\t\t\tif (testPlay !== '') {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tTest play; starting passage: \"${testPlay}\"`); }\n\n\t\t\t\t\tConfig.debug = true;\n\t\t\t\t\treturn testPlay;\n\t\t\t\t}\n\n\t\t\t\t// In the absence of a `testPlay` value, return 'Start'.\n\t\t\t\treturn 'Start';\n\t\t\t})();\n\n\t\t\t/*\n\t\t\t\tProcess the passages, excluding any tagged 'Twine.private' or 'annotation'.\n\t\t\t*/\n\t\t\tjQuery('#store-area')\n\t\t\t\t.children(':not([tags~=\"Twine.private\"],[tags~=\"annotation\"])')\n\t\t\t\t.each(function () {\n\t\t\t\t\tconst $this   = jQuery(this);\n\t\t\t\t\tconst passage = new Passage($this.attr('tiddler'), this);\n\n\t\t\t\t\t// Special cases.\n\t\t\t\t\tif (passage.title === Config.passages.start) {\n\t\t\t\t\t\tvalidateStartingPassage(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('stylesheet')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_styles.push(passage);\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('script')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_scripts.push(passage);\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('widget')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_widgets.push(passage);\n\t\t\t\t\t}\n\n\t\t\t\t\t// All other passages.\n\t\t\t\t\telse {\n\t\t\t\t\t\tvalidateSpecialPassages(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tSet the story title or throw an exception.\n\t\t\t*/\n\t\t\tif (_passages.hasOwnProperty('StoryTitle')) {\n\t\t\t\tconst buf = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(buf, _passages.StoryTitle.processText().trim());\n\t\t\t\t_storySetTitle(buf.textContent);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('cannot find the \"StoryTitle\" special passage');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet the default saves ID (must be done after the call to `_storySetTitle()`).\n\t\t\t*/\n\t\t\tConfig.saves.id = Story.domId;\n\t\t}\n\n\t\t// For Twine 2.\n\t\telse {\n\t\t\tconst $storydata = jQuery('tw-storydata');\n\t\t\tconst startNode  = $storydata.attr('startnode') || '';\n\n\t\t\t/*\n\t\t\t\tSet the default starting passage.\n\t\t\t*/\n\t\t\tConfig.passages.start = null; // no default in Twine 2\n\n\t\t\t/*\n\t\t\t\tProcess story options.\n\n\t\t\t\tNOTE: Currently, the only option of interest is 'debug', so we\n\t\t\t\tsimply use a regular expression to check for it.\n\t\t\t*/\n\t\t\tConfig.debug = /\\bdebug\\b/.test($storydata.attr('options'));\n\n\t\t\t/*\n\t\t\t\tProcess stylesheet passages.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('style') // alternatively: '[type=\"text/twine-css\"]' or '#twine-user-stylesheet'\n\t\t\t\t.each(function (i) {\n\t\t\t\t\t_styles.push(new Passage(`tw-user-style-${i}`, this));\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tProcess script passages.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('script') // alternatively: '[type=\"text/twine-javascript\"]' or '#twine-user-script'\n\t\t\t\t.each(function (i) {\n\t\t\t\t\t_scripts.push(new Passage(`tw-user-script-${i}`, this));\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tProcess normal passages, excluding any tagged 'Twine.private' or 'annotation'.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('tw-passagedata:not([tags~=\"Twine.private\"],[tags~=\"annotation\"])')\n\t\t\t\t.each(function () {\n\t\t\t\t\tconst $this   = jQuery(this);\n\t\t\t\t\tconst pid     = $this.attr('pid') || '';\n\t\t\t\t\tconst passage = new Passage($this.attr('name'), this);\n\n\t\t\t\t\t// Special cases.\n\t\t\t\t\tif (pid === startNode && startNode !== '') {\n\t\t\t\t\t\tConfig.passages.start = passage.title;\n\t\t\t\t\t\tvalidateStartingPassage(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('widget')) {\n\t\t\t\t\t\t_widgets.push(passage);\n\t\t\t\t\t}\n\n\t\t\t\t\t// All other passages.\n\t\t\t\t\telse {\n\t\t\t\t\t\tvalidateSpecialPassages(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tGet the story IFID.\n\t\t\t*/\n\t\t\t_ifId = $storydata.attr('ifid');\n\n\t\t\t/*\n\t\t\t\tSet the story title.\n\n\t\t\t\tFIXME: Maybe `$storydata.attr('name')` should be used instead of `'{{STORY_NAME}}'`?\n\t\t\t*/\n\t\t\t// _storySetTitle($storydata.attr('name'));\n\t\t\t_storySetTitle('{{STORY_NAME}}');\n\n\t\t\t/*\n\t\t\t\tSet the default saves ID (must be done after the call to `_storySetTitle()`).\n\t\t\t*/\n\t\t\tConfig.saves.id = Story.domId;\n\t\t}\n\t}\n\n\tfunction storyInit() {\n\t\tif (DEBUG) { console.log('[Story/storyInit()]'); }\n\n\t\t/*\n\t\t\tAdd the story styles.\n\t\t*/\n\t\t(() => {\n\t\t\tconst storyStyle = document.createElement('style');\n\n\t\t\t(new StyleWrapper(storyStyle))\n\t\t\t\t.add(_styles.map(style => style.text.trim()).join('\\n'));\n\n\t\t\tjQuery(storyStyle)\n\t\t\t\t.appendTo(document.head)\n\t\t\t\t.attr({\n\t\t\t\t\tid   : 'style-story',\n\t\t\t\t\ttype : 'text/css'\n\t\t\t\t});\n\t\t})();\n\n\t\t/*\n\t\t\tEvaluate the story scripts.\n\t\t*/\n\t\tfor (let i = 0; i < _scripts.length; ++i) {\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(_scripts[i].text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error(_scripts[i].title, typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t\tProcess the story widgets.\n\t\t*/\n\t\tfor (let i = 0; i < _widgets.length; ++i) {\n\t\t\ttry {\n\t\t\t\tWikifier.wikifyEval(_widgets[i].processText());\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error(_widgets[i].title, typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction _storySetTitle(rawTitle) {\n\t\tif (rawTitle == null) { // lazy equality for null\n\t\t\tthrow new Error('story title must not be null or undefined');\n\t\t}\n\n\t\tconst title = Util.unescape(String(rawTitle)).trim();\n\n\t\tif (title === '') { // lazy equality for null\n\t\t\tthrow new Error('story title must not be empty or consist solely of whitespace');\n\t\t}\n\n\t\tdocument.title = _title = title;\n\n\t\t// TODO: In v3 the `_domId` should be created from a combination of the\n\t\t// `_title` slug and the IFID, if available, to avoid collisions between\n\t\t// stories whose titles generate identical slugs.\n\t\t_domId = Util.slugify(_title);\n\n\t\t// [v2] Protect the `_domId` against being an empty string.\n\t\t//\n\t\t// If `_domId` is empty, attempt a failover.\n\t\tif (_domId === '') {\n\t\t\t// If `_ifId` is not empty, then use it.\n\t\t\tif (_ifId !== '') {\n\t\t\t\t_domId = _ifId;\n\t\t\t}\n\n\t\t\t// Elsewise generate a string from the `_title`'s code points (in hexadecimal).\n\t\t\telse {\n\t\t\t\tfor (let i = 0, len = _title.length; i < len; ++i) {\n\t\t\t\t\tconst { char, start, end } = Util.charAndPosAt(_title, i);\n\t\t\t\t\t_domId += char.codePointAt(0).toString(16);\n\t\t\t\t\ti += end - start;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction storyTitle() {\n\t\treturn _title;\n\t}\n\n\tfunction storyDomId() {\n\t\treturn _domId;\n\t}\n\n\tfunction storyIfId() {\n\t\treturn _ifId;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPassage Functions.\n\t*******************************************************************************************************************/\n\tfunction passagesAdd(passage) {\n\t\tif (!(passage instanceof Passage)) {\n\t\t\tthrow new TypeError('Story.add passage parameter must be an instance of Passage');\n\t\t}\n\n\t\tconst title = passage.title;\n\n\t\tif (!_passages.hasOwnProperty(title)) {\n\t\t\t_passages[title] = passage;\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tfunction passagesHas(title) {\n\t\tlet type = typeof title;\n\n\t\tswitch (type) {\n\t\t// Valid types.\n\t\tcase 'number':\n\t\tcase 'string':\n\t\t\treturn _passages.hasOwnProperty(String(title));\n\n\t\t// Invalid types.  We do the extra processing just to make a nicer error.\n\t\tcase 'undefined':\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\ttype = title === null ? 'null' : 'an object';\n\t\t\tbreak;\n\n\t\tdefault: // 'bigint', 'boolean', 'function', 'symbol'\n\t\t\ttype = `a ${type}`;\n\t\t\tbreak;\n\t\t}\n\n\t\tthrow new TypeError(`Story.has title parameter cannot be ${type}`);\n\t}\n\n\tfunction passagesGet(title) {\n\t\tlet type = typeof title;\n\n\t\tswitch (type) {\n\t\t// Valid types.\n\t\tcase 'number':\n\t\tcase 'string':\n\t\t/* eslint-disable indent */\n\t\t\t{\n\t\t\t\tconst id = String(title);\n\t\t\t\treturn _passages.hasOwnProperty(id) ? _passages[id] : new Passage(id || '(unknown)');\n\t\t\t}\n\t\t/* eslint-enable indent */\n\n\t\t// Invalid types.  We do the extra processing just to make a nicer error.\n\t\tcase 'undefined':\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\ttype = title === null ? 'null' : 'an object';\n\t\t\tbreak;\n\n\t\tdefault: // 'bigint', 'boolean', 'function', 'symbol'\n\t\t\ttype = `a ${type}`;\n\t\t\tbreak;\n\t\t}\n\n\t\tthrow new TypeError(`Story.get title parameter cannot be ${type}`);\n\t}\n\n\tfunction passagesGetAllRegular() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Object.assign({}, _passages));\n\t}\n\n\tfunction passagesGetAllScript() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_scripts));\n\t}\n\n\tfunction passagesGetAllStylesheet() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_styles));\n\t}\n\n\tfunction passagesGetAllWidget() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_widgets));\n\t}\n\n\tfunction passagesLookup(key, value  /* legacy */, sortKey = 'title'/* /legacy */) {\n\t\tconst results = [];\n\n\t\tObject.keys(_passages).forEach(name => {\n\t\t\tconst passage = _passages[name];\n\n\t\t\t// Objects (sans `null`).\n\t\t\tif (typeof passage[key] === 'object' && passage[key] !== null) {\n\t\t\t\t// The only object type currently supported is `Array`, since the\n\t\t\t\t// non-method `Passage` object properties currently yield only either\n\t\t\t\t// primitives or arrays.\n\t\t\t\tif (passage[key] instanceof Array && passage[key].some(m => Util.sameValueZero(m, value))) {\n\t\t\t\t\tresults.push(passage);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// All other types (incl. `null`).\n\t\t\telse if (Util.sameValueZero(passage[key], value)) {\n\t\t\t\tresults.push(passage);\n\t\t\t}\n\t\t});\n\n\t\t// For v3.\n\t\t// /* eslint-disable no-nested-ternary */\n\t\t// // QUESTION: Do we really need to sort the list?\n\t\t// results.sort((a, b) => a.title === b.title ? 0 : a.title < b.title ? -1 : +1);\n\t\t// /* eslint-enable no-nested-ternary */\n\n\t\t/* legacy */\n\t\t/* eslint-disable eqeqeq, no-nested-ternary, max-len */\n\t\tresults.sort((a, b) => a[sortKey] == b[sortKey] ? 0 : a[sortKey] < b[sortKey] ? -1 : +1); // lazy equality for null\n\t\t/* eslint-enable eqeqeq, no-nested-ternary, max-len */\n\t\t/* /legacy */\n\n\t\treturn results;\n\t}\n\n\tfunction passagesLookupWith(predicate /* legacy */, sortKey = 'title'/* /legacy */) {\n\t\tif (typeof predicate !== 'function') {\n\t\t\tthrow new TypeError('Story.lookupWith predicate parameter must be a function');\n\t\t}\n\n\t\tconst results = [];\n\n\t\tObject.keys(_passages).forEach(name => {\n\t\t\tconst passage = _passages[name];\n\n\t\t\tif (predicate(passage)) {\n\t\t\t\tresults.push(passage);\n\t\t\t}\n\t\t});\n\n\t\t// For v3.\n\t\t// /* eslint-disable no-nested-ternary */\n\t\t// // QUESTION: Do we really need to sort the list?\n\t\t// results.sort((a, b) => a.title === b.title ? 0 : a.title < b.title ? -1 : +1);\n\t\t// /* eslint-enable no-nested-ternary */\n\n\t\t/* legacy */\n\t\t/* eslint-disable eqeqeq, no-nested-ternary, max-len */\n\t\tresults.sort((a, b) => a[sortKey] == b[sortKey] ? 0 : a[sortKey] < b[sortKey] ? -1 : +1); // lazy equality for null\n\t\t/* eslint-enable eqeqeq, no-nested-ternary, max-len */\n\t\t/* /legacy */\n\n\t\treturn results;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Story Functions.\n\t\tload  : { value : storyLoad },\n\t\tinit  : { value : storyInit },\n\t\ttitle : { get : storyTitle },\n\t\tdomId : { get : storyDomId },\n\t\tifId  : { get : storyIfId },\n\n\t\t// Passage Functions.\n\t\tadd              : { value : passagesAdd },\n\t\thas              : { value : passagesHas },\n\t\tget              : { value : passagesGet },\n\t\tgetAllRegular    : { value : passagesGetAllRegular },\n\t\tgetAllScript     : { value : passagesGetAllScript },\n\t\tgetAllStylesheet : { value : passagesGetAllStylesheet },\n\t\tgetAllWidget     : { value : passagesGetAllWidget },\n\t\tlookup           : { value : passagesLookup },\n\t\tlookupWith       : { value : passagesLookupWith }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tui.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Dialog, Engine, Has, L10n, Save, Setting, State, Story, Util, Wikifier, Config, errorPrologRegExp,\n\t       settings\n*/\n\nvar UI = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUI Functions, Core.\n\t*******************************************************************************************************************/\n\tfunction uiAssembleLinkList(passage, listEl) {\n\t\tlet list = listEl;\n\n\t\t// Cache the values of `Config.debug` and `Config.cleanupWikifierOutput`,\n\t\t// then disable them during this method's run.\n\t\tconst debugState = Config.debug;\n\t\tconst cleanState = Config.cleanupWikifierOutput;\n\t\tConfig.debug = false;\n\t\tConfig.cleanupWikifierOutput = false;\n\n\t\ttry {\n\t\t\tif (list == null) { // lazy equality for null\n\t\t\t\tlist = document.createElement('ul');\n\t\t\t}\n\n\t\t\t// Wikify the content of the given source passage into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, Story.get(passage).processText().trim());\n\n\t\t\t// Gather the text of any error elements within the fragment…\n\t\t\tconst errors = [...frag.querySelectorAll('.error')]\n\t\t\t\t.map(errEl => errEl.textContent.replace(errorPrologRegExp, ''));\n\n\t\t\t// …and throw an exception, if there were any errors.\n\t\t\tif (errors.length > 0) {\n\t\t\t\tthrow new Error(errors.join('; '));\n\t\t\t}\n\n\t\t\twhile (frag.hasChildNodes()) {\n\t\t\t\tconst node = frag.firstChild;\n\n\t\t\t\t// Create list items for <a>-element nodes.\n\t\t\t\tif (node.nodeType === Node.ELEMENT_NODE && node.nodeName.toUpperCase() === 'A') {\n\t\t\t\t\tconst li = document.createElement('li');\n\t\t\t\t\tlist.appendChild(li);\n\t\t\t\t\tli.appendChild(node);\n\t\t\t\t}\n\n\t\t\t\t// Discard non-<a>-element nodes.\n\t\t\t\telse {\n\t\t\t\t\tfrag.removeChild(node);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\t// Restore the `Config` settings to their original values.\n\t\t\tConfig.cleanupWikifierOutput = cleanState;\n\t\t\tConfig.debug = debugState;\n\t\t}\n\n\t\treturn list;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUI Functions, Built-ins.\n\t*******************************************************************************************************************/\n\tfunction uiOpenAlert(message, /* options, closeFn */ ...args) {\n\t\tjQuery(Dialog.setup('Alert', 'alert'))\n\t\t\t.append(\n\t\t\t\t  `<p>${message}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"alert-ok\" class=\"ui-close\">${L10n.get(['alertOk', 'ok'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t);\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenJumpto(/* options, closeFn */ ...args) {\n\t\tuiBuildJumpto();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenRestart(/* options, closeFn */ ...args) {\n\t\tuiBuildRestart();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenSaves(/* options, closeFn */ ...args) {\n\t\tuiBuildSaves();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenSettings(/* options, closeFn */ ...args) {\n\t\tuiBuildSettings();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenShare(/* options, closeFn */ ...args) {\n\t\tuiBuildShare();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiBuildAutoload() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildAutoload()]'); }\n\n\t\tjQuery(Dialog.setup(L10n.get('autoloadTitle'), 'autoload'))\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  `<p>${L10n.get('autoloadPrompt')}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"autoload-ok\" class=\"ui-close\">${L10n.get(['autoloadOk', 'ok'])}</button></li>`\n\t\t\t\t+ `<li><button id=\"autoload-cancel\" class=\"ui-close\">${L10n.get(['autoloadCancel', 'cancel'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t);\n\n\t\t// Add an additional delegated click handler for the `.ui-close` elements to handle autoloading.\n\t\tjQuery(document).one('click.autoload', '.ui-close', ev => {\n\t\t\tconst isAutoloadOk = ev.target.id === 'autoload-ok';\n\t\t\tjQuery(document).one(':dialogclosed', () => {\n\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\tif (!isAutoloadOk || !Save.autosave.load()) {\n\t\t\t\t\tEngine.play(Config.passages.start);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildJumpto() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildJumpto()]'); }\n\n\t\tconst list = document.createElement('ul');\n\n\t\tjQuery(Dialog.setup(L10n.get('jumptoTitle'), 'jumpto list'))\n\t\t\t.append(list);\n\n\t\tconst expired = State.expired.length;\n\n\t\tfor (let i = State.size - 1; i >= 0; --i) {\n\t\t\tif (i === State.activeIndex) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst passage = Story.get(State.history[i].title);\n\n\t\t\tif (passage && passage.tags.includes('bookmark')) {\n\t\t\t\tjQuery(document.createElement('li'))\n\t\t\t\t\t.append(\n\t\t\t\t\t\tjQuery(document.createElement('a'))\n\t\t\t\t\t\t\t.ariaClick({ one : true }, (function (idx) {\n\t\t\t\t\t\t\t\treturn () => jQuery(document).one(':dialogclosed', () => Engine.goTo(idx));\n\t\t\t\t\t\t\t})(i))\n\t\t\t\t\t\t\t.addClass('ui-close')\n\t\t\t\t\t\t\t.text(`${L10n.get('jumptoTurn')} ${expired + i + 1}: ${passage.description()}`)\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo(list);\n\t\t\t}\n\t\t}\n\n\t\tif (!list.hasChildNodes()) {\n\t\t\tjQuery(list).append(`<li><a><em>${L10n.get('jumptoUnavailable')}</em></a></li>`);\n\t\t}\n\t}\n\n\tfunction uiBuildRestart() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildRestart()]'); }\n\n\t\tjQuery(Dialog.setup(L10n.get('restartTitle'), 'restart'))\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  `<p>${L10n.get('restartPrompt')}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"restart-ok\">${L10n.get(['restartOk', 'ok'])}</button></li>`\n\t\t\t\t+ `<li><button id=\"restart-cancel\" class=\"ui-close\">${L10n.get(['restartCancel', 'cancel'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t)\n\t\t\t.find('#restart-ok')\n\t\t\t/*\n\t\t\t\tInstead of adding '.ui-close' to '#restart-ok' (to receive the use of the default\n\t\t\t\tdelegated dialog close handler), we set up a special case close handler here.  We\n\t\t\t\tdo this to ensure that the invocation of `Engine.restart()` happens after the dialog\n\t\t\t\thas fully closed.  If we did not, then a race condition could occur, causing display\n\t\t\t\tshenanigans.\n\t\t\t*/\n\t\t\t.ariaClick({ one : true }, () => {\n\t\t\t\tjQuery(document).one(':dialogclosed', () => Engine.restart());\n\t\t\t\tDialog.close();\n\t\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildSaves() {\n\t\tfunction createActionItem(bId, bClass, bText, bAction) {\n\t\t\tconst $btn = jQuery(document.createElement('button'))\n\t\t\t\t.attr('id', `saves-${bId}`)\n\t\t\t\t.html(bText);\n\n\t\t\tif (bClass) {\n\t\t\t\t$btn.addClass(bClass);\n\t\t\t}\n\n\t\t\tif (bAction) {\n\t\t\t\t$btn.ariaClick(bAction);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$btn.ariaDisabled(true);\n\t\t\t}\n\n\t\t\treturn jQuery(document.createElement('li'))\n\t\t\t\t.append($btn);\n\t\t}\n\n\t\tfunction createSaveList() {\n\t\t\tfunction createButton(bId, bClass, bText, bSlot, bAction) {\n\t\t\t\tconst $btn = jQuery(document.createElement('button'))\n\t\t\t\t\t.attr('id', `saves-${bId}-${bSlot}`)\n\t\t\t\t\t.addClass(bId)\n\t\t\t\t\t.html(bText);\n\n\t\t\t\tif (bClass) {\n\t\t\t\t\t$btn.addClass(bClass);\n\t\t\t\t}\n\n\t\t\t\tif (bAction) {\n\t\t\t\t\tif (bSlot === 'auto') {\n\t\t\t\t\t\t$btn.ariaClick({\n\t\t\t\t\t\t\tlabel : `${bText} ${L10n.get('savesLabelAuto')}`\n\t\t\t\t\t\t}, () => bAction());\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t$btn.ariaClick({\n\t\t\t\t\t\t\tlabel : `${bText} ${L10n.get('savesLabelSlot')} ${bSlot + 1}`\n\t\t\t\t\t\t}, () => bAction(bSlot));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$btn.ariaDisabled(true);\n\t\t\t\t}\n\n\t\t\t\treturn $btn;\n\t\t\t}\n\n\t\t\tconst saves  = Save.get();\n\t\t\tconst $tbody = jQuery(document.createElement('tbody'));\n\n\t\t\tif (Save.autosave.ok()) {\n\t\t\t\tconst $tdSlot = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdLoad = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDesc = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDele = jQuery(document.createElement('td'));\n\n\t\t\t\t// Add the slot ID.\n\t\t\t\tjQuery(document.createElement('b'))\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttitle        : L10n.get('savesLabelAuto'),\n\t\t\t\t\t\t'aria-label' : L10n.get('savesLabelAuto')\n\t\t\t\t\t})\n\t\t\t\t\t.text('A') // '\\u25C6' Black Diamond\n\t\t\t\t\t.appendTo($tdSlot);\n\n\t\t\t\tif (saves.autosave) {\n\t\t\t\t\t// Add the load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('load', 'ui-close', L10n.get('savesLabelLoad'), 'auto', () => {\n\t\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.autosave.load());\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description (title and datestamp).\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.text(saves.autosave.title)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.addClass('datestamp')\n\t\t\t\t\t\t.html(\n\t\t\t\t\t\t\tsaves.autosave.date\n\t\t\t\t\t\t\t\t? `${new Date(saves.autosave.date).toLocaleString()}`\n\t\t\t\t\t\t\t\t: `<em>${L10n.get('savesUnknownDate')}</em>`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\n\t\t\t\t\t// Add the delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), 'auto', () => {\n\t\t\t\t\t\t\tSave.autosave.delete();\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Add the disabled load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('load', null, L10n.get('savesLabelLoad'), 'auto')\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description.\n\t\t\t\t\t$tdDesc.addClass('empty').text('\\u2022\\u00a0\\u00a0\\u2022\\u00a0\\u00a0\\u2022');\n\n\t\t\t\t\t// Add the disabled delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), 'auto')\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t.append($tdSlot)\n\t\t\t\t\t.append($tdLoad)\n\t\t\t\t\t.append($tdDesc)\n\t\t\t\t\t.append($tdDele)\n\t\t\t\t\t.appendTo($tbody);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = saves.slots.length; i < iend; ++i) {\n\t\t\t\tconst $tdSlot = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdLoad = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDesc = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDele = jQuery(document.createElement('td'));\n\n\t\t\t\t// Add the slot ID.\n\t\t\t\t$tdSlot.append(document.createTextNode(i + 1));\n\n\t\t\t\tif (saves.slots[i]) {\n\t\t\t\t\t// Add the load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('save', 'ui-close', L10n.get('savesLabelSave'), i, Save.slots.save),\n\t\t\t\t\t\tcreateButton('load', 'ui-close', L10n.get('savesLabelLoad'), i, slot => {\n\t\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.slots.load(slot));\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description (title and datestamp).\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.text(saves.slots[i].title)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.addClass('datestamp')\n\t\t\t\t\t\t.html(\n\t\t\t\t\t\t\tsaves.slots[i].date\n\t\t\t\t\t\t\t\t? `${new Date(saves.slots[i].date).toLocaleString()}`\n\t\t\t\t\t\t\t\t: `<em>${L10n.get('savesUnknownDate')}</em>`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\n\t\t\t\t\t// Add the delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), i, slot => {\n\t\t\t\t\t\t\tSave.slots.delete(slot);\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Add the save button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('save', 'ui-close', L10n.get('savesLabelSave'), i, Save.slots.save)\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description.\n\t\t\t\t\t$tdDesc.addClass('empty').text('\\u2022\\u00a0\\u00a0\\u2022\\u00a0\\u00a0\\u2022');\n\n\t\t\t\t\t// Add the disabled delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), i)\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t.append($tdSlot)\n\t\t\t\t\t.append($tdLoad)\n\t\t\t\t\t.append($tdDesc)\n\t\t\t\t\t.append($tdDele)\n\t\t\t\t\t.appendTo($tbody);\n\t\t\t}\n\n\t\t\treturn jQuery(document.createElement('table'))\n\t\t\t\t.attr('id', 'saves-list')\n\t\t\t\t.append($tbody);\n\t\t}\n\n\t\tif (DEBUG) { console.log('[UI/uiBuildSaves()]'); }\n\n\t\tconst $dialogBody = jQuery(Dialog.setup(L10n.get('savesTitle'), 'saves'));\n\t\tconst savesOk     = Save.ok();\n\n\t\t// Add saves list.\n\t\tif (savesOk) {\n\t\t\t$dialogBody.append(createSaveList());\n\t\t}\n\n\t\t// Add button bar items (export, import, and clear).\n\t\tif (savesOk || Has.fileAPI) {\n\t\t\tconst $btnBar = jQuery(document.createElement('ul'))\n\t\t\t\t.addClass('buttons')\n\t\t\t\t.appendTo($dialogBody);\n\n\t\t\tif (Has.fileAPI) {\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'export',\n\t\t\t\t\t'ui-close',\n\t\t\t\t\tL10n.get('savesLabelExport'),\n\t\t\t\t\t() => Save.export()\n\t\t\t\t));\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'import',\n\t\t\t\t\tnull,\n\t\t\t\t\tL10n.get('savesLabelImport'),\n\t\t\t\t\t() => $dialogBody.find('#saves-import-file').trigger('click')\n\t\t\t\t));\n\n\t\t\t\t// Add the hidden `input[type=file]` element which will be triggered by the `#saves-import` button.\n\t\t\t\tjQuery(document.createElement('input'))\n\t\t\t\t\t.css({\n\t\t\t\t\t\tdisplay    : 'block',\n\t\t\t\t\t\tvisibility : 'hidden',\n\t\t\t\t\t\tposition   : 'fixed',\n\t\t\t\t\t\tleft       : '-9999px',\n\t\t\t\t\t\ttop        : '-9999px',\n\t\t\t\t\t\twidth      : '1px',\n\t\t\t\t\t\theight     : '1px'\n\t\t\t\t\t})\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttype          : 'file',\n\t\t\t\t\t\tid            : 'saves-import-file',\n\t\t\t\t\t\ttabindex      : -1,\n\t\t\t\t\t\t'aria-hidden' : true\n\t\t\t\t\t})\n\t\t\t\t\t.on('change', ev => {\n\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.import(ev));\n\t\t\t\t\t\tDialog.close();\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo($dialogBody);\n\t\t\t}\n\n\t\t\tif (savesOk) {\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'clear',\n\t\t\t\t\tnull,\n\t\t\t\t\tL10n.get('savesLabelClear'),\n\t\t\t\t\tSave.autosave.has() || !Save.slots.isEmpty()\n\t\t\t\t\t\t? () => {\n\t\t\t\t\t\t\tSave.clear();\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t: null\n\t\t\t\t));\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tuiOpenAlert(L10n.get('savesIncapable'));\n\t\treturn false;\n\t}\n\n\tfunction uiBuildSettings() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildSettings()]'); }\n\n\t\tconst $dialogBody = jQuery(Dialog.setup(L10n.get('settingsTitle'), 'settings'));\n\n\t\tSetting.forEach(control => {\n\t\t\tif (control.type === Setting.Types.Header) {\n\t\t\t\tconst name     = control.name;\n\t\t\t\tconst id       = Util.slugify(name);\n\t\t\t\tconst $header  = jQuery(document.createElement('div'));\n\t\t\t\tconst $heading = jQuery(document.createElement('h2'));\n\n\t\t\t\t$header\n\t\t\t\t\t.attr('id', `header-body-${id}`)\n\t\t\t\t\t.append($heading)\n\t\t\t\t\t.appendTo($dialogBody);\n\t\t\t\t$heading\n\t\t\t\t\t.attr('id', `header-heading-${id}`)\n\t\t\t\t\t.wiki(name);\n\n\t\t\t\t// Set up the description, if any.\n\t\t\t\tif (control.desc) {\n\t\t\t\t\tjQuery(document.createElement('p'))\n\t\t\t\t\t\t.attr('id', `header-desc-${id}`)\n\t\t\t\t\t\t.wiki(control.desc)\n\t\t\t\t\t\t.appendTo($header);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst name        = control.name;\n\t\t\tconst id          = Util.slugify(name);\n\t\t\tconst $setting    = jQuery(document.createElement('div'));\n\t\t\tconst $label      = jQuery(document.createElement('label'));\n\t\t\tconst $controlBox = jQuery(document.createElement('div'));\n\t\t\tlet $control;\n\n\t\t\t// Set up the label+control wrapper.\n\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t.append($label)\n\t\t\t\t.append($controlBox)\n\t\t\t\t.appendTo($setting);\n\n\t\t\t// Set up the description, if any.\n\t\t\tif (control.desc) {\n\t\t\t\tjQuery(document.createElement('p'))\n\t\t\t\t\t.attr('id', `setting-desc-${id}`)\n\t\t\t\t\t.wiki(control.desc)\n\t\t\t\t\t.appendTo($setting);\n\t\t\t}\n\n\t\t\t// Set up the label.\n\t\t\t$label\n\t\t\t\t.attr({\n\t\t\t\t\tid  : `setting-label-${id}`,\n\t\t\t\t\tfor : `setting-control-${id}` // must be in sync with $control's ID (see below)\n\t\t\t\t})\n\t\t\t\t.wiki(control.label);\n\n\t\t\t// Set up the control.\n\t\t\tif (settings[name] == null) { // lazy equality for null\n\t\t\t\tsettings[name] = control.default;\n\t\t\t}\n\n\t\t\tswitch (control.type) {\n\t\t\tcase Setting.Types.Toggle:\n\t\t\t\t$control = jQuery(document.createElement('button'));\n\n\t\t\t\tif (settings[name]) {\n\t\t\t\t\t$control\n\t\t\t\t\t\t.addClass('enabled')\n\t\t\t\t\t\t.text(L10n.get('settingsOn'));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$control\n\t\t\t\t\t\t.text(L10n.get('settingsOff'));\n\t\t\t\t}\n\n\t\t\t\t$control.ariaClick(function () {\n\t\t\t\t\tif (settings[name]) {\n\t\t\t\t\t\tjQuery(this)\n\t\t\t\t\t\t\t.removeClass('enabled')\n\t\t\t\t\t\t\t.text(L10n.get('settingsOff'));\n\t\t\t\t\t\tsettings[name] = false;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tjQuery(this)\n\t\t\t\t\t\t\t.addClass('enabled')\n\t\t\t\t\t\t\t.text(L10n.get('settingsOn'));\n\t\t\t\t\t\tsettings[name] = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tSetting.save();\n\n\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\tdefault : control.default\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase Setting.Types.List:\n\t\t\t\t$control = jQuery(document.createElement('select'));\n\n\t\t\t\tfor (let i = 0, iend = control.list.length; i < iend; ++i) {\n\t\t\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t\t\t.val(i)\n\t\t\t\t\t\t.text(control.list[i])\n\t\t\t\t\t\t.appendTo($control);\n\t\t\t\t}\n\n\t\t\t\t$control\n\t\t\t\t\t.val(control.list.indexOf(settings[name]))\n\t\t\t\t\t.attr('tabindex', 0)\n\t\t\t\t\t.on('change', function () {\n\t\t\t\t\t\tsettings[name] = control.list[Number(this.value)];\n\t\t\t\t\t\tSetting.save();\n\n\t\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\t\tdefault : control.default,\n\t\t\t\t\t\t\t\tlist    : control.list\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase Setting.Types.Range:\n\t\t\t\t$control = jQuery(document.createElement('input'));\n\n\t\t\t\t// NOTE: Setting the value with `<jQuery>.val()` can cause odd behavior\n\t\t\t\t// in Edge if it's called before the type is set, so we use the `value`\n\t\t\t\t// content attribute here to dodge the entire issue.\n\t\t\t\t$control\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttype     : 'range',\n\t\t\t\t\t\tmin      : control.min,\n\t\t\t\t\t\tmax      : control.max,\n\t\t\t\t\t\tstep     : control.step,\n\t\t\t\t\t\tvalue    : settings[name],\n\t\t\t\t\t\ttabindex : 0\n\t\t\t\t\t})\n\t\t\t\t\t.on('change input', function () {\n\t\t\t\t\t\tsettings[name] = Number(this.value);\n\t\t\t\t\t\tSetting.save();\n\n\t\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\t\tdefault : control.default,\n\t\t\t\t\t\t\t\tmin     : control.min,\n\t\t\t\t\t\t\t\tmax     : control.max,\n\t\t\t\t\t\t\t\tstep    : control.step\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.on('keypress', ev => {\n\t\t\t\t\t\tif (ev.which === 13) {\n\t\t\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t\t\t$control.trigger('change');\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$control\n\t\t\t\t.attr('id', `setting-control-${id}`)\n\t\t\t\t.appendTo($controlBox);\n\n\t\t\t$setting\n\t\t\t\t.attr('id', `setting-body-${id}`)\n\t\t\t\t.appendTo($dialogBody);\n\t\t});\n\n\t\t// Add the button bar.\n\t\t$dialogBody\n\t\t\t.append(\n\t\t\t\t  '<ul class=\"buttons\">'\n\t\t\t\t+     `<li><button id=\"settings-ok\" class=\"ui-close\">${L10n.get(['settingsOk', 'ok'])}</button></li>`\n\t\t\t\t+     `<li><button id=\"settings-reset\">${L10n.get('settingsReset')}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t)\n\t\t\t.find('#settings-reset')\n\t\t\t/*\n\t\t\t\tInstead of adding '.ui-close' to '#settings-reset' (to receive the use of the default\n\t\t\t\tdelegated dialog close handler), we set up a special case close handler here.  We\n\t\t\t\tdo this to ensure that the invocation of `window.location.reload()` happens after the\n\t\t\t\tdialog has fully closed.  If we did not, then a race condition could occur, causing\n\t\t\t\tdisplay shenanigans.\n\t\t\t*/\n\t\t\t.ariaClick({ one : true }, () => {\n\t\t\t\tjQuery(document).one(':dialogclosed', () => {\n\t\t\t\t\tSetting.reset();\n\t\t\t\t\twindow.location.reload();\n\t\t\t\t});\n\t\t\t\tDialog.close();\n\t\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildShare() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildShare()]'); }\n\n\t\ttry {\n\t\t\tjQuery(Dialog.setup(L10n.get('shareTitle'), 'share list'))\n\t\t\t\t.append(uiAssembleLinkList('StoryShare'));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tconsole.error(ex);\n\t\t\tAlert.error('StoryShare', ex.message);\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tUI Functions, Core.\n\t\t*/\n\t\tassembleLinkList : { value : uiAssembleLinkList },\n\n\t\t/*\n\t\t\tUI Functions, Built-ins.\n\t\t*/\n\t\talert         : { value : uiOpenAlert },\n\t\tjumpto        : { value : uiOpenJumpto },\n\t\trestart       : { value : uiOpenRestart },\n\t\tsaves         : { value : uiOpenSaves },\n\t\tsettings      : { value : uiOpenSettings },\n\t\tshare         : { value : uiOpenShare },\n\t\tbuildAutoload : { value : uiBuildAutoload },\n\t\tbuildJumpto   : { value : uiBuildJumpto },\n\t\tbuildRestart  : { value : uiBuildRestart },\n\t\tbuildSaves    : { value : uiBuildSaves },\n\t\tbuildSettings : { value : uiBuildSettings },\n\t\tbuildShare    : { value : uiBuildShare },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\t// `UIBar` methods.\n\t\t/* global UIBar */\n\t\tstow                     : { value : () => UIBar.stow() },\n\t\tunstow                   : { value : () => UIBar.unstow() },\n\t\tsetStoryElements         : { value : () => UIBar.update() },\n\t\t// `Dialog` methods.\n\t\tisOpen                   : { value : (...args) => Dialog.isOpen(...args) },\n\t\tbody                     : { value : () => Dialog.body() },\n\t\tsetup                    : { value : (...args) => Dialog.setup(...args) },\n\t\taddClickHandler          : { value : (...args) => Dialog.addClickHandler(...args) },\n\t\topen                     : { value : (...args) => Dialog.open(...args) },\n\t\tclose                    : { value : (...args) => Dialog.close(...args) },\n\t\tresize                   : { value : () => Dialog.resize() },\n\t\t// Deprecated method names.\n\t\tbuildDialogAutoload      : { value : uiBuildAutoload },\n\t\tbuildDialogJumpto        : { value : uiBuildJumpto },\n\t\tbuildDialogRestart       : { value : uiBuildRestart },\n\t\tbuildDialogSaves         : { value : uiBuildSaves },\n\t\tbuildDialogSettings      : { value : uiBuildSettings },\n\t\tbuildDialogShare         : { value : uiBuildShare },\n\t\tbuildLinkListFromPassage : { value : uiAssembleLinkList }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tuibar.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Dialog, Engine, L10n, Setting, State, Story, UI, Config, setDisplayTitle, setPageElement\n*/\n\nvar UIBar = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// UI bar element cache.\n\tlet _$uiBar = null;\n\n\n\t/*******************************************************************************\n\t\tUI Bar Functions.\n\t*******************************************************************************/\n\n\tfunction uiBarDestroy() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarDestroy()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Hide the UI bar.\n\t\t_$uiBar.hide();\n\n\t\t// Remove its namespaced events.\n\t\tjQuery(document).off('.ui-bar');\n\n\t\t// Remove its styles.\n\t\tjQuery(document.head).find('#style-ui-bar').remove();\n\n\t\t// Remove it from the DOM.\n\t\t_$uiBar.remove();\n\n\t\t// Drop the reference to the element.\n\t\t_$uiBar = null;\n\t}\n\n\tfunction uiBarHide() {\n\t\tif (_$uiBar) {\n\t\t\t_$uiBar.hide();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarInit() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarInit()]'); }\n\n\t\tif (document.getElementById('ui-bar')) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Generate the UI bar elements.\n\t\tconst $elems = (() => {\n\t\t\tconst toggleLabel   = L10n.get('uiBarToggle');\n\t\t\tconst backwardLabel = L10n.get('uiBarBackward');\n\t\t\tconst jumptoLabel   = L10n.get('uiBarJumpto');\n\t\t\tconst forwardLabel  = L10n.get('uiBarForward');\n\n\t\t\treturn jQuery(document.createDocumentFragment())\n\t\t\t\t.append(\n\t\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t\t  '<div id=\"ui-bar\">'\n\t\t\t\t\t+     '<div id=\"ui-bar-tray\">'\n\t\t\t\t\t+         `<button id=\"ui-bar-toggle\" tabindex=\"0\" title=\"${toggleLabel}\" aria-label=\"${toggleLabel}\"></button>`\n\t\t\t\t\t+         '<div id=\"ui-bar-history\">'\n\t\t\t\t\t+             `<button id=\"history-backward\" tabindex=\"0\" title=\"${backwardLabel}\" aria-label=\"${backwardLabel}\">\\uE821</button>`\n\t\t\t\t\t+             `<button id=\"history-jumpto\" tabindex=\"0\" title=\"${jumptoLabel}\" aria-label=\"${jumptoLabel}\">\\uE839</button>`\n\t\t\t\t\t+             `<button id=\"history-forward\" tabindex=\"0\" title=\"${forwardLabel}\" aria-label=\"${forwardLabel}\">\\uE822</button>`\n\t\t\t\t\t+         '</div>'\n\t\t\t\t\t+     '</div>'\n\t\t\t\t\t+     '<div id=\"ui-bar-body\">'\n\t\t\t\t\t+         '<header id=\"title\" role=\"banner\">'\n\t\t\t\t\t+             '<div id=\"story-banner\"></div>'\n\t\t\t\t\t+             '<h1 id=\"story-title\"></h1>'\n\t\t\t\t\t+             '<div id=\"story-subtitle\"></div>'\n\t\t\t\t\t+             '<div id=\"story-title-separator\"></div>'\n\t\t\t\t\t+             '<p id=\"story-author\"></p>'\n\t\t\t\t\t+         '</header>'\n\t\t\t\t\t+         '<div id=\"story-caption\"></div>'\n\t\t\t\t\t+         '<nav id=\"menu\" role=\"navigation\">'\n\t\t\t\t\t+             '<ul id=\"menu-story\"></ul>'\n\t\t\t\t\t+             '<ul id=\"menu-core\">'\n\t\t\t\t\t+                 `<li id=\"menu-item-saves\"><a tabindex=\"0\">${L10n.get('savesTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-settings\"><a tabindex=\"0\">${L10n.get('settingsTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-restart\"><a tabindex=\"0\">${L10n.get('restartTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-share\"><a tabindex=\"0\">${L10n.get('shareTitle')}</a></li>`\n\t\t\t\t\t+             '</ul>'\n\t\t\t\t\t+         '</nav>'\n\t\t\t\t\t+     '</div>'\n\t\t\t\t\t+ '</div>'\n\t\t\t\t\t/* eslint-enable max-len */\n\t\t\t\t);\n\t\t})();\n\n\t\t/*\n\t\t\tCache the UI bar element, since its going to be used often.\n\n\t\t\tNOTE: We rewrap the element itself, rather than simply using the result\n\t\t\tof `find()`, so that we cache an uncluttered jQuery-wrapper (i.e. `context`\n\t\t\trefers to the element and there is no `prevObject`).\n\t\t*/\n\t\t_$uiBar = jQuery($elems.find('#ui-bar').get(0));\n\n\t\t// Insert the UI bar elements into the page before the main script.\n\t\t$elems.insertBefore('body>script#script-sugarcube');\n\n\t\t// Set up the UI bar's global event handlers.\n\t\tjQuery(document)\n\t\t\t// Set up a handler for the history-backward/-forward buttons.\n\t\t\t.on(':historyupdate.ui-bar', (($backward, $forward) => () => {\n\t\t\t\t$backward.ariaDisabled(State.length < 2);\n\t\t\t\t$forward.ariaDisabled(State.length === State.size);\n\t\t\t})(jQuery('#history-backward'), jQuery('#history-forward')));\n\t}\n\n\tfunction uiBarIsHidden() {\n\t\treturn _$uiBar && _$uiBar.css('display') === 'none';\n\t}\n\n\tfunction uiBarIsStowed() {\n\t\treturn _$uiBar && _$uiBar.hasClass('stowed');\n\t}\n\n\tfunction uiBarShow() {\n\t\tif (_$uiBar) {\n\t\t\t_$uiBar.show();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarStart() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarStart()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Set up the #ui-bar's initial state.\n\t\tif (\n\t\t\ttypeof Config.ui.stowBarInitially === 'boolean'\n\t\t\t\t? Config.ui.stowBarInitially\n\t\t\t\t: jQuery(window).width() <= Config.ui.stowBarInitially\n\t\t) {\n\t\t\tuiBarStow(true);\n\t\t}\n\n\t\t// Set up the #ui-bar-toggle and #ui-bar-history widgets.\n\t\tjQuery('#ui-bar-toggle')\n\t\t\t.ariaClick({\n\t\t\t\tlabel : L10n.get('uiBarToggle')\n\t\t\t}, () => _$uiBar.toggleClass('stowed'));\n\n\t\tif (Config.history.controls) {\n\t\t\tjQuery('#history-backward')\n\t\t\t\t.ariaDisabled(State.length < 2)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tlabel : L10n.get('uiBarBackward')\n\t\t\t\t}, () => Engine.backward());\n\n\t\t\tif (Story.lookup('tags', 'bookmark').length > 0) {\n\t\t\t\tjQuery('#history-jumpto')\n\t\t\t\t\t.ariaClick({\n\t\t\t\t\t\tlabel : L10n.get('uiBarJumpto')\n\t\t\t\t\t}, () => UI.jumpto());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery('#history-jumpto').remove();\n\t\t\t}\n\n\t\t\tjQuery('#history-forward')\n\t\t\t\t.ariaDisabled(State.length === State.size)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tlabel : L10n.get('uiBarForward')\n\t\t\t\t}, () => Engine.forward());\n\t\t}\n\t\telse {\n\t\t\tjQuery('#ui-bar-history').remove();\n\t\t}\n\n\t\t// Set up the story display title.\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t}\n\t\telse {\n\t\t\tif (TWINE1) { // for Twine 1\n\t\t\t\tsetPageElement('story-title', 'StoryTitle', Story.title);\n\t\t\t}\n\t\t\telse { // for Twine 2\n\t\t\t\tjQuery('#story-title').text(Story.title);\n\t\t\t}\n\t\t}\n\n\t\t// Set up the dynamic page elements.\n\t\tif (!Story.has('StoryCaption')) {\n\t\t\tjQuery('#story-caption').remove();\n\t\t}\n\n\t\tif (!Story.has('StoryMenu')) {\n\t\t\tjQuery('#menu-story').remove();\n\t\t}\n\n\t\tif (!Config.ui.updateStoryElements) {\n\t\t\t// We only need to set the story elements here if `Config.ui.updateStoryElements`\n\t\t\t// is falsy, since otherwise they will be set by `Engine.play()`.\n\t\t\tuiBarUpdate();\n\t\t}\n\n\t\t// Set up the Saves menu item.\n\t\tjQuery('#menu-item-saves a')\n\t\t\t.ariaClick(ev => {\n\t\t\t\tev.preventDefault();\n\t\t\t\tUI.buildSaves();\n\t\t\t\tDialog.open();\n\t\t\t})\n\t\t\t.text(L10n.get('savesTitle'));\n\n\t\t// Set up the Settings menu item.\n\t\tif (!Setting.isEmpty()) {\n\t\t\tjQuery('#menu-item-settings a')\n\t\t\t\t.ariaClick(ev => {\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\tUI.buildSettings();\n\t\t\t\t\tDialog.open();\n\t\t\t\t})\n\t\t\t\t.text(L10n.get('settingsTitle'));\n\t\t}\n\t\telse {\n\t\t\tjQuery('#menu-item-settings').remove();\n\t\t}\n\n\t\t// Set up the Restart menu item.\n\t\tjQuery('#menu-item-restart a')\n\t\t\t.ariaClick(ev => {\n\t\t\t\tev.preventDefault();\n\t\t\t\tUI.buildRestart();\n\t\t\t\tDialog.open();\n\t\t\t})\n\t\t\t.text(L10n.get('restartTitle'));\n\n\t\t// Set up the Share menu item.\n\t\tif (Story.has('StoryShare')) {\n\t\t\tjQuery('#menu-item-share a')\n\t\t\t\t.ariaClick(ev => {\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\tUI.buildShare();\n\t\t\t\t\tDialog.open();\n\t\t\t\t})\n\t\t\t\t.text(L10n.get('shareTitle'));\n\t\t}\n\t\telse {\n\t\t\tjQuery('#menu-item-share').remove();\n\t\t}\n\t}\n\n\tfunction uiBarStow(noAnimation) {\n\t\tif (_$uiBar && !_$uiBar.hasClass('stowed')) {\n\t\t\tlet $story;\n\n\t\t\tif (noAnimation) {\n\t\t\t\t$story = jQuery('#story');\n\t\t\t\t$story.addClass('no-transition');\n\t\t\t\t_$uiBar.addClass('no-transition');\n\t\t\t}\n\n\t\t\t_$uiBar.addClass('stowed');\n\n\t\t\tif (noAnimation) {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t$story.removeClass('no-transition');\n\t\t\t\t\t_$uiBar.removeClass('no-transition');\n\t\t\t\t}, Engine.minDomActionDelay);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarUnstow(noAnimation) {\n\t\tif (_$uiBar && _$uiBar.hasClass('stowed')) {\n\t\t\tlet $story;\n\n\t\t\tif (noAnimation) {\n\t\t\t\t$story = jQuery('#story');\n\t\t\t\t$story.addClass('no-transition');\n\t\t\t\t_$uiBar.addClass('no-transition');\n\t\t\t}\n\n\t\t\t_$uiBar.removeClass('stowed');\n\n\t\t\tif (noAnimation) {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t$story.removeClass('no-transition');\n\t\t\t\t\t_$uiBar.removeClass('no-transition');\n\t\t\t\t}, Engine.minDomActionDelay);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarUpdate() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarUpdate()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Set up the (non-navigation) dynamic page elements.\n\t\tsetPageElement('story-banner', 'StoryBanner');\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t}\n\t\tsetPageElement('story-subtitle', 'StorySubtitle');\n\t\tsetPageElement('story-author', 'StoryAuthor');\n\t\tsetPageElement('story-caption', 'StoryCaption');\n\n\t\t// Set up the #menu-story items.\n\t\tconst menuStory = document.getElementById('menu-story');\n\n\t\tif (menuStory !== null) {\n\t\t\tjQuery(menuStory).empty();\n\n\t\t\tif (Story.has('StoryMenu')) {\n\t\t\t\ttry {\n\t\t\t\t\tUI.assembleLinkList('StoryMenu', menuStory);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\tconsole.error(ex);\n\t\t\t\t\tAlert.error('StoryMenu', ex.message);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tdestroy  : { value : uiBarDestroy },\n\t\thide     : { value : uiBarHide },\n\t\tinit     : { value : uiBarInit },\n\t\tisHidden : { value : uiBarIsHidden },\n\t\tisStowed : { value : uiBarIsStowed },\n\t\tshow     : { value : uiBarShow },\n\t\tstart    : { value : uiBarStart },\n\t\tstow     : { value : uiBarStow },\n\t\tunstow   : { value : uiBarUnstow },\n\t\tupdate   : { value : uiBarUpdate },\n\n\t\t// Legacy Functions.\n\t\tsetStoryElements : { value : uiBarUpdate }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tdebugbar.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal DebugView, Engine, L10n, Patterns, State, Util, session\n*/\n\nvar DebugBar = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tconst _variableRe   = new RegExp(`^${Patterns.variable}$`);\n\tconst _numericKeyRe = /^\\d+$/;\n\tconst _watchList    = [];\n\tlet _$debugBar   = null;\n\tlet _$watchBody  = null;\n\tlet _$watchList  = null;\n\tlet _$turnSelect = null;\n\tlet _stowed      = true;\n\n\n\t/*******************************************************************************************************************\n\t\tDebug Bar Functions.\n\t*******************************************************************************************************************/\n\tfunction debugBarInit() {\n\t\tif (DEBUG) { console.log('[DebugBar/debugBarInit()]'); }\n\n\t\t/*\n\t\t\tGenerate the debug bar elements and append them to the `<body>`.\n\t\t*/\n\t\tconst barToggleLabel   = L10n.get('debugBarToggle');\n\t\tconst watchAddLabel    = L10n.get('debugBarAddWatch');\n\t\tconst watchAllLabel    = L10n.get('debugBarWatchAll');\n\t\tconst watchNoneLabel   = L10n.get('debugBarWatchNone');\n\t\tconst watchToggleLabel = L10n.get('debugBarWatchToggle');\n\t\tconst viewsToggleLabel = L10n.get('debugBarViewsToggle');\n\n\t\tjQuery(document.createDocumentFragment())\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  '<div id=\"debug-bar\">'\n\t\t\t\t+     '<div id=\"debug-bar-watch\">'\n\t\t\t\t+         `<div>${L10n.get('debugBarNoWatches')}</div>>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div>'\n\t\t\t\t+         `<button id=\"debug-bar-watch-toggle\" tabindex=\"0\" title=\"${watchToggleLabel}\" aria-label=\"${watchToggleLabel}\">${L10n.get('debugBarLabelWatch')}</button>`\n\t\t\t\t+         `<label id=\"debug-bar-watch-label\" for=\"debug-bar-watch-input\">${L10n.get('debugBarLabelAdd')}</label>`\n\t\t\t\t+         '<input id=\"debug-bar-watch-input\" name=\"debug-bar-watch-input\" type=\"text\" list=\"debug-bar-watch-list\" tabindex=\"0\">'\n\t\t\t\t+         '<datalist id=\"debug-bar-watch-list\" aria-hidden=\"true\" hidden=\"hidden\"></datalist>'\n\t\t\t\t+         `<button id=\"debug-bar-watch-add\" tabindex=\"0\" title=\"${watchAddLabel}\" aria-label=\"${watchAddLabel}\"></button>`\n\t\t\t\t+         `<button id=\"debug-bar-watch-all\" tabindex=\"0\" title=\"${watchAllLabel}\" aria-label=\"${watchAllLabel}\"></button>`\n\t\t\t\t+         `<button id=\"debug-bar-watch-none\" tabindex=\"0\" title=\"${watchNoneLabel}\" aria-label=\"${watchNoneLabel}\"></button>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div>'\n\t\t\t\t+         `<button id=\"debug-bar-views-toggle\" tabindex=\"0\" title=\"${viewsToggleLabel}\" aria-label=\"${viewsToggleLabel}\">${L10n.get('debugBarLabelViews')}</button>`\n\t\t\t\t+         `<label id=\"debug-bar-turn-label\" for=\"debug-bar-turn-select\">${L10n.get('debugBarLabelTurn')}</label>`\n\t\t\t\t+         '<select id=\"debug-bar-turn-select\" tabindex=\"0\"></select>'\n\t\t\t\t+     '</div>'\n\t\t\t\t+     `<button id=\"debug-bar-toggle\" tabindex=\"0\" title=\"${barToggleLabel}\" aria-label=\"${barToggleLabel}\"></button>`\n\t\t\t\t+ '</div>'\n\t\t\t\t+ '<div id=\"debug-bar-hint\"></div>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t)\n\t\t\t.appendTo('body');\n\n\t\t/*\n\t\t\tCache various oft used elements.\n\n\t\t\tNOTE: We rewrap the elements themselves, rather than simply using\n\t\t\tthe results of `find()`, so that we cache uncluttered jQuery-wrappers\n\t\t\t(i.e. `context` refers to the elements and there is no `prevObject`).\n\t\t*/\n\t\t_$debugBar   = jQuery('#debug-bar');\n\t\t_$watchBody  = jQuery(_$debugBar.find('#debug-bar-watch').get(0));\n\t\t_$watchList  = jQuery(_$debugBar.find('#debug-bar-watch-list').get(0));\n\t\t_$turnSelect = jQuery(_$debugBar.find('#debug-bar-turn-select').get(0));\n\n\t\tconst $barToggle   = jQuery(_$debugBar.find('#debug-bar-toggle').get(0));\n\t\tconst $watchToggle = jQuery(_$debugBar.find('#debug-bar-watch-toggle').get(0));\n\t\tconst $watchInput  = jQuery(_$debugBar.find('#debug-bar-watch-input').get(0));\n\t\tconst $watchAdd    = jQuery(_$debugBar.find('#debug-bar-watch-add').get(0));\n\t\tconst $watchAll    = jQuery(_$debugBar.find('#debug-bar-watch-all').get(0));\n\t\tconst $watchNone   = jQuery(_$debugBar.find('#debug-bar-watch-none').get(0));\n\t\tconst $viewsToggle = jQuery(_$debugBar.find('#debug-bar-views-toggle').get(0));\n\n\t\t/*\n\t\t\tSet up the debug bar's local event handlers.\n\t\t*/\n\t\t$barToggle\n\t\t\t.ariaClick(debugBarToggle);\n\t\t$watchToggle\n\t\t\t.ariaClick(debugBarWatchToggle);\n\t\t$watchInput\n\t\t\t.on(':addwatch', function () {\n\t\t\t\tdebugBarWatchAdd(this.value.trim());\n\t\t\t\tthis.value = '';\n\t\t\t})\n\t\t\t.on('keypress', ev => {\n\t\t\t\tif (ev.which === 13) { // 13 is Return/Enter\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t$watchInput.trigger(':addwatch');\n\t\t\t\t}\n\t\t\t});\n\t\t$watchAdd\n\t\t\t.ariaClick(() => $watchInput.trigger(':addwatch'));\n\t\t$watchAll\n\t\t\t.ariaClick(debugBarWatchAddAll);\n\t\t$watchNone\n\t\t\t.ariaClick(debugBarWatchClear);\n\t\t_$turnSelect\n\t\t\t.on('change', function () {\n\t\t\t\tEngine.goTo(Number(this.value));\n\t\t\t});\n\t\t$viewsToggle\n\t\t\t.ariaClick(() => {\n\t\t\t\tDebugView.toggle();\n\t\t\t\t_updateSession();\n\t\t\t});\n\n\t\t/*\n\t\t\tSet up the debug bar's global event handlers.\n\t\t*/\n\t\tjQuery(document)\n\t\t\t// Set up a handler for the history select.\n\t\t\t.on(':historyupdate.debug-bar', _updateTurnSelect)\n\t\t\t// Set up a handler for the variables watch.\n\t\t\t.on(':passageend.debug-bar', () => {\n\t\t\t\t_updateWatchBody();\n\t\t\t\t_updateWatchList();\n\t\t\t})\n\t\t\t// Set up a handler for engine resets to clear the active debug session.\n\t\t\t.on(':enginerestart.debug-bar', _clearSession);\n\n\t\t/*\n\t\t\tInitially enable debug views if there's no active debug session.\n\t\t*/\n\t\tif (!_hasSession()) {\n\t\t\tDebugView.enable();\n\t\t}\n\t}\n\n\tfunction debugBarStart() {\n\t\tif (DEBUG) { console.log('[DebugBar/debugBarStart()]'); }\n\n\t\t// Attempt to restore an existing session.\n\t\t_restoreSession();\n\n\t\t// Update the UI.\n\t\t_updateBar();\n\t\t_updateTurnSelect();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t}\n\n\tfunction debugBarIsStowed() {\n\t\treturn _stowed;\n\t}\n\n\tfunction debugBarStow() {\n\t\t_debugBarStowNoUpdate();\n\t\t_stowed = true;\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarUnstow() {\n\t\t_debugBarUnstowNoUpdate();\n\t\t_stowed = false;\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarToggle() {\n\t\tif (_stowed) {\n\t\t\tdebugBarUnstow();\n\t\t}\n\t\telse {\n\t\t\tdebugBarStow();\n\t\t}\n\t}\n\n\tfunction debugBarWatchAdd(varName) {\n\t\tif (!_variableRe.test(varName)) {\n\t\t\treturn;\n\t\t}\n\n\t\t_watchList.pushUnique(varName);\n\t\t_watchList.sort();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchAddAll() {\n\t\tObject.keys(State.variables).map(name => _watchList.pushUnique(`$${name}`));\n\t\tObject.keys(State.temporary).map(name => _watchList.pushUnique(`_${name}`));\n\n\t\t_watchList.sort();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchClear() {\n\t\tfor (let i = _watchList.length - 1; i >= 0; --i) {\n\t\t\t_watchList.pop();\n\t\t}\n\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchDelete(varName) {\n\t\t_watchList.delete(varName);\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchDisable() {\n\t\t_debugBarWatchDisableNoUpdate();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchEnable() {\n\t\t_debugBarWatchEnableNoUpdate();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchIsEnabled() {\n\t\treturn !_$watchBody.attr('hidden');\n\t}\n\n\tfunction debugBarWatchToggle() {\n\t\tif (_$watchBody.attr('hidden')) {\n\t\t\tdebugBarWatchEnable();\n\t\t}\n\t\telse {\n\t\t\tdebugBarWatchDisable();\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _debugBarStowNoUpdate() {\n\t\t_$debugBar.css('right', `-${_$debugBar.outerWidth()}px`);\n\t}\n\n\tfunction _debugBarUnstowNoUpdate() {\n\t\t_$debugBar.css('right', 0);\n\t}\n\n\tfunction _debugBarWatchDisableNoUpdate() {\n\t\t_$watchBody.attr({\n\t\t\t'aria-hidden' : true,\n\t\t\thidden        : 'hidden'\n\t\t});\n\t}\n\n\tfunction _debugBarWatchEnableNoUpdate() {\n\t\t_$watchBody.removeAttr('aria-hidden hidden');\n\t}\n\n\tfunction _clearSession() {\n\t\tsession.delete('debugState');\n\t}\n\n\tfunction _hasSession() {\n\t\treturn session.has('debugState');\n\t}\n\n\tfunction _restoreSession() {\n\t\tif (!_hasSession()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst debugState = session.get('debugState');\n\n\t\t_stowed = debugState.stowed;\n\n\t\t_watchList.push(...debugState.watchList);\n\n\t\tif (debugState.watchEnabled) {\n\t\t\t_debugBarWatchEnableNoUpdate();\n\t\t}\n\t\telse {\n\t\t\t_debugBarWatchDisableNoUpdate();\n\t\t}\n\n\t\tif (debugState.viewsEnabled) {\n\t\t\tDebugView.enable();\n\t\t}\n\t\telse {\n\t\t\tDebugView.disable();\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction _updateSession() {\n\t\tsession.set('debugState', {\n\t\t\tstowed       : _stowed,\n\t\t\twatchList    : _watchList,\n\t\t\twatchEnabled : debugBarWatchIsEnabled(),\n\t\t\tviewsEnabled : DebugView.isEnabled()\n\t\t});\n\t}\n\n\tfunction _updateBar() {\n\t\tif (_stowed) {\n\t\t\tdebugBarStow();\n\t\t}\n\t\telse {\n\t\t\tdebugBarUnstow();\n\t\t}\n\t}\n\n\tfunction _updateWatchBody() {\n\t\tif (_watchList.length === 0) {\n\t\t\t_$watchBody\n\t\t\t\t.empty()\n\t\t\t\t.append(`<div>${L10n.get('debugBarNoWatches')}</div>`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst delLabel = L10n.get('debugBarDeleteWatch');\n\t\tconst $table   = jQuery(document.createElement('table'));\n\t\tconst $tbody   = jQuery(document.createElement('tbody'));\n\n\t\tfor (let i = 0, len = _watchList.length; i < len; ++i) {\n\t\t\tconst varName = _watchList[i];\n\t\t\tconst varKey  = varName.slice(1);\n\t\t\tconst store   = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\tconst $row    = jQuery(document.createElement('tr'));\n\t\t\tconst $delBtn = jQuery(document.createElement('button'));\n\t\t\tconst $code   = jQuery(document.createElement('code'));\n\n\t\t\t$delBtn\n\t\t\t\t.addClass('watch-delete')\n\t\t\t\t.attr('data-name', varName)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tone   : true,\n\t\t\t\t\tlabel : delLabel\n\t\t\t\t}, () => debugBarWatchDelete(varName));\n\t\t\t$code\n\t\t\t\t.text(_toWatchString(store[varKey]));\n\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.append($delBtn)\n\t\t\t\t.appendTo($row);\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.text(varName)\n\t\t\t\t.appendTo($row);\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.append($code)\n\t\t\t\t.appendTo($row);\n\t\t\t$row\n\t\t\t\t.appendTo($tbody);\n\t\t}\n\n\t\t$table\n\t\t\t.append($tbody);\n\t\t_$watchBody\n\t\t\t.empty()\n\t\t\t.append($table);\n\t}\n\n\tfunction _updateWatchList() {\n\t\tconst svn = Object.keys(State.variables);\n\t\tconst tvn = Object.keys(State.temporary);\n\n\t\tif (svn.length === 0 && tvn.length === 0) {\n\t\t\t_$watchList.empty();\n\t\t\treturn;\n\t\t}\n\n\t\tconst names   = [...svn.map(name => `$${name}`), ...tvn.map(name => `_${name}`)].sort();\n\t\tconst options = document.createDocumentFragment();\n\n\t\tnames.delete(_watchList);\n\n\t\tfor (let i = 0, len = names.length; i < len; ++i) {\n\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t.val(names[i])\n\t\t\t\t.appendTo(options);\n\t\t}\n\n\t\t_$watchList\n\t\t\t.empty()\n\t\t\t.append(options);\n\t}\n\n\tfunction _updateTurnSelect() {\n\t\tconst histLen = State.size;\n\t\tconst expLen  = State.expired.length;\n\t\tconst options = document.createDocumentFragment();\n\n\t\tfor (let i = 0; i < histLen; ++i) {\n\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t.val(i)\n\t\t\t\t.text(`${expLen + i + 1}. ${Util.escape(State.history[i].title)}`)\n\t\t\t\t.appendTo(options);\n\t\t}\n\n\t\t_$turnSelect\n\t\t\t.empty()\n\t\t\t.ariaDisabled(histLen < 2)\n\t\t\t.append(options)\n\t\t\t.val(State.activeIndex);\n\t}\n\n\tfunction _toWatchString(value) {\n\t\t/*\n\t\t\tHandle the `null` primitive.\n\t\t*/\n\t\tif (value === null) {\n\t\t\treturn 'null';\n\t\t}\n\n\t\t/*\n\t\t\tHandle the rest of the primitives and functions.\n\t\t*/\n\t\tswitch (typeof value) {\n\t\tcase 'number':\n\t\t\tif (Number.isNaN(value)) {\n\t\t\t\treturn 'NaN';\n\t\t\t}\n\t\t\telse if (!Number.isFinite(value)) {\n\t\t\t\treturn 'Infinity';\n\t\t\t}\n\t\t\t/* falls through */\n\t\tcase 'boolean':\n\t\tcase 'symbol':\n\t\tcase 'undefined':\n\t\t\treturn String(value);\n\n\t\tcase 'string':\n\t\t\treturn JSON.stringify(value);\n\n\t\t// case 'symbol':\n\t\t// \treturn `Symbol\\u202F\"${String(value).slice(7, -1)}\"`;\n\n\t\tcase 'function':\n\t\t\t// return JSON.stringify(value.toString());\n\t\t\treturn 'Function';\n\t\t}\n\n\t\tconst objType = Util.toStringTag(value);\n\n\t\t// /*\n\t\t// \tHandle instances of the primitive exemplar objects (`Boolean`, `Number`, `String`).\n\t\t// */\n\t\t// if (objType === 'Boolean') {\n\t\t// \treturn `Boolean\\u202F{${String(value)}}`;\n\t\t// }\n\t\t// if (objType === 'Number') {\n\t\t// \treturn `Number\\u202F{${String(value)}}`;\n\t\t// }\n\t\t// if (objType === 'String') {\n\t\t// \treturn `String\\u202F{\"${String(value)}\"}`;\n\t\t// }\n\n\t\t/*\n\t\t\tHandle `Date` objects.\n\t\t*/\n\t\tif (objType === 'Date') {\n\t\t\t// return `Date\\u202F${value.toISOString()}`;\n\t\t\treturn `Date\\u202F{${value.toLocaleString()}}`;\n\t\t}\n\n\t\t/*\n\t\t\tHandle `RegExp` objects.\n\t\t*/\n\t\tif (objType === 'RegExp') {\n\t\t\treturn `RegExp\\u202F${value.toString()}`;\n\t\t}\n\n\t\tconst result = [];\n\n\t\t/*\n\t\t\tHandle `Array` & `Set` objects.\n\t\t*/\n\t\tif (value instanceof Array || value instanceof Set) {\n\t\t\tconst list = value instanceof Array ? value : Array.from(value);\n\n\t\t\t// own numeric properties\n\t\t\t// NOTE: Do not use `<Array>.forEach()` here as it skips undefined members.\n\t\t\tfor (let i = 0, len = list.length; i < len; ++i) {\n\t\t\t\tresult.push(list.hasOwnProperty(i) ? _toWatchString(list[i]) : '<empty>');\n\t\t\t}\n\n\t\t\t// own enumerable non-numeric expando properties\n\t\t\tObject.keys(list)\n\t\t\t\t.filter(key => !_numericKeyRe.test(key))\n\t\t\t\t.forEach(key => result.push(`${_toWatchString(key)}: ${_toWatchString(list[key])}`));\n\n\t\t\treturn `${objType}(${list.length})\\u202F[${result.join(', ')}]`;\n\t\t}\n\n\t\t/*\n\t\t\tHandle `Map` objects.\n\t\t*/\n\t\tif (value instanceof Map) {\n\t\t\tvalue.forEach((val, key) => result.push(`${_toWatchString(key)} \\u2192 ${_toWatchString(val)}`));\n\n\t\t\treturn `${objType}(${value.size})\\u202F{${result.join(', ')}}`;\n\t\t}\n\n\t\t/*\n\t\t\tGeneral object handling.\n\t\t*/\n\t\t// own enumerable properties\n\t\tObject.keys(value)\n\t\t\t.forEach(key => result.push(`${_toWatchString(key)}: ${_toWatchString(value[key])}`));\n\n\t\treturn `${objType}\\u202F{${result.join(', ')}}`;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tDebug Bar Functions.\n\t\t*/\n\t\tinit     : { value : debugBarInit },\n\t\tisStowed : { value : debugBarIsStowed },\n\t\tstart    : { value : debugBarStart },\n\t\tstow     : { value : debugBarStow },\n\t\ttoggle   : { value : debugBarToggle },\n\t\tunstow   : { value : debugBarUnstow },\n\n\t\t/*\n\t\t\tWatch Functions.\n\t\t*/\n\t\twatch : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd       : { value : debugBarWatchAdd },\n\t\t\t\tall       : { value : debugBarWatchAddAll },\n\t\t\t\tclear     : { value : debugBarWatchClear },\n\t\t\t\tdelete    : { value : debugBarWatchDelete },\n\t\t\t\tdisable   : { value : debugBarWatchDisable },\n\t\t\t\tenable    : { value : debugBarWatchEnable },\n\t\t\t\tisEnabled : { value : debugBarWatchIsEnabled },\n\t\t\t\ttoggle    : { value : debugBarWatchToggle }\n\t\t\t}))\n\t\t}\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tloadscreen.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Engine */\n\nvar LoadScreen = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Locks collection.\n\tconst _locks = new Set();\n\n\t// Auto-incrementing lock ID.\n\tlet _autoId = 0;\n\n\n\t/*******************************************************************************************************************\n\t\tLoadScreen Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tInitialize management of the loading screen.\n\t*/\n\tfunction loadScreenInit() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenInit()]'); }\n\n\t\t// Add a `readystatechange` listener for hiding/showing the loading screen.\n\t\tjQuery(document).on('readystatechange.SugarCube', () => {\n\t\t\tif (DEBUG) { console.log(`[LoadScreen/<readystatechange>] document.readyState: \"${document.readyState}\"; locks(${_locks.size}):`, _locks); }\n\n\t\t\tif (_locks.size > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// The value of `document.readyState` may be: 'loading' -> 'interactive' -> 'complete'.\n\t\t\t// Though, to reach this point, it must already be in, at least, the 'interactive' state.\n\t\t\tif (document.readyState === 'complete') {\n\t\t\t\tif (jQuery(document.documentElement).attr('data-init') === 'loading') {\n\t\t\t\t\tif (Config.loadDelay > 0) {\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tif (_locks.size === 0) {\n\t\t\t\t\t\t\t\tloadScreenHide();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, Math.max(Engine.minDomActionDelay, Config.loadDelay));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tloadScreenHide();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloadScreenShow();\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\tClear the loading screen.\n\t*/\n\tfunction loadScreenClear() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenClear()]'); }\n\n\t\t// Remove the event listener.\n\t\tjQuery(document).off('readystatechange.SugarCube');\n\n\t\t// Clear all locks.\n\t\t_locks.clear();\n\n\t\t// Hide the loading screen.\n\t\tloadScreenHide();\n\t}\n\n\t/*\n\t\tHide the loading screen.\n\t*/\n\tfunction loadScreenHide() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenHide()]'); }\n\n\t\tjQuery(document.documentElement).removeAttr('data-init');\n\t}\n\n\t/*\n\t\tShow the loading screen.\n\t*/\n\tfunction loadScreenShow() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenShow()]'); }\n\n\t\tjQuery(document.documentElement).attr('data-init', 'loading');\n\t}\n\n\t/*\n\t\tReturns a new lock ID after locking and showing the loading screen.\n\t*/\n\tfunction loadScreenLock() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenLock()]'); }\n\n\t\t++_autoId;\n\t\t_locks.add(_autoId);\n\n\t\tif (DEBUG) { console.log(`\\tacquired loading screen lock; id: ${_autoId}`); }\n\n\t\tloadScreenShow();\n\t\treturn _autoId;\n\t}\n\n\t/*\n\t\tRemove the lock associated with the given lock ID and, if no locks remain,\n\t\ttrigger a `readystatechange` event.\n\t*/\n\tfunction loadScreenUnlock(id) {\n\t\tif (DEBUG) { console.log(`[LoadScreen/loadScreenUnlock(id: ${id})]`); }\n\n\t\tif (id == null) { // lazy equality for null\n\t\t\tthrow new Error('LoadScreen.unlock called with a null or undefined ID');\n\t\t}\n\n\t\tif (_locks.has(id)) {\n\t\t\t_locks.delete(id);\n\n\t\t\tif (DEBUG) { console.log(`\\treleased loading screen lock; id: ${id}`); }\n\t\t}\n\n\t\tif (_locks.size === 0) {\n\t\t\tjQuery(document).trigger('readystatechange');\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : loadScreenInit },\n\t\tclear  : { value : loadScreenClear },\n\t\thide   : { value : loadScreenHide },\n\t\tshow   : { value : loadScreenShow },\n\t\tlock   : { value : loadScreenLock },\n\t\tunlock : { value : loadScreenUnlock }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tsugarcube.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Browser, Config, Dialog, Engine, Fullscreen, Has, LoadScreen, SimpleStore, L10n, Macro, Passage,\n\t       Save, Scripting, Setting, SimpleAudio, State, Story, UI, UIBar, DebugBar, Util, Visibility, Wikifier\n*/\n/* eslint-disable no-var */\n\n/*\n\tVersion object.\n*/\nvar version = Object.freeze({\n\ttitle      : 'SugarCube',\n\tmajor      : 2,\n\tminor      : 31,\n\tpatch      : 1,\n\tprerelease : null,\n\tbuild      : 21,\n\tdate       : new Date(\"2020-04-15T12:06:24.618Z\"),\n\t/* legacy */\n\textensions : {},\n\t/* /legacy */\n\n\ttoString() {\n\t\t'use strict';\n\n\t\tconst prerelease = this.prerelease ? `-${this.prerelease}` : '';\n\t\treturn `${this.major}.${this.minor}.${this.patch}${prerelease}+${this.build}`;\n\t},\n\n\tshort() {\n\t\t'use strict';\n\n\t\tconst prerelease = this.prerelease ? `-${this.prerelease}` : '';\n\t\treturn `${this.title} (v${this.major}.${this.minor}.${this.patch}${prerelease})`;\n\t},\n\n\tlong() {\n\t\t'use strict';\n\n\t\treturn `${this.title} v${this.toString()} (${this.date.toUTCString()})`;\n\t}\n});\n\n/* eslint-disable no-unused-vars */\n/*\n\tInternal variables.\n*/\n// Temporary state object.\nvar TempState = {};\n\n// Legacy macros object.\nvar macros = {};\n\n// Post-display task callbacks object.\nvar postdisplay = {};\n\n// Post-render task callbacks object.\nvar postrender = {};\n\n// Pre-display task callbacks object.\nvar predisplay = {};\n\n// Pre-history task callbacks object.\nvar prehistory = {};\n\n// Pre-render task callbacks object.\nvar prerender = {};\n\n// Session storage manager object.\nvar session = null;\n\n// Settings object.\nvar settings = {};\n\n// Setup object.\nvar setup = {};\n\n// Persistant storage manager object.\nvar storage = null;\n\n/*\n\tLegacy aliases.\n*/\nvar browser       = Browser;\nvar config        = Config;\nvar has           = Has;\nvar History       = State;\nvar state         = State;\nvar tale          = Story;\nvar TempVariables = State.temporary;\n/* eslint-enable no-unused-vars */\n\n/*\n\tGlobal `SugarCube` object.  Allows scripts to detect if they're running in SugarCube by\n\ttesting for the object (e.g. `\"SugarCube\" in window`) and contains exported identifiers\n\tfor debugging purposes.\n*/\nwindow.SugarCube = {};\n\n/*\n\tMain function, entry point for the story.\n*/\njQuery(() => {\n\t'use strict';\n\n\tif (DEBUG) { console.log('[SugarCube/main()] Document loaded; beginning startup.'); }\n\n\t/*\n\t\tWARNING!\n\n\t\tThe ordering of the code within this function is critically important,\n\t\tso be careful when mucking around with it.\n\t*/\n\ttry {\n\t\t// Acquire an initial lock for and initialize the loading screen.\n\t\tconst lockId = LoadScreen.lock();\n\t\tLoadScreen.init();\n\n\t\t// Normalize the document.\n\t\tif (document.normalize) {\n\t\t\tdocument.normalize();\n\t\t}\n\n\t\t// Load the story data (must be done before most anything else).\n\t\tStory.load();\n\n\t\t// Instantiate the storage and session objects.\n\t\t// NOTE: `SimpleStore.create(storageId, persistent)`\n\t\tstorage = SimpleStore.create(Story.domId, true);\n\t\tsession = SimpleStore.create(Story.domId, false);\n\n\t\t// Initialize the user interface (must be done before story initialization, specifically before scripts).\n\t\tDialog.init();\n\t\tUIBar.init();\n\t\tEngine.init();\n\n\t\t// Initialize the story (largely load the user styles, scripts, and widgets).\n\t\tStory.init();\n\n\t\t// Initialize the localization (must be done after story initialization).\n\t\tL10n.init();\n\n\t\t// Alert when the browser is degrading required capabilities (must be done after localization initialization).\n\t\tif (!session.has('rcWarn') && storage.name === 'cookie') {\n\t\t\t/* eslint-disable no-alert */\n\t\t\tsession.set('rcWarn', 1);\n\t\t\twindow.alert(L10n.get('warningNoWebStorage'));\n\t\t\t/* eslint-enable no-alert */\n\t\t}\n\n\t\t// Initialize the saves (must be done after story initialization, but before engine start).\n\t\tSave.init();\n\n\t\t// Initialize the settings.\n\t\tSetting.init();\n\n\t\t// Initialize the macros.\n\t\tMacro.init();\n\n\t\t// Start the engine (should be done as late as possible, but before interface startup).\n\t\tEngine.start();\n\n\t\t// Initialize the debug bar interface (should be done as late as possible, but before interface startup).\n\t\tif (Config.debug) {\n\t\t\tDebugBar.init();\n\t\t}\n\n\t\t// Set a recurring timer to start the interfaces (necessary due to DOM readiness issues in some browsers).\n\t\tconst $window    = $(window);\n\t\tconst vprCheckId = setInterval(() => {\n\t\t\t// If `$window.width()` returns a zero value, bail out and wait.\n\t\t\tif (!$window.width()) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Clear the recurring timer.\n\t\t\tclearInterval(vprCheckId);\n\n\t\t\t// Start the UI bar interface.\n\t\t\tUIBar.start();\n\n\t\t\t// Start the debug bar interface.\n\t\t\tif (Config.debug) {\n\t\t\t\tDebugBar.start();\n\t\t\t}\n\n\t\t\t// Trigger the `:storyready` global synthetic event.\n\t\t\tjQuery.event.trigger({ type : ':storyready' });\n\n\t\t\t// Release the loading screen lock after a short delay.\n\t\t\tsetTimeout(() => LoadScreen.unlock(lockId), Engine.minDomActionDelay * 2);\n\t\t}, Engine.minDomActionDelay);\n\n\t\t// Finally, export identifiers for debugging purposes.\n\t\tObject.defineProperty(window, 'SugarCube', {\n\t\t\t// WARNING: We need to assign new values at points, so seal it, do not freeze it.\n\t\t\tvalue : Object.seal(Object.assign(Object.create(null), {\n\t\t\t\tBrowser,\n\t\t\t\tConfig,\n\t\t\t\tDialog,\n\t\t\t\tEngine,\n\t\t\t\tFullscreen,\n\t\t\t\tHas,\n\t\t\t\tL10n,\n\t\t\t\tMacro,\n\t\t\t\tPassage,\n\t\t\t\tSave,\n\t\t\t\tScripting,\n\t\t\t\tSetting,\n\t\t\t\tSimpleAudio,\n\t\t\t\tState,\n\t\t\t\tStory,\n\t\t\t\tUI,\n\t\t\t\tUIBar,\n\t\t\t\tDebugBar,\n\t\t\t\tUtil,\n\t\t\t\tVisibility,\n\t\t\t\tWikifier,\n\t\t\t\tsession,\n\t\t\t\tsettings,\n\t\t\t\tsetup,\n\t\t\t\tstorage,\n\t\t\t\tversion\n\t\t\t}))\n\t\t});\n\n\t\tif (DEBUG) { console.log('[SugarCube/main()] Startup complete; story ready.'); }\n\t}\n\tcatch (ex) {\n\t\tconsole.error(ex);\n\t\tLoadScreen.clear();\n\t\treturn Alert.fatal(null, ex.message, ex);\n\t}\n});\n\n})(window, window.document, jQuery);\n}\n\t</script>\n</body>\n</html>\n"});
\ No newline at end of file
+window.storyFormat({"name":"SugarCube","version":"2.31.1","description":"A full featured, highly customizable story format.  See its <a href=\"http://www.motoslave.net/sugarcube/2/#documentation\" target=\"_blank\">documentation</a>.","author":"Thomas Michael Edwards","image":"icon.svg","url":"http://www.motoslave.net/sugarcube/","license":"BSD-2-Clause","proofing":false,"source":"<!DOCTYPE html>\n<html data-init=\"no-js\">\n<head>\n<meta charset=\"UTF-8\" />\n<title>{{STORY_NAME}}</title>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n<!--\n\nSugarCube (v2.31.1): A free (gratis and libre) story format.\n\nCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n-->\n<script id=\"script-libraries\" type=\"text/javascript\">\nif(document.head&&document.addEventListener&&document.querySelector&&Object.create&&Object.freeze&&JSON){document.documentElement.setAttribute(\"data-init\", \"loading\");\n/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js */\nif(\"document\" in self){if(!(\"classList\" in document.createElement(\"_\"))){(function(j){\"use strict\";if(!(\"Element\" in j)){return}var a=\"classList\",f=\"prototype\",m=j.Element[f],b=Object,k=String[f].trim||function(){return this.replace(/^\\s+|\\s+$/g,\"\")},c=Array[f].indexOf||function(q){var p=0,o=this.length;for(;p<o;p++){if(p in this&&this[p]===q){return p}}return -1},n=function(o,p){this.name=o;this.code=DOMException[o];this.message=p},g=function(p,o){if(o===\"\"){throw new n(\"SYNTAX_ERR\",\"An invalid or illegal string was specified\")}if(/\\s/.test(o)){throw new n(\"INVALID_CHARACTER_ERR\",\"String contains an invalid character\")}return c.call(p,o)},d=function(s){var r=k.call(s.getAttribute(\"class\")||\"\"),q=r?r.split(/\\s+/):[],p=0,o=q.length;for(;p<o;p++){this.push(q[p])}this._updateClassName=function(){s.setAttribute(\"class\",this.toString())}},e=d[f]=[],i=function(){return new d(this)};n[f]=Error[f];e.item=function(o){return this[o]||null};e.contains=function(o){o+=\"\";return g(this,o)!==-1};e.add=function(){var s=arguments,r=0,p=s.length,q,o=false;do{q=s[r]+\"\";if(g(this,q)===-1){this.push(q);o=true}}while(++r<p);if(o){this._updateClassName()}};e.remove=function(){var t=arguments,s=0,p=t.length,r,o=false,q;do{r=t[s]+\"\";q=g(this,r);while(q!==-1){this.splice(q,1);o=true;q=g(this,r)}}while(++s<p);if(o){this._updateClassName()}};e.toggle=function(p,q){p+=\"\";var o=this.contains(p),r=o?q!==true&&\"remove\":q!==false&&\"add\";if(r){this[r](p)}if(q===true||q===false){return q}else{return !o}};e.toString=function(){return this.join(\" \")};if(b.defineProperty){var l={get:i,enumerable:true,configurable:true};try{b.defineProperty(m,a,l)}catch(h){if(h.number===-2146823252){l.enumerable=false;b.defineProperty(m,a,l)}}}else{if(b[f].__defineGetter__){m.__defineGetter__(a,i)}}}(self))}else{(function(){var b=document.createElement(\"_\");b.classList.add(\"c1\",\"c2\");if(!b.classList.contains(\"c2\")){var c=function(e){var d=DOMTokenList.prototype[e];DOMTokenList.prototype[e]=function(h){var g,f=arguments.length;for(g=0;g<f;g++){h=arguments[g];d.call(this,h)}}};c(\"add\");c(\"remove\")}b.classList.toggle(\"c3\",false);if(b.classList.contains(\"c3\")){var a=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(d,e){if(1 in arguments&&!this.contains(d)===!e){return e}else{return a.call(this,d)}}}b=null}())}};\n/*!\n * https://github.com/es-shims/es5-shim\n * @license es5-shim Copyright 2009-2015 by contributors, MIT License\n * see https://github.com/es-shims/es5-shim/blob/v4.5.13/LICENSE\n */\n(function(t,r){\"use strict\";if(typeof define===\"function\"&&define.amd){define(r)}else if(typeof exports===\"object\"){module.exports=r()}else{t.returnExports=r()}})(this,function(){var t=Array;var r=t.prototype;var e=Object;var n=e.prototype;var i=Function;var a=i.prototype;var o=String;var f=o.prototype;var u=Number;var l=u.prototype;var s=r.slice;var c=r.splice;var v=r.push;var h=r.unshift;var p=r.concat;var y=r.join;var d=a.call;var g=a.apply;var w=Math.max;var b=Math.min;var T=n.toString;var m=typeof Symbol===\"function\"&&typeof Symbol.toStringTag===\"symbol\";var D;var S=Function.prototype.toString,x=/^\\s*class /,O=function isES6ClassFn(t){try{var r=S.call(t);var e=r.replace(/\\/\\/.*\\n/g,\"\");var n=e.replace(/\\/\\*[.\\s\\S]*\\*\\//g,\"\");var i=n.replace(/\\n/gm,\" \").replace(/ {2}/g,\" \");return x.test(i)}catch(a){return false}},E=function tryFunctionObject(t){try{if(O(t)){return false}S.call(t);return true}catch(r){return false}},j=\"[object Function]\",I=\"[object GeneratorFunction]\",D=function isCallable(t){if(!t){return false}if(typeof t!==\"function\"&&typeof t!==\"object\"){return false}if(m){return E(t)}if(O(t)){return false}var r=T.call(t);return r===j||r===I};var M;var U=RegExp.prototype.exec,$=function tryRegexExec(t){try{U.call(t);return true}catch(r){return false}},F=\"[object RegExp]\";M=function isRegex(t){if(typeof t!==\"object\"){return false}return m?$(t):T.call(t)===F};var N;var C=String.prototype.valueOf,k=function tryStringObject(t){try{C.call(t);return true}catch(r){return false}},A=\"[object String]\";N=function isString(t){if(typeof t===\"string\"){return true}if(typeof t!==\"object\"){return false}return m?k(t):T.call(t)===A};var R=e.defineProperty&&function(){try{var t={};e.defineProperty(t,\"x\",{enumerable:false,value:t});for(var r in t){return false}return t.x===t}catch(n){return false}}();var P=function(t){var r;if(R){r=function(t,r,n,i){if(!i&&r in t){return}e.defineProperty(t,r,{configurable:true,enumerable:false,writable:true,value:n})}}else{r=function(t,r,e,n){if(!n&&r in t){return}t[r]=e}}return function defineProperties(e,n,i){for(var a in n){if(t.call(n,a)){r(e,a,n[a],i)}}}}(n.hasOwnProperty);var J=function isPrimitive(t){var r=typeof t;return t===null||r!==\"object\"&&r!==\"function\"};var Y=u.isNaN||function isActualNaN(t){return t!==t};var z={ToInteger:function ToInteger(t){var r=+t;if(Y(r)){r=0}else if(r!==0&&r!==1/0&&r!==-(1/0)){r=(r>0||-1)*Math.floor(Math.abs(r))}return r},ToPrimitive:function ToPrimitive(t){var r,e,n;if(J(t)){return t}e=t.valueOf;if(D(e)){r=e.call(t);if(J(r)){return r}}n=t.toString;if(D(n)){r=n.call(t);if(J(r)){return r}}throw new TypeError},ToObject:function(t){if(t==null){throw new TypeError(\"can't convert \"+t+\" to object\")}return e(t)},ToUint32:function ToUint32(t){return t>>>0}};var Z=function Empty(){};P(a,{bind:function bind(t){var r=this;if(!D(r)){throw new TypeError(\"Function.prototype.bind called on incompatible \"+r)}var n=s.call(arguments,1);var a;var o=function(){if(this instanceof a){var i=g.call(r,this,p.call(n,s.call(arguments)));if(e(i)===i){return i}return this}else{return g.call(r,t,p.call(n,s.call(arguments)))}};var f=w(0,r.length-n.length);var u=[];for(var l=0;l<f;l++){v.call(u,\"$\"+l)}a=i(\"binder\",\"return function (\"+y.call(u,\",\")+\"){ return binder.apply(this, arguments); }\")(o);if(r.prototype){Z.prototype=r.prototype;a.prototype=new Z;Z.prototype=null}return a}});var G=d.bind(n.hasOwnProperty);var H=d.bind(n.toString);var W=d.bind(s);var B=g.bind(s);if(typeof document===\"object\"&&document&&document.documentElement){try{W(document.documentElement.childNodes)}catch(X){var L=W;var q=B;W=function arraySliceIE(t){var r=[];var e=t.length;while(e-- >0){r[e]=t[e]}return q(r,L(arguments,1))};B=function arraySliceApplyIE(t,r){return q(W(t),r)}}}var K=d.bind(f.slice);var Q=d.bind(f.split);var V=d.bind(f.indexOf);var _=d.bind(v);var tt=d.bind(n.propertyIsEnumerable);var rt=d.bind(r.sort);var et=t.isArray||function isArray(t){return H(t)===\"[object Array]\"};var nt=[].unshift(0)!==1;P(r,{unshift:function(){h.apply(this,arguments);return this.length}},nt);P(t,{isArray:et});var it=e(\"a\");var at=it[0]!==\"a\"||!(0 in it);var ot=function properlyBoxed(t){var r=true;var e=true;var n=false;if(t){try{t.call(\"foo\",function(t,e,n){if(typeof n!==\"object\"){r=false}});t.call([1],function(){\"use strict\";e=typeof this===\"string\"},\"x\")}catch(i){n=true}}return!!t&&!n&&r&&e};P(r,{forEach:function forEach(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=-1;var i=z.ToUint32(e.length);var a;if(arguments.length>1){a=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.forEach callback must be a function\")}while(++n<i){if(n in e){if(typeof a===\"undefined\"){t(e[n],n,r)}else{t.call(a,e[n],n,r)}}}}},!ot(r.forEach));P(r,{map:function map(r){var e=z.ToObject(this);var n=at&&N(this)?Q(this,\"\"):e;var i=z.ToUint32(n.length);var a=t(i);var o;if(arguments.length>1){o=arguments[1]}if(!D(r)){throw new TypeError(\"Array.prototype.map callback must be a function\")}for(var f=0;f<i;f++){if(f in n){if(typeof o===\"undefined\"){a[f]=r(n[f],f,e)}else{a[f]=r.call(o,n[f],f,e)}}}return a}},!ot(r.map));P(r,{filter:function filter(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i=[];var a;var o;if(arguments.length>1){o=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.filter callback must be a function\")}for(var f=0;f<n;f++){if(f in e){a=e[f];if(typeof o===\"undefined\"?t(a,f,r):t.call(o,a,f,r)){_(i,a)}}}return i}},!ot(r.filter));P(r,{every:function every(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i;if(arguments.length>1){i=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.every callback must be a function\")}for(var a=0;a<n;a++){if(a in e&&!(typeof i===\"undefined\"?t(e[a],a,r):t.call(i,e[a],a,r))){return false}}return true}},!ot(r.every));P(r,{some:function some(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);var i;if(arguments.length>1){i=arguments[1]}if(!D(t)){throw new TypeError(\"Array.prototype.some callback must be a function\")}for(var a=0;a<n;a++){if(a in e&&(typeof i===\"undefined\"?t(e[a],a,r):t.call(i,e[a],a,r))){return true}}return false}},!ot(r.some));var ft=false;if(r.reduce){ft=typeof r.reduce.call(\"es5\",function(t,r,e,n){return n})===\"object\"}P(r,{reduce:function reduce(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);if(!D(t)){throw new TypeError(\"Array.prototype.reduce callback must be a function\")}if(n===0&&arguments.length===1){throw new TypeError(\"reduce of empty array with no initial value\")}var i=0;var a;if(arguments.length>=2){a=arguments[1]}else{do{if(i in e){a=e[i++];break}if(++i>=n){throw new TypeError(\"reduce of empty array with no initial value\")}}while(true)}for(;i<n;i++){if(i in e){a=t(a,e[i],i,r)}}return a}},!ft);var ut=false;if(r.reduceRight){ut=typeof r.reduceRight.call(\"es5\",function(t,r,e,n){return n})===\"object\"}P(r,{reduceRight:function reduceRight(t){var r=z.ToObject(this);var e=at&&N(this)?Q(this,\"\"):r;var n=z.ToUint32(e.length);if(!D(t)){throw new TypeError(\"Array.prototype.reduceRight callback must be a function\")}if(n===0&&arguments.length===1){throw new TypeError(\"reduceRight of empty array with no initial value\")}var i;var a=n-1;if(arguments.length>=2){i=arguments[1]}else{do{if(a in e){i=e[a--];break}if(--a<0){throw new TypeError(\"reduceRight of empty array with no initial value\")}}while(true)}if(a<0){return i}do{if(a in e){i=t(i,e[a],a,r)}}while(a--);return i}},!ut);var lt=r.indexOf&&[0,1].indexOf(1,2)!==-1;P(r,{indexOf:function indexOf(t){var r=at&&N(this)?Q(this,\"\"):z.ToObject(this);var e=z.ToUint32(r.length);if(e===0){return-1}var n=0;if(arguments.length>1){n=z.ToInteger(arguments[1])}n=n>=0?n:w(0,e+n);for(;n<e;n++){if(n in r&&r[n]===t){return n}}return-1}},lt);var st=r.lastIndexOf&&[0,1].lastIndexOf(0,-3)!==-1;P(r,{lastIndexOf:function lastIndexOf(t){var r=at&&N(this)?Q(this,\"\"):z.ToObject(this);var e=z.ToUint32(r.length);if(e===0){return-1}var n=e-1;if(arguments.length>1){n=b(n,z.ToInteger(arguments[1]))}n=n>=0?n:e-Math.abs(n);for(;n>=0;n--){if(n in r&&t===r[n]){return n}}return-1}},st);var ct=function(){var t=[1,2];var r=t.splice();return t.length===2&&et(r)&&r.length===0}();P(r,{splice:function splice(t,r){if(arguments.length===0){return[]}else{return c.apply(this,arguments)}}},!ct);var vt=function(){var t={};r.splice.call(t,0,0,1);return t.length===1}();P(r,{splice:function splice(t,r){if(arguments.length===0){return[]}var e=arguments;this.length=w(z.ToInteger(this.length),0);if(arguments.length>0&&typeof r!==\"number\"){e=W(arguments);if(e.length<2){_(e,this.length-t)}else{e[1]=z.ToInteger(r)}}return c.apply(this,e)}},!vt);var ht=function(){var r=new t(1e5);r[8]=\"x\";r.splice(1,1);return r.indexOf(\"x\")===7}();var pt=function(){var t=256;var r=[];r[t]=\"a\";r.splice(t+1,0,\"b\");return r[t]===\"a\"}();P(r,{splice:function splice(t,r){var e=z.ToObject(this);var n=[];var i=z.ToUint32(e.length);var a=z.ToInteger(t);var f=a<0?w(i+a,0):b(a,i);var u=b(w(z.ToInteger(r),0),i-f);var l=0;var s;while(l<u){s=o(f+l);if(G(e,s)){n[l]=e[s]}l+=1}var c=W(arguments,2);var v=c.length;var h;if(v<u){l=f;var p=i-u;while(l<p){s=o(l+u);h=o(l+v);if(G(e,s)){e[h]=e[s]}else{delete e[h]}l+=1}l=i;var y=i-u+v;while(l>y){delete e[l-1];l-=1}}else if(v>u){l=i-u;while(l>f){s=o(l+u-1);h=o(l+v-1);if(G(e,s)){e[h]=e[s]}else{delete e[h]}l-=1}}l=f;for(var d=0;d<c.length;++d){e[l]=c[d];l+=1}e.length=i-u+v;return n}},!ht||!pt);var yt=r.join;var dt;try{dt=Array.prototype.join.call(\"123\",\",\")!==\"1,2,3\"}catch(X){dt=true}if(dt){P(r,{join:function join(t){var r=typeof t===\"undefined\"?\",\":t;return yt.call(N(this)?Q(this,\"\"):this,r)}},dt)}var gt=[1,2].join(undefined)!==\"1,2\";if(gt){P(r,{join:function join(t){var r=typeof t===\"undefined\"?\",\":t;return yt.call(this,r)}},gt)}var wt=function push(t){var r=z.ToObject(this);var e=z.ToUint32(r.length);var n=0;while(n<arguments.length){r[e+n]=arguments[n];n+=1}r.length=e+n;return e+n};var bt=function(){var t={};var r=Array.prototype.push.call(t,undefined);return r!==1||t.length!==1||typeof t[0]!==\"undefined\"||!G(t,0)}();P(r,{push:function push(t){if(et(this)){return v.apply(this,arguments)}return wt.apply(this,arguments)}},bt);var Tt=function(){var t=[];var r=t.push(undefined);return r!==1||t.length!==1||typeof t[0]!==\"undefined\"||!G(t,0)}();P(r,{push:wt},Tt);P(r,{slice:function(t,r){var e=N(this)?Q(this,\"\"):this;return B(e,arguments)}},at);var mt=function(){try{[1,2].sort(null)}catch(t){try{[1,2].sort({})}catch(r){return false}}return true}();var Dt=function(){try{[1,2].sort(/a/);return false}catch(t){}return true}();var St=function(){try{[1,2].sort(undefined);return true}catch(t){}return false}();P(r,{sort:function sort(t){if(typeof t===\"undefined\"){return rt(this)}if(!D(t)){throw new TypeError(\"Array.prototype.sort callback must be a function\")}return rt(this,t)}},mt||!St||!Dt);var xt=!tt({toString:null},\"toString\");var Ot=tt(function(){},\"prototype\");var Et=!G(\"x\",\"0\");var jt=function(t){var r=t.constructor;return r&&r.prototype===t};var It={$applicationCache:true,$console:true,$external:true,$frame:true,$frameElement:true,$frames:true,$innerHeight:true,$innerWidth:true,$onmozfullscreenchange:true,$onmozfullscreenerror:true,$outerHeight:true,$outerWidth:true,$pageXOffset:true,$pageYOffset:true,$parent:true,$scrollLeft:true,$scrollTop:true,$scrollX:true,$scrollY:true,$self:true,$webkitIndexedDB:true,$webkitStorageInfo:true,$window:true,$width:true,$height:true,$top:true,$localStorage:true};var Mt=function(){if(typeof window===\"undefined\"){return false}for(var t in window){try{if(!It[\"$\"+t]&&G(window,t)&&window[t]!==null&&typeof window[t]===\"object\"){jt(window[t])}}catch(r){return true}}return false}();var Ut=function(t){if(typeof window===\"undefined\"||!Mt){return jt(t)}try{return jt(t)}catch(r){return false}};var $t=[\"toString\",\"toLocaleString\",\"valueOf\",\"hasOwnProperty\",\"isPrototypeOf\",\"propertyIsEnumerable\",\"constructor\"];var Ft=$t.length;var Nt=function isArguments(t){return H(t)===\"[object Arguments]\"};var Ct=function isArguments(t){return t!==null&&typeof t===\"object\"&&typeof t.length===\"number\"&&t.length>=0&&!et(t)&&D(t.callee)};var kt=Nt(arguments)?Nt:Ct;P(e,{keys:function keys(t){var r=D(t);var e=kt(t);var n=t!==null&&typeof t===\"object\";var i=n&&N(t);if(!n&&!r&&!e){throw new TypeError(\"Object.keys called on a non-object\")}var a=[];var f=Ot&&r;if(i&&Et||e){for(var u=0;u<t.length;++u){_(a,o(u))}}if(!e){for(var l in t){if(!(f&&l===\"prototype\")&&G(t,l)){_(a,o(l))}}}if(xt){var s=Ut(t);for(var c=0;c<Ft;c++){var v=$t[c];if(!(s&&v===\"constructor\")&&G(t,v)){_(a,v)}}}return a}});var At=e.keys&&function(){return e.keys(arguments).length===2}(1,2);var Rt=e.keys&&function(){var t=e.keys(arguments);return arguments.length!==1||t.length!==1||t[0]!==1}(1);var Pt=e.keys;P(e,{keys:function keys(t){if(kt(t)){return Pt(W(t))}else{return Pt(t)}}},!At||Rt);var Jt=new Date(-0xc782b5b342b24).getUTCMonth()!==0;var Yt=new Date(-0x55d318d56a724);var zt=new Date(14496624e5);var Zt=Yt.toUTCString()!==\"Mon, 01 Jan -45875 11:59:59 GMT\";var Gt;var Ht;var Wt=Yt.getTimezoneOffset();if(Wt<-720){Gt=Yt.toDateString()!==\"Tue Jan 02 -45875\";Ht=!/^Thu Dec 10 2015 \\d\\d:\\d\\d:\\d\\d GMT[-+]\\d\\d\\d\\d(?: |$)/.test(String(zt))}else{Gt=Yt.toDateString()!==\"Mon Jan 01 -45875\";Ht=!/^Wed Dec 09 2015 \\d\\d:\\d\\d:\\d\\d GMT[-+]\\d\\d\\d\\d(?: |$)/.test(String(zt))}var Bt=d.bind(Date.prototype.getFullYear);var Xt=d.bind(Date.prototype.getMonth);var Lt=d.bind(Date.prototype.getDate);var qt=d.bind(Date.prototype.getUTCFullYear);var Kt=d.bind(Date.prototype.getUTCMonth);var Qt=d.bind(Date.prototype.getUTCDate);var Vt=d.bind(Date.prototype.getUTCDay);var _t=d.bind(Date.prototype.getUTCHours);var tr=d.bind(Date.prototype.getUTCMinutes);var rr=d.bind(Date.prototype.getUTCSeconds);var er=d.bind(Date.prototype.getUTCMilliseconds);var nr=[\"Sun\",\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\"];var ir=[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"];var ar=function daysInMonth(t,r){return Lt(new Date(r,t,0))};P(Date.prototype,{getFullYear:function getFullYear(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);if(t<0&&Xt(this)>11){return t+1}return t},getMonth:function getMonth(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);var r=Xt(this);if(t<0&&r>11){return 0}return r},getDate:function getDate(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Bt(this);var r=Xt(this);var e=Lt(this);if(t<0&&r>11){if(r===12){return e}var n=ar(0,t+1);return n-e+1}return e},getUTCFullYear:function getUTCFullYear(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);if(t<0&&Kt(this)>11){return t+1}return t},getUTCMonth:function getUTCMonth(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);var r=Kt(this);if(t<0&&r>11){return 0}return r},getUTCDate:function getUTCDate(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=qt(this);var r=Kt(this);var e=Qt(this);if(t<0&&r>11){if(r===12){return e}var n=ar(0,t+1);return n-e+1}return e}},Jt);P(Date.prototype,{toUTCString:function toUTCString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=Vt(this);var r=Qt(this);var e=Kt(this);var n=qt(this);var i=_t(this);var a=tr(this);var o=rr(this);return nr[t]+\", \"+(r<10?\"0\"+r:r)+\" \"+ir[e]+\" \"+n+\" \"+(i<10?\"0\"+i:i)+\":\"+(a<10?\"0\"+a:a)+\":\"+(o<10?\"0\"+o:o)+\" GMT\"}},Jt||Zt);P(Date.prototype,{toDateString:function toDateString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=this.getDay();var r=this.getDate();var e=this.getMonth();var n=this.getFullYear();return nr[t]+\" \"+ir[e]+\" \"+(r<10?\"0\"+r:r)+\" \"+n}},Jt||Gt);if(Jt||Ht){Date.prototype.toString=function toString(){if(!this||!(this instanceof Date)){throw new TypeError(\"this is not a Date object.\")}var t=this.getDay();var r=this.getDate();var e=this.getMonth();var n=this.getFullYear();var i=this.getHours();var a=this.getMinutes();var o=this.getSeconds();var f=this.getTimezoneOffset();var u=Math.floor(Math.abs(f)/60);var l=Math.floor(Math.abs(f)%60);return nr[t]+\" \"+ir[e]+\" \"+(r<10?\"0\"+r:r)+\" \"+n+\" \"+(i<10?\"0\"+i:i)+\":\"+(a<10?\"0\"+a:a)+\":\"+(o<10?\"0\"+o:o)+\" GMT\"+(f>0?\"-\":\"+\")+(u<10?\"0\"+u:u)+(l<10?\"0\"+l:l)};if(R){e.defineProperty(Date.prototype,\"toString\",{configurable:true,enumerable:false,writable:true})}}var or=-621987552e5;var fr=\"-000001\";var ur=Date.prototype.toISOString&&new Date(or).toISOString().indexOf(fr)===-1;var lr=Date.prototype.toISOString&&new Date(-1).toISOString()!==\"1969-12-31T23:59:59.999Z\";var sr=d.bind(Date.prototype.getTime);P(Date.prototype,{toISOString:function toISOString(){if(!isFinite(this)||!isFinite(sr(this))){throw new RangeError(\"Date.prototype.toISOString called on non-finite value.\")}var t=qt(this);var r=Kt(this);t+=Math.floor(r/12);r=(r%12+12)%12;var e=[r+1,Qt(this),_t(this),tr(this),rr(this)];t=(t<0?\"-\":t>9999?\"+\":\"\")+K(\"00000\"+Math.abs(t),0<=t&&t<=9999?-4:-6);for(var n=0;n<e.length;++n){e[n]=K(\"00\"+e[n],-2)}return t+\"-\"+W(e,0,2).join(\"-\")+\"T\"+W(e,2).join(\":\")+\".\"+K(\"000\"+er(this),-3)+\"Z\"}},ur||lr);var cr=function(){try{return Date.prototype.toJSON&&new Date(NaN).toJSON()===null&&new Date(or).toJSON().indexOf(fr)!==-1&&Date.prototype.toJSON.call({toISOString:function(){return true}})}catch(t){return false}}();if(!cr){Date.prototype.toJSON=function toJSON(t){var r=e(this);var n=z.ToPrimitive(r);if(typeof n===\"number\"&&!isFinite(n)){return null}var i=r.toISOString;if(!D(i)){throw new TypeError(\"toISOString property is not callable\")}return i.call(r)}}var vr=Date.parse(\"+033658-09-27T01:46:40.000Z\")===1e15;var hr=!isNaN(Date.parse(\"2012-04-04T24:00:00.500Z\"))||!isNaN(Date.parse(\"2012-11-31T23:59:59.000Z\"))||!isNaN(Date.parse(\"2012-12-31T23:59:60.000Z\"));var pr=isNaN(Date.parse(\"2000-01-01T00:00:00.000Z\"));if(pr||hr||!vr){var yr=Math.pow(2,31)-1;var dr=Y(new Date(1970,0,1,0,0,0,yr+1).getTime());Date=function(t){var r=function Date(e,n,i,a,f,u,l){var s=arguments.length;var c;if(this instanceof t){var v=u;var h=l;if(dr&&s>=7&&l>yr){var p=Math.floor(l/yr)*yr;var y=Math.floor(p/1e3);v+=y;h-=y*1e3}c=s===1&&o(e)===e?new t(r.parse(e)):s>=7?new t(e,n,i,a,f,v,h):s>=6?new t(e,n,i,a,f,v):s>=5?new t(e,n,i,a,f):s>=4?new t(e,n,i,a):s>=3?new t(e,n,i):s>=2?new t(e,n):s>=1?new t(e instanceof t?+e:e):new t}else{c=t.apply(this,arguments)}if(!J(c)){P(c,{constructor:r},true)}return c};var e=new RegExp(\"^\"+\"(\\\\d{4}|[+-]\\\\d{6})\"+\"(?:-(\\\\d{2})\"+\"(?:-(\\\\d{2})\"+\"(?:\"+\"T(\\\\d{2})\"+\":(\\\\d{2})\"+\"(?:\"+\":(\\\\d{2})\"+\"(?:(\\\\.\\\\d{1,}))?\"+\")?\"+\"(\"+\"Z|\"+\"(?:\"+\"([-+])\"+\"(\\\\d{2})\"+\":(\\\\d{2})\"+\")\"+\")?)?)?)?\"+\"$\");var n=[0,31,59,90,120,151,181,212,243,273,304,334,365];var i=function dayFromMonth(t,r){var e=r>1?1:0;return n[r]+Math.floor((t-1969+e)/4)-Math.floor((t-1901+e)/100)+Math.floor((t-1601+e)/400)+365*(t-1970)};var a=function toUTC(r){var e=0;var n=r;if(dr&&n>yr){var i=Math.floor(n/yr)*yr;var a=Math.floor(i/1e3);e+=a;n-=a*1e3}return u(new t(1970,0,1,0,0,e,n))};for(var f in t){if(G(t,f)){r[f]=t[f]}}P(r,{now:t.now,UTC:t.UTC},true);r.prototype=t.prototype;P(r.prototype,{constructor:r},true);var l=function parse(r){var n=e.exec(r);if(n){var o=u(n[1]),f=u(n[2]||1)-1,l=u(n[3]||1)-1,s=u(n[4]||0),c=u(n[5]||0),v=u(n[6]||0),h=Math.floor(u(n[7]||0)*1e3),p=Boolean(n[4]&&!n[8]),y=n[9]===\"-\"?1:-1,d=u(n[10]||0),g=u(n[11]||0),w;var b=c>0||v>0||h>0;if(s<(b?24:25)&&c<60&&v<60&&h<1e3&&f>-1&&f<12&&d<24&&g<60&&l>-1&&l<i(o,f+1)-i(o,f)){w=((i(o,f)+l)*24+s+d*y)*60;w=((w+c+g*y)*60+v)*1e3+h;if(p){w=a(w)}if(-864e13<=w&&w<=864e13){return w}}return NaN}return t.parse.apply(this,arguments)};P(r,{parse:l});return r}(Date)}if(!Date.now){Date.now=function now(){return(new Date).getTime()}}var gr=l.toFixed&&(8e-5.toFixed(3)!==\"0.000\"||.9.toFixed(0)!==\"1\"||1.255.toFixed(2)!==\"1.25\"||(1000000000000000128).toFixed(0)!==\"1000000000000000128\");var wr={base:1e7,size:6,data:[0,0,0,0,0,0],multiply:function multiply(t,r){var e=-1;var n=r;while(++e<wr.size){n+=t*wr.data[e];wr.data[e]=n%wr.base;n=Math.floor(n/wr.base)}},divide:function divide(t){var r=wr.size;var e=0;while(--r>=0){e+=wr.data[r];wr.data[r]=Math.floor(e/t);e=e%t*wr.base}},numToString:function numToString(){var t=wr.size;var r=\"\";while(--t>=0){if(r!==\"\"||t===0||wr.data[t]!==0){var e=o(wr.data[t]);if(r===\"\"){r=e}else{r+=K(\"0000000\",0,7-e.length)+e}}}return r},pow:function pow(t,r,e){return r===0?e:r%2===1?pow(t,r-1,e*t):pow(t*t,r/2,e)},log:function log(t){var r=0;var e=t;while(e>=4096){r+=12;e/=4096}while(e>=2){r+=1;e/=2}return r}};var br=function toFixed(t){var r,e,n,i,a,f,l,s;r=u(t);r=Y(r)?0:Math.floor(r);if(r<0||r>20){throw new RangeError(\"Number.toFixed called with invalid number of decimals\")}e=u(this);if(Y(e)){return\"NaN\"}if(e<=-1e21||e>=1e21){return o(e)}n=\"\";if(e<0){n=\"-\";e=-e}i=\"0\";if(e>1e-21){a=wr.log(e*wr.pow(2,69,1))-69;f=a<0?e*wr.pow(2,-a,1):e/wr.pow(2,a,1);f*=4503599627370496;a=52-a;if(a>0){wr.multiply(0,f);l=r;while(l>=7){wr.multiply(1e7,0);l-=7}wr.multiply(wr.pow(10,l,1),0);l=a-1;while(l>=23){wr.divide(1<<23);l-=23}wr.divide(1<<l);wr.multiply(1,1);wr.divide(2);i=wr.numToString()}else{wr.multiply(0,f);wr.multiply(1<<-a,0);i=wr.numToString()+K(\"0.00000000000000000000\",2,2+r)}}if(r>0){s=i.length;if(s<=r){i=n+K(\"0.0000000000000000000\",0,r-s+2)+i}else{i=n+K(i,0,s-r)+\".\"+K(i,s-r)}}else{i=n+i}return i};P(l,{toFixed:br},gr);var Tr=function(){try{return 1..toPrecision(undefined)===\"1\"}catch(t){return true}}();var mr=l.toPrecision;P(l,{toPrecision:function toPrecision(t){return typeof t===\"undefined\"?mr.call(this):mr.call(this,t)}},Tr);if(\"ab\".split(/(?:ab)*/).length!==2||\".\".split(/(.?)(.?)/).length!==4||\"tesst\".split(/(s)*/)[1]===\"t\"||\"test\".split(/(?:)/,-1).length!==4||\"\".split(/.?/).length||\".\".split(/()()/).length>1){(function(){var t=typeof/()??/.exec(\"\")[1]===\"undefined\";var r=Math.pow(2,32)-1;f.split=function(e,n){var i=String(this);if(typeof e===\"undefined\"&&n===0){return[]}if(!M(e)){return Q(this,e,n)}var a=[];var o=(e.ignoreCase?\"i\":\"\")+(e.multiline?\"m\":\"\")+(e.unicode?\"u\":\"\")+(e.sticky?\"y\":\"\"),f=0,u,l,s,c;var h=new RegExp(e.source,o+\"g\");if(!t){u=new RegExp(\"^\"+h.source+\"$(?!\\\\s)\",o)}var p=typeof n===\"undefined\"?r:z.ToUint32(n);l=h.exec(i);while(l){s=l.index+l[0].length;if(s>f){_(a,K(i,f,l.index));if(!t&&l.length>1){l[0].replace(u,function(){for(var t=1;t<arguments.length-2;t++){if(typeof arguments[t]===\"undefined\"){l[t]=void 0}}})}if(l.length>1&&l.index<i.length){v.apply(a,W(l,1))}c=l[0].length;f=s;if(a.length>=p){break}}if(h.lastIndex===l.index){h.lastIndex++}l=h.exec(i)}if(f===i.length){if(c||!h.test(\"\")){_(a,\"\")}}else{_(a,K(i,f))}return a.length>p?W(a,0,p):a}})()}else if(\"0\".split(void 0,0).length){f.split=function split(t,r){if(typeof t===\"undefined\"&&r===0){return[]}return Q(this,t,r)}}var Dr=f.replace;var Sr=function(){var t=[];\"x\".replace(/x(.)?/g,function(r,e){_(t,e)});return t.length===1&&typeof t[0]===\"undefined\"}();if(!Sr){f.replace=function replace(t,r){var e=D(r);var n=M(t)&&/\\)[*?]/.test(t.source);if(!e||!n){return Dr.call(this,t,r)}else{var i=function(e){var n=arguments.length;var i=t.lastIndex;t.lastIndex=0;var a=t.exec(e)||[];t.lastIndex=i;_(a,arguments[n-2],arguments[n-1]);return r.apply(this,a)};return Dr.call(this,t,i)}}}var xr=f.substr;var Or=\"\".substr&&\"0b\".substr(-1)!==\"b\";P(f,{substr:function substr(t,r){var e=t;if(t<0){e=w(this.length+t,0)}return xr.call(this,e,r)}},Or);var Er=\"\\t\\n\\x0B\\f\\r \\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\"+\"\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\"+\"\\u2029\\ufeff\";var jr=\"\\u200b\";var Ir=\"[\"+Er+\"]\";var Mr=new RegExp(\"^\"+Ir+Ir+\"*\");var Ur=new RegExp(Ir+Ir+\"*$\");var $r=f.trim&&(Er.trim()||!jr.trim());P(f,{trim:function trim(){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}return o(this).replace(Mr,\"\").replace(Ur,\"\")}},$r);var Fr=d.bind(String.prototype.trim);var Nr=f.lastIndexOf&&\"abc\\u3042\\u3044\".lastIndexOf(\"\\u3042\\u3044\",2)!==-1;P(f,{lastIndexOf:function lastIndexOf(t){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}var r=o(this);var e=o(t);var n=arguments.length>1?u(arguments[1]):NaN;var i=Y(n)?Infinity:z.ToInteger(n);var a=b(w(i,0),r.length);var f=e.length;var l=a+f;while(l>0){l=w(0,l-f);var s=V(K(r,l,a+f),e);if(s!==-1){return l+s}}return-1}},Nr);var Cr=f.lastIndexOf;P(f,{lastIndexOf:function lastIndexOf(t){return Cr.apply(this,arguments)}},f.lastIndexOf.length!==1);if(parseInt(Er+\"08\")!==8||parseInt(Er+\"0x16\")!==22){parseInt=function(t){var r=/^[-+]?0[xX]/;return function parseInt(e,n){if(typeof e===\"symbol\"){\"\"+e}var i=Fr(String(e));var a=u(n)||(r.test(i)?16:10);return t(i,a)}}(parseInt)}if(1/parseFloat(\"-0\")!==-Infinity){parseFloat=function(t){return function parseFloat(r){var e=Fr(String(r));var n=t(e);return n===0&&K(e,0,1)===\"-\"?-0:n}}(parseFloat)}if(String(new RangeError(\"test\"))!==\"RangeError: test\"){var kr=function toString(){if(typeof this===\"undefined\"||this===null){throw new TypeError(\"can't convert \"+this+\" to object\")}var t=this.name;if(typeof t===\"undefined\"){t=\"Error\"}else if(typeof t!==\"string\"){t=o(t)}var r=this.message;if(typeof r===\"undefined\"){r=\"\"}else if(typeof r!==\"string\"){r=o(r)}if(!t){return r}if(!r){return t}return t+\": \"+r};Error.prototype.toString=kr}if(R){var Ar=function(t,r){if(tt(t,r)){var e=Object.getOwnPropertyDescriptor(t,r);if(e.configurable){e.enumerable=false;Object.defineProperty(t,r,e)}}};Ar(Error.prototype,\"message\");if(Error.prototype.message!==\"\"){Error.prototype.message=\"\"}Ar(Error.prototype,\"name\")}if(String(/a/gim)!==\"/a/gim\"){var Rr=function toString(){var t=\"/\"+this.source+\"/\";if(this.global){t+=\"g\"}if(this.ignoreCase){t+=\"i\"}if(this.multiline){t+=\"m\"}return t};RegExp.prototype.toString=Rr}});\n//# sourceMappingURL=es5-shim.map\n/*!\n * https://github.com/paulmillr/es6-shim\n * @license es6-shim Copyright 2013-2016 by Paul Miller (http://paulmillr.com)\n *   and contributors,  MIT License\n * es6-shim: v0.35.4\n * see https://github.com/paulmillr/es6-shim/blob/0.35.4/LICENSE\n * Details and documentation:\n * https://github.com/paulmillr/es6-shim/\n */\n(function(e,t){if(typeof define===\"function\"&&define.amd){define(t)}else if(typeof exports===\"object\"){module.exports=t()}else{e.returnExports=t()}})(this,function(){\"use strict\";var e=Function.call.bind(Function.apply);var t=Function.call.bind(Function.call);var r=Array.isArray;var n=Object.keys;var o=function notThunker(t){return function notThunk(){return!e(t,this,arguments)}};var i=function(e){try{e();return false}catch(t){return true}};var a=function valueOrFalseIfThrows(e){try{return e()}catch(t){return false}};var u=o(i);var f=function(){return!i(function(){return Object.defineProperty({},\"x\",{get:function(){}})})};var s=!!Object.defineProperty&&f();var c=function foo(){}.name===\"foo\";var l=Function.call.bind(Array.prototype.forEach);var p=Function.call.bind(Array.prototype.reduce);var v=Function.call.bind(Array.prototype.filter);var y=Function.call.bind(Array.prototype.some);var h=function(e,t,r,n){if(!n&&t in e){return}if(s){Object.defineProperty(e,t,{configurable:true,enumerable:false,writable:true,value:r})}else{e[t]=r}};var b=function(e,t,r){l(n(t),function(n){var o=t[n];h(e,n,o,!!r)})};var g=Function.call.bind(Object.prototype.toString);var d=typeof/abc/===\"function\"?function IsCallableSlow(e){return typeof e===\"function\"&&g(e)===\"[object Function]\"}:function IsCallableFast(e){return typeof e===\"function\"};var m={getter:function(e,t,r){if(!s){throw new TypeError(\"getters require true ES5 support\")}Object.defineProperty(e,t,{configurable:true,enumerable:false,get:r})},proxy:function(e,t,r){if(!s){throw new TypeError(\"getters require true ES5 support\")}var n=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,{configurable:n.configurable,enumerable:n.enumerable,get:function getKey(){return e[t]},set:function setKey(r){e[t]=r}})},redefine:function(e,t,r){if(s){var n=Object.getOwnPropertyDescriptor(e,t);n.value=r;Object.defineProperty(e,t,n)}else{e[t]=r}},defineByDescriptor:function(e,t,r){if(s){Object.defineProperty(e,t,r)}else if(\"value\"in r){e[t]=r.value}},preserveToString:function(e,t){if(t&&d(t.toString)){h(e,\"toString\",t.toString.bind(t),true)}}};var O=Object.create||function(e,t){var r=function Prototype(){};r.prototype=e;var o=new r;if(typeof t!==\"undefined\"){n(t).forEach(function(e){m.defineByDescriptor(o,e,t[e])})}return o};var w=function(e,t){if(!Object.setPrototypeOf){return false}return a(function(){var r=function Subclass(t){var r=new e(t);Object.setPrototypeOf(r,Subclass.prototype);return r};Object.setPrototypeOf(r,e);r.prototype=O(e.prototype,{constructor:{value:r}});return t(r)})};var j=function(){if(typeof self!==\"undefined\"){return self}if(typeof window!==\"undefined\"){return window}if(typeof global!==\"undefined\"){return global}throw new Error(\"unable to locate global object\")};var S=j();var T=S.isFinite;var I=Function.call.bind(String.prototype.indexOf);var E=Function.apply.bind(Array.prototype.indexOf);var P=Function.call.bind(Array.prototype.concat);var C=Function.call.bind(String.prototype.slice);var M=Function.call.bind(Array.prototype.push);var x=Function.apply.bind(Array.prototype.push);var N=Function.call.bind(Array.prototype.shift);var A=Math.max;var R=Math.min;var _=Math.floor;var k=Math.abs;var L=Math.exp;var F=Math.log;var D=Math.sqrt;var z=Function.call.bind(Object.prototype.hasOwnProperty);var q;var W=function(){};var G=S.Map;var H=G&&G.prototype[\"delete\"];var V=G&&G.prototype.get;var B=G&&G.prototype.has;var U=G&&G.prototype.set;var $=S.Symbol||{};var J=$.species||\"@@species\";var X=Number.isNaN||function isNaN(e){return e!==e};var K=Number.isFinite||function isFinite(e){return typeof e===\"number\"&&T(e)};var Z=d(Math.sign)?Math.sign:function sign(e){var t=Number(e);if(t===0){return t}if(X(t)){return t}return t<0?-1:1};var Y=function log1p(e){var t=Number(e);if(t<-1||X(t)){return NaN}if(t===0||t===Infinity){return t}if(t===-1){return-Infinity}return 1+t-1===0?t:t*(F(1+t)/(1+t-1))};var Q=function isArguments(e){return g(e)===\"[object Arguments]\"};var ee=function isArguments(e){return e!==null&&typeof e===\"object\"&&typeof e.length===\"number\"&&e.length>=0&&g(e)!==\"[object Array]\"&&g(e.callee)===\"[object Function]\"};var te=Q(arguments)?Q:ee;var re={primitive:function(e){return e===null||typeof e!==\"function\"&&typeof e!==\"object\"},string:function(e){return g(e)===\"[object String]\"},regex:function(e){return g(e)===\"[object RegExp]\"},symbol:function(e){return typeof S.Symbol===\"function\"&&typeof e===\"symbol\"}};var ne=function overrideNative(e,t,r){var n=e[t];h(e,t,r,true);m.preserveToString(e[t],n)};var oe=typeof $===\"function\"&&typeof $[\"for\"]===\"function\"&&re.symbol($());var ie=re.symbol($.iterator)?$.iterator:\"_es6-shim iterator_\";if(S.Set&&typeof(new S.Set)[\"@@iterator\"]===\"function\"){ie=\"@@iterator\"}if(!S.Reflect){h(S,\"Reflect\",{},true)}var ae=S.Reflect;var ue=String;var fe=typeof document===\"undefined\"||!document?null:document.all;var se=fe==null?function isNullOrUndefined(e){return e==null}:function isNullOrUndefinedAndNotDocumentAll(e){return e==null&&e!==fe};var ce={Call:function Call(t,r){var n=arguments.length>2?arguments[2]:[];if(!ce.IsCallable(t)){throw new TypeError(t+\" is not a function\")}return e(t,r,n)},RequireObjectCoercible:function(e,t){if(se(e)){throw new TypeError(t||\"Cannot call method on \"+e)}return e},TypeIsObject:function(e){if(e===void 0||e===null||e===true||e===false){return false}return typeof e===\"function\"||typeof e===\"object\"||e===fe},ToObject:function(e,t){return Object(ce.RequireObjectCoercible(e,t))},IsCallable:d,IsConstructor:function(e){return ce.IsCallable(e)},ToInt32:function(e){return ce.ToNumber(e)>>0},ToUint32:function(e){return ce.ToNumber(e)>>>0},ToNumber:function(e){if(g(e)===\"[object Symbol]\"){throw new TypeError(\"Cannot convert a Symbol value to a number\")}return+e},ToInteger:function(e){var t=ce.ToNumber(e);if(X(t)){return 0}if(t===0||!K(t)){return t}return(t>0?1:-1)*_(k(t))},ToLength:function(e){var t=ce.ToInteger(e);if(t<=0){return 0}if(t>Number.MAX_SAFE_INTEGER){return Number.MAX_SAFE_INTEGER}return t},SameValue:function(e,t){if(e===t){if(e===0){return 1/e===1/t}return true}return X(e)&&X(t)},SameValueZero:function(e,t){return e===t||X(e)&&X(t)},IsIterable:function(e){return ce.TypeIsObject(e)&&(typeof e[ie]!==\"undefined\"||te(e))},GetIterator:function(e){if(te(e)){return new q(e,\"value\")}var t=ce.GetMethod(e,ie);if(!ce.IsCallable(t)){throw new TypeError(\"value is not an iterable\")}var r=ce.Call(t,e);if(!ce.TypeIsObject(r)){throw new TypeError(\"bad iterator\")}return r},GetMethod:function(e,t){var r=ce.ToObject(e)[t];if(se(r)){return void 0}if(!ce.IsCallable(r)){throw new TypeError(\"Method not callable: \"+t)}return r},IteratorComplete:function(e){return!!e.done},IteratorClose:function(e,t){var r=ce.GetMethod(e,\"return\");if(r===void 0){return}var n,o;try{n=ce.Call(r,e)}catch(i){o=i}if(t){return}if(o){throw o}if(!ce.TypeIsObject(n)){throw new TypeError(\"Iterator's return method returned a non-object.\")}},IteratorNext:function(e){var t=arguments.length>1?e.next(arguments[1]):e.next();if(!ce.TypeIsObject(t)){throw new TypeError(\"bad iterator\")}return t},IteratorStep:function(e){var t=ce.IteratorNext(e);var r=ce.IteratorComplete(t);return r?false:t},Construct:function(e,t,r,n){var o=typeof r===\"undefined\"?e:r;if(!n&&ae.construct){return ae.construct(e,t,o)}var i=o.prototype;if(!ce.TypeIsObject(i)){i=Object.prototype}var a=O(i);var u=ce.Call(e,a,t);return ce.TypeIsObject(u)?u:a},SpeciesConstructor:function(e,t){var r=e.constructor;if(r===void 0){return t}if(!ce.TypeIsObject(r)){throw new TypeError(\"Bad constructor\")}var n=r[J];if(se(n)){return t}if(!ce.IsConstructor(n)){throw new TypeError(\"Bad @@species\")}return n},CreateHTML:function(e,t,r,n){var o=ce.ToString(e);var i=\"<\"+t;if(r!==\"\"){var a=ce.ToString(n);var u=a.replace(/\"/g,\"&quot;\");i+=\" \"+r+'=\"'+u+'\"'}var f=i+\">\";var s=f+o;return s+\"</\"+t+\">\"},IsRegExp:function IsRegExp(e){if(!ce.TypeIsObject(e)){return false}var t=e[$.match];if(typeof t!==\"undefined\"){return!!t}return re.regex(e)},ToString:function ToString(e){return ue(e)}};if(s&&oe){var le=function defineWellKnownSymbol(e){if(re.symbol($[e])){return $[e]}var t=$[\"for\"](\"Symbol.\"+e);Object.defineProperty($,e,{configurable:false,enumerable:false,writable:false,value:t});return t};if(!re.symbol($.search)){var pe=le(\"search\");var ve=String.prototype.search;h(RegExp.prototype,pe,function search(e){return ce.Call(ve,e,[this])});var ye=function search(e){var t=ce.RequireObjectCoercible(this);if(!se(e)){var r=ce.GetMethod(e,pe);if(typeof r!==\"undefined\"){return ce.Call(r,e,[t])}}return ce.Call(ve,t,[ce.ToString(e)])};ne(String.prototype,\"search\",ye)}if(!re.symbol($.replace)){var he=le(\"replace\");var be=String.prototype.replace;h(RegExp.prototype,he,function replace(e,t){return ce.Call(be,e,[this,t])});var ge=function replace(e,t){var r=ce.RequireObjectCoercible(this);if(!se(e)){var n=ce.GetMethod(e,he);if(typeof n!==\"undefined\"){return ce.Call(n,e,[r,t])}}return ce.Call(be,r,[ce.ToString(e),t])};ne(String.prototype,\"replace\",ge)}if(!re.symbol($.split)){var de=le(\"split\");var me=String.prototype.split;h(RegExp.prototype,de,function split(e,t){return ce.Call(me,e,[this,t])});var Oe=function split(e,t){var r=ce.RequireObjectCoercible(this);if(!se(e)){var n=ce.GetMethod(e,de);if(typeof n!==\"undefined\"){return ce.Call(n,e,[r,t])}}return ce.Call(me,r,[ce.ToString(e),t])};ne(String.prototype,\"split\",Oe)}var we=re.symbol($.match);var je=we&&function(){var e={};e[$.match]=function(){return 42};return\"a\".match(e)!==42}();if(!we||je){var Se=le(\"match\");var Te=String.prototype.match;h(RegExp.prototype,Se,function match(e){return ce.Call(Te,e,[this])});var Ie=function match(e){var t=ce.RequireObjectCoercible(this);if(!se(e)){var r=ce.GetMethod(e,Se);if(typeof r!==\"undefined\"){return ce.Call(r,e,[t])}}return ce.Call(Te,t,[ce.ToString(e)])};ne(String.prototype,\"match\",Ie)}}var Ee=function wrapConstructor(e,t,r){m.preserveToString(t,e);if(Object.setPrototypeOf){Object.setPrototypeOf(e,t)}if(s){l(Object.getOwnPropertyNames(e),function(n){if(n in W||r[n]){return}m.proxy(e,n,t)})}else{l(Object.keys(e),function(n){if(n in W||r[n]){return}t[n]=e[n]})}t.prototype=e.prototype;m.redefine(e.prototype,\"constructor\",t)};var Pe=function(){return this};var Ce=function(e){if(s&&!z(e,J)){m.getter(e,J,Pe)}};var Me=function(e,t){var r=t||function iterator(){return this};h(e,ie,r);if(!e[ie]&&re.symbol(ie)){e[ie]=r}};var xe=function createDataProperty(e,t,r){if(s){Object.defineProperty(e,t,{configurable:true,enumerable:true,writable:true,value:r})}else{e[t]=r}};var Ne=function createDataPropertyOrThrow(e,t,r){xe(e,t,r);if(!ce.SameValue(e[t],r)){throw new TypeError(\"property is nonconfigurable\")}};var Ae=function(e,t,r,n){if(!ce.TypeIsObject(e)){throw new TypeError(\"Constructor requires `new`: \"+t.name)}var o=t.prototype;if(!ce.TypeIsObject(o)){o=r}var i=O(o);for(var a in n){if(z(n,a)){var u=n[a];h(i,a,u,true)}}return i};if(String.fromCodePoint&&String.fromCodePoint.length!==1){var Re=String.fromCodePoint;ne(String,\"fromCodePoint\",function fromCodePoint(e){return ce.Call(Re,this,arguments)})}var _e={fromCodePoint:function fromCodePoint(e){var t=[];var r;for(var n=0,o=arguments.length;n<o;n++){r=Number(arguments[n]);if(!ce.SameValue(r,ce.ToInteger(r))||r<0||r>1114111){throw new RangeError(\"Invalid code point \"+r)}if(r<65536){M(t,String.fromCharCode(r))}else{r-=65536;M(t,String.fromCharCode((r>>10)+55296));M(t,String.fromCharCode(r%1024+56320))}}return t.join(\"\")},raw:function raw(e){var t=ce.ToObject(e,\"bad callSite\");var r=ce.ToObject(t.raw,\"bad raw value\");var n=r.length;var o=ce.ToLength(n);if(o<=0){return\"\"}var i=[];var a=0;var u,f,s,c;while(a<o){u=ce.ToString(a);s=ce.ToString(r[u]);M(i,s);if(a+1>=o){break}f=a+1<arguments.length?arguments[a+1]:\"\";c=ce.ToString(f);M(i,c);a+=1}return i.join(\"\")}};if(String.raw&&String.raw({raw:{0:\"x\",1:\"y\",length:2}})!==\"xy\"){ne(String,\"raw\",_e.raw)}b(String,_e);var ke=function repeat(e,t){if(t<1){return\"\"}if(t%2){return repeat(e,t-1)+e}var r=repeat(e,t/2);return r+r};var Le=Infinity;var Fe={repeat:function repeat(e){var t=ce.ToString(ce.RequireObjectCoercible(this));var r=ce.ToInteger(e);if(r<0||r>=Le){throw new RangeError(\"repeat count must be less than infinity and not overflow maximum string size\")}return ke(t,r)},startsWith:function startsWith(e){var t=ce.ToString(ce.RequireObjectCoercible(this));if(ce.IsRegExp(e)){throw new TypeError('Cannot call method \"startsWith\" with a regex')}var r=ce.ToString(e);var n;if(arguments.length>1){n=arguments[1]}var o=A(ce.ToInteger(n),0);return C(t,o,o+r.length)===r},endsWith:function endsWith(e){var t=ce.ToString(ce.RequireObjectCoercible(this));if(ce.IsRegExp(e)){throw new TypeError('Cannot call method \"endsWith\" with a regex')}var r=ce.ToString(e);var n=t.length;var o;if(arguments.length>1){o=arguments[1]}var i=typeof o===\"undefined\"?n:ce.ToInteger(o);var a=R(A(i,0),n);return C(t,a-r.length,a)===r},includes:function includes(e){if(ce.IsRegExp(e)){throw new TypeError('\"includes\" does not accept a RegExp')}var t=ce.ToString(e);var r;if(arguments.length>1){r=arguments[1]}return I(this,t,r)!==-1},codePointAt:function codePointAt(e){var t=ce.ToString(ce.RequireObjectCoercible(this));var r=ce.ToInteger(e);var n=t.length;if(r>=0&&r<n){var o=t.charCodeAt(r);var i=r+1===n;if(o<55296||o>56319||i){return o}var a=t.charCodeAt(r+1);if(a<56320||a>57343){return o}return(o-55296)*1024+(a-56320)+65536}}};if(String.prototype.includes&&\"a\".includes(\"a\",Infinity)!==false){ne(String.prototype,\"includes\",Fe.includes)}if(String.prototype.startsWith&&String.prototype.endsWith){var De=i(function(){return\"/a/\".startsWith(/a/)});var ze=a(function(){return\"abc\".startsWith(\"a\",Infinity)===false});if(!De||!ze){ne(String.prototype,\"startsWith\",Fe.startsWith);ne(String.prototype,\"endsWith\",Fe.endsWith)}}if(oe){var qe=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".startsWith(e)});if(!qe){ne(String.prototype,\"startsWith\",Fe.startsWith)}var We=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".endsWith(e)});if(!We){ne(String.prototype,\"endsWith\",Fe.endsWith)}var Ge=a(function(){var e=/a/;e[$.match]=false;return\"/a/\".includes(e)});if(!Ge){ne(String.prototype,\"includes\",Fe.includes)}}b(String.prototype,Fe);var He=[\"\\t\\n\\x0B\\f\\r \\xa0\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\",\"\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\u2028\",\"\\u2029\\ufeff\"].join(\"\");var Ve=new RegExp(\"(^[\"+He+\"]+)|([\"+He+\"]+$)\",\"g\");var Be=function trim(){return ce.ToString(ce.RequireObjectCoercible(this)).replace(Ve,\"\")};var Ue=[\"\\x85\",\"\\u200b\",\"\\ufffe\"].join(\"\");var $e=new RegExp(\"[\"+Ue+\"]\",\"g\");var Je=/^[-+]0x[0-9a-f]+$/i;var Xe=Ue.trim().length!==Ue.length;h(String.prototype,\"trim\",Be,Xe);var Ke=function(e){return{value:e,done:arguments.length===0}};var Ze=function(e){ce.RequireObjectCoercible(e);this._s=ce.ToString(e);this._i=0};Ze.prototype.next=function(){var e=this._s;var t=this._i;if(typeof e===\"undefined\"||t>=e.length){this._s=void 0;return Ke()}var r=e.charCodeAt(t);var n,o;if(r<55296||r>56319||t+1===e.length){o=1}else{n=e.charCodeAt(t+1);o=n<56320||n>57343?1:2}this._i=t+o;return Ke(e.substr(t,o))};Me(Ze.prototype);Me(String.prototype,function(){return new Ze(this)});var Ye={from:function from(e){var r=this;var n;if(arguments.length>1){n=arguments[1]}var o,i;if(typeof n===\"undefined\"){o=false}else{if(!ce.IsCallable(n)){throw new TypeError(\"Array.from: when provided, the second argument must be a function\")}if(arguments.length>2){i=arguments[2]}o=true}var a=typeof(te(e)||ce.GetMethod(e,ie))!==\"undefined\";var u,f,s;if(a){f=ce.IsConstructor(r)?Object(new r):[];var c=ce.GetIterator(e);var l,p;s=0;while(true){l=ce.IteratorStep(c);if(l===false){break}p=l.value;try{if(o){p=typeof i===\"undefined\"?n(p,s):t(n,i,p,s)}f[s]=p}catch(v){ce.IteratorClose(c,true);throw v}s+=1}u=s}else{var y=ce.ToObject(e);u=ce.ToLength(y.length);f=ce.IsConstructor(r)?Object(new r(u)):new Array(u);var h;for(s=0;s<u;++s){h=y[s];if(o){h=typeof i===\"undefined\"?n(h,s):t(n,i,h,s)}Ne(f,s,h)}}f.length=u;return f},of:function of(){var e=arguments.length;var t=this;var n=r(t)||!ce.IsCallable(t)?new Array(e):ce.Construct(t,[e]);for(var o=0;o<e;++o){Ne(n,o,arguments[o])}n.length=e;return n}};b(Array,Ye);Ce(Array);q=function(e,t){this.i=0;this.array=e;this.kind=t};b(q.prototype,{next:function(){var e=this.i;var t=this.array;if(!(this instanceof q)){throw new TypeError(\"Not an ArrayIterator\")}if(typeof t!==\"undefined\"){var r=ce.ToLength(t.length);for(;e<r;e++){var n=this.kind;var o;if(n===\"key\"){o=e}else if(n===\"value\"){o=t[e]}else if(n===\"entry\"){o=[e,t[e]]}this.i=e+1;return Ke(o)}}this.array=void 0;return Ke()}});Me(q.prototype);var Qe=Array.of===Ye.of||function(){var e=function Foo(e){this.length=e};e.prototype=[];var t=Array.of.apply(e,[1,2]);return t instanceof e&&t.length===2}();if(!Qe){ne(Array,\"of\",Ye.of)}var et={copyWithin:function copyWithin(e,t){var r=ce.ToObject(this);var n=ce.ToLength(r.length);var o=ce.ToInteger(e);var i=ce.ToInteger(t);var a=o<0?A(n+o,0):R(o,n);var u=i<0?A(n+i,0):R(i,n);var f;if(arguments.length>2){f=arguments[2]}var s=typeof f===\"undefined\"?n:ce.ToInteger(f);var c=s<0?A(n+s,0):R(s,n);var l=R(c-u,n-a);var p=1;if(u<a&&a<u+l){p=-1;u+=l-1;a+=l-1}while(l>0){if(u in r){r[a]=r[u]}else{delete r[a]}u+=p;a+=p;l-=1}return r},fill:function fill(e){var t;if(arguments.length>1){t=arguments[1]}var r;if(arguments.length>2){r=arguments[2]}var n=ce.ToObject(this);var o=ce.ToLength(n.length);t=ce.ToInteger(typeof t===\"undefined\"?0:t);r=ce.ToInteger(typeof r===\"undefined\"?o:r);var i=t<0?A(o+t,0):R(t,o);var a=r<0?o+r:r;for(var u=i;u<o&&u<a;++u){n[u]=e}return n},find:function find(e){var r=ce.ToObject(this);var n=ce.ToLength(r.length);if(!ce.IsCallable(e)){throw new TypeError(\"Array#find: predicate must be a function\")}var o=arguments.length>1?arguments[1]:null;for(var i=0,a;i<n;i++){a=r[i];if(o){if(t(e,o,a,i,r)){return a}}else if(e(a,i,r)){return a}}},findIndex:function findIndex(e){var r=ce.ToObject(this);var n=ce.ToLength(r.length);if(!ce.IsCallable(e)){throw new TypeError(\"Array#findIndex: predicate must be a function\")}var o=arguments.length>1?arguments[1]:null;for(var i=0;i<n;i++){if(o){if(t(e,o,r[i],i,r)){return i}}else if(e(r[i],i,r)){return i}}return-1},keys:function keys(){return new q(this,\"key\")},values:function values(){return new q(this,\"value\")},entries:function entries(){return new q(this,\"entry\")}};if(Array.prototype.keys&&!ce.IsCallable([1].keys().next)){delete Array.prototype.keys}if(Array.prototype.entries&&!ce.IsCallable([1].entries().next)){delete Array.prototype.entries}if(Array.prototype.keys&&Array.prototype.entries&&!Array.prototype.values&&Array.prototype[ie]){b(Array.prototype,{values:Array.prototype[ie]});if(re.symbol($.unscopables)){Array.prototype[$.unscopables].values=true}}if(c&&Array.prototype.values&&Array.prototype.values.name!==\"values\"){var tt=Array.prototype.values;ne(Array.prototype,\"values\",function values(){return ce.Call(tt,this,arguments)});h(Array.prototype,ie,Array.prototype.values,true)}b(Array.prototype,et);if(1/[true].indexOf(true,-0)<0){h(Array.prototype,\"indexOf\",function indexOf(e){var t=E(this,arguments);if(t===0&&1/t<0){return 0}return t},true)}Me(Array.prototype,function(){return this.values()});if(Object.getPrototypeOf){Me(Object.getPrototypeOf([].values()))}var rt=function(){return a(function(){return Array.from({length:-1}).length===0})}();var nt=function(){var e=Array.from([0].entries());return e.length===1&&r(e[0])&&e[0][0]===0&&e[0][1]===0}();if(!rt||!nt){ne(Array,\"from\",Ye.from)}var ot=function(){return a(function(){return Array.from([0],void 0)})}();if(!ot){var it=Array.from;ne(Array,\"from\",function from(e){if(arguments.length>1&&typeof arguments[1]!==\"undefined\"){return ce.Call(it,this,arguments)}else{return t(it,this,e)}})}var at=-(Math.pow(2,32)-1);var ut=function(e,r){var n={length:at};n[r?(n.length>>>0)-1:0]=true;return a(function(){t(e,n,function(){throw new RangeError(\"should not reach here\")},[]);return true})};if(!ut(Array.prototype.forEach)){var ft=Array.prototype.forEach;ne(Array.prototype,\"forEach\",function forEach(e){return ce.Call(ft,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.map)){var st=Array.prototype.map;ne(Array.prototype,\"map\",function map(e){return ce.Call(st,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.filter)){var ct=Array.prototype.filter;ne(Array.prototype,\"filter\",function filter(e){return ce.Call(ct,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.some)){var lt=Array.prototype.some;ne(Array.prototype,\"some\",function some(e){return ce.Call(lt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.every)){var pt=Array.prototype.every;ne(Array.prototype,\"every\",function every(e){return ce.Call(pt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.reduce)){var vt=Array.prototype.reduce;ne(Array.prototype,\"reduce\",function reduce(e){return ce.Call(vt,this.length>=0?this:[],arguments)},true)}if(!ut(Array.prototype.reduceRight,true)){var yt=Array.prototype.reduceRight;ne(Array.prototype,\"reduceRight\",function reduceRight(e){return ce.Call(yt,this.length>=0?this:[],arguments)},true)}var ht=Number(\"0o10\")!==8;var bt=Number(\"0b10\")!==2;var gt=y(Ue,function(e){return Number(e+0+e)===0});if(ht||bt||gt){var dt=Number;var mt=/^0b[01]+$/i;var Ot=/^0o[0-7]+$/i;var wt=mt.test.bind(mt);var jt=Ot.test.bind(Ot);var St=function(e){var t;if(typeof e.valueOf===\"function\"){t=e.valueOf();if(re.primitive(t)){return t}}if(typeof e.toString===\"function\"){t=e.toString();if(re.primitive(t)){return t}}throw new TypeError(\"No default value\")};var Tt=$e.test.bind($e);var It=Je.test.bind(Je);var Et=function(){var e=function Number(t){var r;if(arguments.length>0){r=re.primitive(t)?t:St(t,\"number\")}else{r=0}if(typeof r===\"string\"){r=ce.Call(Be,r);if(wt(r)){r=parseInt(C(r,2),2)}else if(jt(r)){r=parseInt(C(r,2),8)}else if(Tt(r)||It(r)){r=NaN}}var n=this;var o=a(function(){dt.prototype.valueOf.call(n);return true});if(n instanceof e&&!o){return new dt(r)}return dt(r)};return e}();Ee(dt,Et,{});b(Et,{NaN:dt.NaN,MAX_VALUE:dt.MAX_VALUE,MIN_VALUE:dt.MIN_VALUE,NEGATIVE_INFINITY:dt.NEGATIVE_INFINITY,POSITIVE_INFINITY:dt.POSITIVE_INFINITY});Number=Et;m.redefine(S,\"Number\",Et)}var Pt=Math.pow(2,53)-1;b(Number,{MAX_SAFE_INTEGER:Pt,MIN_SAFE_INTEGER:-Pt,EPSILON:2.220446049250313e-16,parseInt:S.parseInt,parseFloat:S.parseFloat,isFinite:K,isInteger:function isInteger(e){return K(e)&&ce.ToInteger(e)===e},isSafeInteger:function isSafeInteger(e){return Number.isInteger(e)&&k(e)<=Number.MAX_SAFE_INTEGER},isNaN:X});h(Number,\"parseInt\",S.parseInt,Number.parseInt!==S.parseInt);if([,1].find(function(){return true})===1){ne(Array.prototype,\"find\",et.find)}if([,1].findIndex(function(){return true})!==0){ne(Array.prototype,\"findIndex\",et.findIndex)}var Ct=Function.bind.call(Function.bind,Object.prototype.propertyIsEnumerable);var Mt=function ensureEnumerable(e,t){if(s&&Ct(e,t)){Object.defineProperty(e,t,{enumerable:false})}};var xt=function sliceArgs(){var e=Number(this);var t=arguments.length;var r=t-e;var n=new Array(r<0?0:r);for(var o=e;o<t;++o){n[o-e]=arguments[o]}return n};var Nt=function assignTo(e){return function assignToSource(t,r){t[r]=e[r];return t}};var At=function(e,t){var r=n(Object(t));var o;if(ce.IsCallable(Object.getOwnPropertySymbols)){o=v(Object.getOwnPropertySymbols(Object(t)),Ct(t))}return p(P(r,o||[]),Nt(t),e)};var Rt={assign:function(e,t){var r=ce.ToObject(e,\"Cannot convert undefined or null to object\");return p(ce.Call(xt,1,arguments),At,r)},is:function is(e,t){return ce.SameValue(e,t)}};var _t=Object.assign&&Object.preventExtensions&&function(){var e=Object.preventExtensions({1:2});try{Object.assign(e,\"xy\")}catch(t){return e[1]===\"y\"}}();if(_t){ne(Object,\"assign\",Rt.assign)}b(Object,Rt);if(s){var kt={setPrototypeOf:function(e,r){var n;var o=function(e,t){if(!ce.TypeIsObject(e)){throw new TypeError(\"cannot set prototype on a non-object\")}if(!(t===null||ce.TypeIsObject(t))){throw new TypeError(\"can only set prototype to an object or null\"+t)}};var i=function(e,r){o(e,r);t(n,e,r);return e};try{n=e.getOwnPropertyDescriptor(e.prototype,r).set;t(n,{},null)}catch(a){if(e.prototype!=={}[r]){return}n=function(e){this[r]=e};i.polyfill=i(i({},null),e.prototype)instanceof e}return i}(Object,\"__proto__\")};b(Object,kt)}if(Object.setPrototypeOf&&Object.getPrototypeOf&&Object.getPrototypeOf(Object.setPrototypeOf({},null))!==null&&Object.getPrototypeOf(Object.create(null))===null){(function(){var e=Object.create(null);var t=Object.getPrototypeOf;var r=Object.setPrototypeOf;Object.getPrototypeOf=function(r){var n=t(r);return n===e?null:n};Object.setPrototypeOf=function(t,n){var o=n===null?e:n;return r(t,o)};Object.setPrototypeOf.polyfill=false})()}var Lt=!i(function(){return Object.keys(\"foo\")});if(!Lt){var Ft=Object.keys;ne(Object,\"keys\",function keys(e){return Ft(ce.ToObject(e))});n=Object.keys}var Dt=i(function(){return Object.keys(/a/g)});if(Dt){var zt=Object.keys;ne(Object,\"keys\",function keys(e){if(re.regex(e)){var t=[];for(var r in e){if(z(e,r)){M(t,r)}}return t}return zt(e)});n=Object.keys}if(Object.getOwnPropertyNames){var qt=!i(function(){return Object.getOwnPropertyNames(\"foo\")});if(!qt){var Wt=typeof window===\"object\"?Object.getOwnPropertyNames(window):[];var Gt=Object.getOwnPropertyNames;ne(Object,\"getOwnPropertyNames\",function getOwnPropertyNames(e){var t=ce.ToObject(e);if(g(t)===\"[object Window]\"){try{return Gt(t)}catch(r){return P([],Wt)}}return Gt(t)})}}if(Object.getOwnPropertyDescriptor){var Ht=!i(function(){return Object.getOwnPropertyDescriptor(\"foo\",\"bar\")});if(!Ht){var Vt=Object.getOwnPropertyDescriptor;ne(Object,\"getOwnPropertyDescriptor\",function getOwnPropertyDescriptor(e,t){return Vt(ce.ToObject(e),t)})}}if(Object.seal){var Bt=!i(function(){return Object.seal(\"foo\")});if(!Bt){var Ut=Object.seal;ne(Object,\"seal\",function seal(e){if(!ce.TypeIsObject(e)){return e}return Ut(e)})}}if(Object.isSealed){var $t=!i(function(){return Object.isSealed(\"foo\")});if(!$t){var Jt=Object.isSealed;ne(Object,\"isSealed\",function isSealed(e){if(!ce.TypeIsObject(e)){return true}return Jt(e)})}}if(Object.freeze){var Xt=!i(function(){return Object.freeze(\"foo\")});if(!Xt){var Kt=Object.freeze;ne(Object,\"freeze\",function freeze(e){if(!ce.TypeIsObject(e)){return e}return Kt(e)})}}if(Object.isFrozen){var Zt=!i(function(){return Object.isFrozen(\"foo\")});if(!Zt){var Yt=Object.isFrozen;ne(Object,\"isFrozen\",function isFrozen(e){if(!ce.TypeIsObject(e)){return true}return Yt(e)})}}if(Object.preventExtensions){var Qt=!i(function(){return Object.preventExtensions(\"foo\")});if(!Qt){var er=Object.preventExtensions;ne(Object,\"preventExtensions\",function preventExtensions(e){if(!ce.TypeIsObject(e)){return e}return er(e)})}}if(Object.isExtensible){var tr=!i(function(){return Object.isExtensible(\"foo\")});if(!tr){var rr=Object.isExtensible;ne(Object,\"isExtensible\",function isExtensible(e){if(!ce.TypeIsObject(e)){return false}return rr(e)})}}if(Object.getPrototypeOf){var nr=!i(function(){return Object.getPrototypeOf(\"foo\")});if(!nr){var or=Object.getPrototypeOf;ne(Object,\"getPrototypeOf\",function getPrototypeOf(e){return or(ce.ToObject(e))})}}var ir=s&&function(){var e=Object.getOwnPropertyDescriptor(RegExp.prototype,\"flags\");return e&&ce.IsCallable(e.get)}();if(s&&!ir){var ar=function flags(){if(!ce.TypeIsObject(this)){throw new TypeError(\"Method called on incompatible type: must be an object.\")}var e=\"\";if(this.global){e+=\"g\"}if(this.ignoreCase){e+=\"i\"}if(this.multiline){e+=\"m\"}if(this.unicode){e+=\"u\"}if(this.sticky){e+=\"y\"}return e};m.getter(RegExp.prototype,\"flags\",ar)}var ur=s&&a(function(){return String(new RegExp(/a/g,\"i\"))===\"/a/i\"});var fr=oe&&s&&function(){var e=/./;e[$.match]=false;return RegExp(e)===e}();var sr=a(function(){return RegExp.prototype.toString.call({source:\"abc\"})===\"/abc/\"});var cr=sr&&a(function(){return RegExp.prototype.toString.call({source:\"a\",flags:\"b\"})===\"/a/b\"});if(!sr||!cr){var lr=RegExp.prototype.toString;h(RegExp.prototype,\"toString\",function toString(){var e=ce.RequireObjectCoercible(this);if(re.regex(e)){return t(lr,e)}var r=ue(e.source);var n=ue(e.flags);return\"/\"+r+\"/\"+n},true);m.preserveToString(RegExp.prototype.toString,lr)}if(s&&(!ur||fr)){var pr=Object.getOwnPropertyDescriptor(RegExp.prototype,\"flags\").get;var vr=Object.getOwnPropertyDescriptor(RegExp.prototype,\"source\")||{};var yr=function(){return this.source};var hr=ce.IsCallable(vr.get)?vr.get:yr;var br=RegExp;var gr=function(){return function RegExp(e,t){var r=ce.IsRegExp(e);var n=this instanceof RegExp;if(!n&&r&&typeof t===\"undefined\"&&e.constructor===RegExp){return e}var o=e;var i=t;if(re.regex(e)){o=ce.Call(hr,e);i=typeof t===\"undefined\"?ce.Call(pr,e):t;return new RegExp(o,i)}else if(r){o=e.source;i=typeof t===\"undefined\"?e.flags:t}return new br(e,t)}}();Ee(br,gr,{$input:true});RegExp=gr;m.redefine(S,\"RegExp\",gr)}if(s){var dr={input:\"$_\",lastMatch:\"$&\",lastParen:\"$+\",leftContext:\"$`\",rightContext:\"$'\"};l(n(dr),function(e){if(e in RegExp&&!(dr[e]in RegExp)){m.getter(RegExp,dr[e],function get(){return RegExp[e]})}})}Ce(RegExp);var mr=1/Number.EPSILON;var Or=function roundTiesToEven(e){return e+mr-mr};var wr=Math.pow(2,-23);var jr=Math.pow(2,127)*(2-wr);var Sr=Math.pow(2,-126);var Tr=Math.E;var Ir=Math.LOG2E;var Er=Math.LOG10E;var Pr=Number.prototype.clz;delete Number.prototype.clz;var Cr={acosh:function acosh(e){var t=Number(e);if(X(t)||e<1){return NaN}if(t===1){return 0}if(t===Infinity){return t}var r=1/(t*t);if(t<2){return Y(t-1+D(1-r)*t)}var n=t/2;return Y(n+D(1-r)*n-1)+1/Ir},asinh:function asinh(e){var t=Number(e);if(t===0||!T(t)){return t}var r=k(t);var n=r*r;var o=Z(t);if(r<1){return o*Y(r+n/(D(n+1)+1))}return o*(Y(r/2+D(1+1/n)*r/2-1)+1/Ir)},atanh:function atanh(e){var t=Number(e);if(t===0){return t}if(t===-1){return-Infinity}if(t===1){return Infinity}if(X(t)||t<-1||t>1){return NaN}var r=k(t);return Z(t)*Y(2*r/(1-r))/2},cbrt:function cbrt(e){var t=Number(e);if(t===0){return t}var r=t<0;var n;if(r){t=-t}if(t===Infinity){n=Infinity}else{n=L(F(t)/3);n=(t/(n*n)+2*n)/3}return r?-n:n},clz32:function clz32(e){var t=Number(e);var r=ce.ToUint32(t);if(r===0){return 32}return Pr?ce.Call(Pr,r):31-_(F(r+.5)*Ir)},cosh:function cosh(e){var t=Number(e);if(t===0){return 1}if(X(t)){return NaN}if(!T(t)){return Infinity}var r=L(k(t)-1);return(r+1/(r*Tr*Tr))*(Tr/2)},expm1:function expm1(e){var t=Number(e);if(t===-Infinity){return-1}if(!T(t)||t===0){return t}if(k(t)>.5){return L(t)-1}var r=t;var n=0;var o=1;while(n+r!==n){n+=r;o+=1;r*=t/o}return n},hypot:function hypot(e,t){var r=0;var n=0;for(var o=0;o<arguments.length;++o){var i=k(Number(arguments[o]));if(n<i){r*=n/i*(n/i);r+=1;n=i}else{r+=i>0?i/n*(i/n):i}}return n===Infinity?Infinity:n*D(r)},log2:function log2(e){return F(e)*Ir},log10:function log10(e){return F(e)*Er},log1p:Y,sign:Z,sinh:function sinh(e){var t=Number(e);if(!T(t)||t===0){return t}var r=k(t);if(r<1){var n=Math.expm1(r);return Z(t)*n*(1+1/(n+1))/2}var o=L(r-1);return Z(t)*(o-1/(o*Tr*Tr))*(Tr/2)},tanh:function tanh(e){var t=Number(e);if(X(t)||t===0){return t}if(t>=20){return 1}if(t<=-20){return-1}return(Math.expm1(t)-Math.expm1(-t))/(L(t)+L(-t))},trunc:function trunc(e){var t=Number(e);return t<0?-_(-t):_(t)},imul:function imul(e,t){var r=ce.ToUint32(e);var n=ce.ToUint32(t);var o=r>>>16&65535;var i=r&65535;var a=n>>>16&65535;var u=n&65535;return i*u+(o*u+i*a<<16>>>0)|0},fround:function fround(e){var t=Number(e);if(t===0||t===Infinity||t===-Infinity||X(t)){return t}var r=Z(t);var n=k(t);if(n<Sr){return r*Or(n/Sr/wr)*Sr*wr}var o=(1+wr/Number.EPSILON)*n;var i=o-(o-n);if(i>jr||X(i)){return r*Infinity}return r*i}};var Mr=function withinULPDistance(e,t,r){return k(1-e/t)/Number.EPSILON<(r||8)};b(Math,Cr);h(Math,\"sinh\",Cr.sinh,Math.sinh(710)===Infinity);h(Math,\"cosh\",Cr.cosh,Math.cosh(710)===Infinity);h(Math,\"log1p\",Cr.log1p,Math.log1p(-1e-17)!==-1e-17);h(Math,\"asinh\",Cr.asinh,Math.asinh(-1e7)!==-Math.asinh(1e7));h(Math,\"asinh\",Cr.asinh,Math.asinh(1e300)===Infinity);h(Math,\"atanh\",Cr.atanh,Math.atanh(1e-300)===0);h(Math,\"tanh\",Cr.tanh,Math.tanh(-2e-17)!==-2e-17);\nh(Math,\"acosh\",Cr.acosh,Math.acosh(Number.MAX_VALUE)===Infinity);h(Math,\"acosh\",Cr.acosh,!Mr(Math.acosh(1+Number.EPSILON),Math.sqrt(2*Number.EPSILON)));h(Math,\"cbrt\",Cr.cbrt,!Mr(Math.cbrt(1e-300),1e-100));h(Math,\"sinh\",Cr.sinh,Math.sinh(-2e-17)!==-2e-17);var xr=Math.expm1(10);h(Math,\"expm1\",Cr.expm1,xr>22025.465794806718||xr<22025.465794806718);var Nr=Math.round;var Ar=Math.round(.5-Number.EPSILON/4)===0&&Math.round(-.5+Number.EPSILON/3.99)===1;var Rr=mr+1;var _r=2*mr-1;var kr=[Rr,_r].every(function(e){return Math.round(e)===e});h(Math,\"round\",function round(e){var t=_(e);var r=t===-1?-0:t+1;return e-t<.5?t:r},!Ar||!kr);m.preserveToString(Math.round,Nr);var Lr=Math.imul;if(Math.imul(4294967295,5)!==-5){Math.imul=Cr.imul;m.preserveToString(Math.imul,Lr)}if(Math.imul.length!==2){ne(Math,\"imul\",function imul(e,t){return ce.Call(Lr,Math,arguments)})}var Fr=function(){var e=S.setTimeout;if(typeof e!==\"function\"&&typeof e!==\"object\"){return}ce.IsPromise=function(e){if(!ce.TypeIsObject(e)){return false}if(typeof e._promise===\"undefined\"){return false}return true};var r=function(e){if(!ce.IsConstructor(e)){throw new TypeError(\"Bad promise constructor\")}var t=this;var r=function(e,r){if(t.resolve!==void 0||t.reject!==void 0){throw new TypeError(\"Bad Promise implementation!\")}t.resolve=e;t.reject=r};t.resolve=void 0;t.reject=void 0;t.promise=new e(r);if(!(ce.IsCallable(t.resolve)&&ce.IsCallable(t.reject))){throw new TypeError(\"Bad promise constructor\")}};var n;if(typeof window!==\"undefined\"&&ce.IsCallable(window.postMessage)){n=function(){var e=[];var t=\"zero-timeout-message\";var r=function(r){M(e,r);window.postMessage(t,\"*\")};var n=function(r){if(r.source===window&&r.data===t){r.stopPropagation();if(e.length===0){return}var n=N(e);n()}};window.addEventListener(\"message\",n,true);return r}}var o=function(){var e=S.Promise;var t=e&&e.resolve&&e.resolve();return t&&function(e){return t.then(e)}};var i=ce.IsCallable(S.setImmediate)?S.setImmediate:typeof process===\"object\"&&process.nextTick?process.nextTick:o()||(ce.IsCallable(n)?n():function(t){e(t,0)});var a=function(e){return e};var u=function(e){throw e};var f=0;var s=1;var c=2;var l=0;var p=1;var v=2;var y={};var h=function(e,t,r){i(function(){g(e,t,r)})};var g=function(e,t,r){var n,o;if(t===y){return e(r)}try{n=e(r);o=t.resolve}catch(i){n=i;o=t.reject}o(n)};var d=function(e,t){var r=e._promise;var n=r.reactionLength;if(n>0){h(r.fulfillReactionHandler0,r.reactionCapability0,t);r.fulfillReactionHandler0=void 0;r.rejectReactions0=void 0;r.reactionCapability0=void 0;if(n>1){for(var o=1,i=0;o<n;o++,i+=3){h(r[i+l],r[i+v],t);e[i+l]=void 0;e[i+p]=void 0;e[i+v]=void 0}}}r.result=t;r.state=s;r.reactionLength=0};var m=function(e,t){var r=e._promise;var n=r.reactionLength;if(n>0){h(r.rejectReactionHandler0,r.reactionCapability0,t);r.fulfillReactionHandler0=void 0;r.rejectReactions0=void 0;r.reactionCapability0=void 0;if(n>1){for(var o=1,i=0;o<n;o++,i+=3){h(r[i+p],r[i+v],t);e[i+l]=void 0;e[i+p]=void 0;e[i+v]=void 0}}}r.result=t;r.state=c;r.reactionLength=0};var O=function(e){var t=false;var r=function(r){var n;if(t){return}t=true;if(r===e){return m(e,new TypeError(\"Self resolution\"))}if(!ce.TypeIsObject(r)){return d(e,r)}try{n=r.then}catch(o){return m(e,o)}if(!ce.IsCallable(n)){return d(e,r)}i(function(){j(e,r,n)})};var n=function(r){if(t){return}t=true;return m(e,r)};return{resolve:r,reject:n}};var w=function(e,r,n,o){if(e===I){t(e,r,n,o,y)}else{t(e,r,n,o)}};var j=function(e,t,r){var n=O(e);var o=n.resolve;var i=n.reject;try{w(r,t,o,i)}catch(a){i(a)}};var T,I;var E=function(){var e=function Promise(t){if(!(this instanceof e)){throw new TypeError('Constructor Promise requires \"new\"')}if(this&&this._promise){throw new TypeError(\"Bad construction\")}if(!ce.IsCallable(t)){throw new TypeError(\"not a valid resolver\")}var r=Ae(this,e,T,{_promise:{result:void 0,state:f,reactionLength:0,fulfillReactionHandler0:void 0,rejectReactionHandler0:void 0,reactionCapability0:void 0}});var n=O(r);var o=n.reject;try{t(n.resolve,o)}catch(i){o(i)}return r};return e}();T=E.prototype;var P=function(e,t,r,n){var o=false;return function(i){if(o){return}o=true;t[e]=i;if(--n.count===0){var a=r.resolve;a(t)}}};var C=function(e,t,r){var n=e.iterator;var o=[];var i={count:1};var a,u;var f=0;while(true){try{a=ce.IteratorStep(n);if(a===false){e.done=true;break}u=a.value}catch(s){e.done=true;throw s}o[f]=void 0;var c=t.resolve(u);var l=P(f,o,r,i);i.count+=1;w(c.then,c,l,r.reject);f+=1}if(--i.count===0){var p=r.resolve;p(o)}return r.promise};var x=function(e,t,r){var n=e.iterator;var o,i,a;while(true){try{o=ce.IteratorStep(n);if(o===false){e.done=true;break}i=o.value}catch(u){e.done=true;throw u}a=t.resolve(i);w(a.then,a,r.resolve,r.reject)}return r.promise};b(E,{all:function all(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Promise is not object\")}var n=new r(t);var o,i;try{o=ce.GetIterator(e);i={iterator:o,done:false};return C(i,t,n)}catch(a){var u=a;if(i&&!i.done){try{ce.IteratorClose(o,true)}catch(f){u=f}}var s=n.reject;s(u);return n.promise}},race:function race(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Promise is not object\")}var n=new r(t);var o,i;try{o=ce.GetIterator(e);i={iterator:o,done:false};return x(i,t,n)}catch(a){var u=a;if(i&&!i.done){try{ce.IteratorClose(o,true)}catch(f){u=f}}var s=n.reject;s(u);return n.promise}},reject:function reject(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Bad promise constructor\")}var n=new r(t);var o=n.reject;o(e);return n.promise},resolve:function resolve(e){var t=this;if(!ce.TypeIsObject(t)){throw new TypeError(\"Bad promise constructor\")}if(ce.IsPromise(e)){var n=e.constructor;if(n===t){return e}}var o=new r(t);var i=o.resolve;i(e);return o.promise}});b(T,{\"catch\":function(e){return this.then(null,e)},then:function then(e,t){var n=this;if(!ce.IsPromise(n)){throw new TypeError(\"not a promise\")}var o=ce.SpeciesConstructor(n,E);var i;var b=arguments.length>2&&arguments[2]===y;if(b&&o===E){i=y}else{i=new r(o)}var g=ce.IsCallable(e)?e:a;var d=ce.IsCallable(t)?t:u;var m=n._promise;var O;if(m.state===f){if(m.reactionLength===0){m.fulfillReactionHandler0=g;m.rejectReactionHandler0=d;m.reactionCapability0=i}else{var w=3*(m.reactionLength-1);m[w+l]=g;m[w+p]=d;m[w+v]=i}m.reactionLength+=1}else if(m.state===s){O=m.result;h(g,i,O)}else if(m.state===c){O=m.result;h(d,i,O)}else{throw new TypeError(\"unexpected Promise state\")}return i.promise}});y=new r(E);I=T.then;return E}();if(S.Promise){delete S.Promise.accept;delete S.Promise.defer;delete S.Promise.prototype.chain}if(typeof Fr===\"function\"){b(S,{Promise:Fr});var Dr=w(S.Promise,function(e){return e.resolve(42).then(function(){})instanceof e});var zr=!i(function(){return S.Promise.reject(42).then(null,5).then(null,W)});var qr=i(function(){return S.Promise.call(3,W)});var Wr=function(e){var t=e.resolve(5);t.constructor={};var r=e.resolve(t);try{r.then(null,W).then(null,W)}catch(n){return true}return t===r}(S.Promise);var Gr=s&&function(){var e=0;var t=Object.defineProperty({},\"then\",{get:function(){e+=1}});Promise.resolve(t);return e===1}();var Hr=function BadResolverPromise(e){var t=new Promise(e);e(3,function(){});this.then=t.then;this.constructor=BadResolverPromise};Hr.prototype=Promise.prototype;Hr.all=Promise.all;var Vr=a(function(){return!!Hr.all([1,2])});if(!Dr||!zr||!qr||Wr||!Gr||Vr){Promise=Fr;ne(S,\"Promise\",Fr)}if(Promise.all.length!==1){var Br=Promise.all;ne(Promise,\"all\",function all(e){return ce.Call(Br,this,arguments)})}if(Promise.race.length!==1){var Ur=Promise.race;ne(Promise,\"race\",function race(e){return ce.Call(Ur,this,arguments)})}if(Promise.resolve.length!==1){var $r=Promise.resolve;ne(Promise,\"resolve\",function resolve(e){return ce.Call($r,this,arguments)})}if(Promise.reject.length!==1){var Jr=Promise.reject;ne(Promise,\"reject\",function reject(e){return ce.Call(Jr,this,arguments)})}Mt(Promise,\"all\");Mt(Promise,\"race\");Mt(Promise,\"resolve\");Mt(Promise,\"reject\");Ce(Promise)}var Xr=function(e){var t=n(p(e,function(e,t){e[t]=true;return e},{}));return e.join(\":\")===t.join(\":\")};var Kr=Xr([\"z\",\"a\",\"bb\"]);var Zr=Xr([\"z\",1,\"a\",\"3\",2]);if(s){var Yr=function fastkey(e,t){if(!t&&!Kr){return null}if(se(e)){return\"^\"+ce.ToString(e)}else if(typeof e===\"string\"){return\"$\"+e}else if(typeof e===\"number\"){if(!Zr){return\"n\"+e}return e}else if(typeof e===\"boolean\"){return\"b\"+e}return null};var Qr=function emptyObject(){return Object.create?Object.create(null):{}};var en=function addIterableToMap(e,n,o){if(r(o)||re.string(o)){l(o,function(e){if(!ce.TypeIsObject(e)){throw new TypeError(\"Iterator value \"+e+\" is not an entry object\")}n.set(e[0],e[1])})}else if(o instanceof e){t(e.prototype.forEach,o,function(e,t){n.set(t,e)})}else{var i,a;if(!se(o)){a=n.set;if(!ce.IsCallable(a)){throw new TypeError(\"bad map\")}i=ce.GetIterator(o)}if(typeof i!==\"undefined\"){while(true){var u=ce.IteratorStep(i);if(u===false){break}var f=u.value;try{if(!ce.TypeIsObject(f)){throw new TypeError(\"Iterator value \"+f+\" is not an entry object\")}t(a,n,f[0],f[1])}catch(s){ce.IteratorClose(i,true);throw s}}}}};var tn=function addIterableToSet(e,n,o){if(r(o)||re.string(o)){l(o,function(e){n.add(e)})}else if(o instanceof e){t(e.prototype.forEach,o,function(e){n.add(e)})}else{var i,a;if(!se(o)){a=n.add;if(!ce.IsCallable(a)){throw new TypeError(\"bad set\")}i=ce.GetIterator(o)}if(typeof i!==\"undefined\"){while(true){var u=ce.IteratorStep(i);if(u===false){break}var f=u.value;try{t(a,n,f)}catch(s){ce.IteratorClose(i,true);throw s}}}}};var rn={Map:function(){var e={};var r=function MapEntry(e,t){this.key=e;this.value=t;this.next=null;this.prev=null};r.prototype.isRemoved=function isRemoved(){return this.key===e};var n=function isMap(e){return!!e._es6map};var o=function requireMapSlot(e,t){if(!ce.TypeIsObject(e)||!n(e)){throw new TypeError(\"Method Map.prototype.\"+t+\" called on incompatible receiver \"+ce.ToString(e))}};var i=function MapIterator(e,t){o(e,\"[[MapIterator]]\");this.head=e._head;this.i=this.head;this.kind=t};i.prototype={isMapIterator:true,next:function next(){if(!this.isMapIterator){throw new TypeError(\"Not a MapIterator\")}var e=this.i;var t=this.kind;var r=this.head;if(typeof this.i===\"undefined\"){return Ke()}while(e.isRemoved()&&e!==r){e=e.prev}var n;while(e.next!==r){e=e.next;if(!e.isRemoved()){if(t===\"key\"){n=e.key}else if(t===\"value\"){n=e.value}else{n=[e.key,e.value]}this.i=e;return Ke(n)}}this.i=void 0;return Ke()}};Me(i.prototype);var a;var u=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}if(this&&this._es6map){throw new TypeError(\"Bad construction\")}var e=Ae(this,Map,a,{_es6map:true,_head:null,_map:G?new G:null,_size:0,_storage:Qr()});var t=new r(null,null);t.next=t.prev=t;e._head=t;if(arguments.length>0){en(Map,e,arguments[0])}return e};a=u.prototype;m.getter(a,\"size\",function(){if(typeof this._size===\"undefined\"){throw new TypeError(\"size method called on incompatible Map\")}return this._size});b(a,{get:function get(e){o(this,\"get\");var t;var r=Yr(e,true);if(r!==null){t=this._storage[r];if(t){return t.value}else{return}}if(this._map){t=V.call(this._map,e);if(t){return t.value}else{return}}var n=this._head;var i=n;while((i=i.next)!==n){if(ce.SameValueZero(i.key,e)){return i.value}}},has:function has(e){o(this,\"has\");var t=Yr(e,true);if(t!==null){return typeof this._storage[t]!==\"undefined\"}if(this._map){return B.call(this._map,e)}var r=this._head;var n=r;while((n=n.next)!==r){if(ce.SameValueZero(n.key,e)){return true}}return false},set:function set(e,t){o(this,\"set\");var n=this._head;var i=n;var a;var u=Yr(e,true);if(u!==null){if(typeof this._storage[u]!==\"undefined\"){this._storage[u].value=t;return this}else{a=this._storage[u]=new r(e,t);i=n.prev}}else if(this._map){if(B.call(this._map,e)){V.call(this._map,e).value=t}else{a=new r(e,t);U.call(this._map,e,a);i=n.prev}}while((i=i.next)!==n){if(ce.SameValueZero(i.key,e)){i.value=t;return this}}a=a||new r(e,t);if(ce.SameValue(-0,e)){a.key=+0}a.next=this._head;a.prev=this._head.prev;a.prev.next=a;a.next.prev=a;this._size+=1;return this},\"delete\":function(t){o(this,\"delete\");var r=this._head;var n=r;var i=Yr(t,true);if(i!==null){if(typeof this._storage[i]===\"undefined\"){return false}n=this._storage[i].prev;delete this._storage[i]}else if(this._map){if(!B.call(this._map,t)){return false}n=V.call(this._map,t).prev;H.call(this._map,t)}while((n=n.next)!==r){if(ce.SameValueZero(n.key,t)){n.key=e;n.value=e;n.prev.next=n.next;n.next.prev=n.prev;this._size-=1;return true}}return false},clear:function clear(){o(this,\"clear\");this._map=G?new G:null;this._size=0;this._storage=Qr();var t=this._head;var r=t;var n=r.next;while((r=n)!==t){r.key=e;r.value=e;n=r.next;r.next=r.prev=t}t.next=t.prev=t},keys:function keys(){o(this,\"keys\");return new i(this,\"key\")},values:function values(){o(this,\"values\");return new i(this,\"value\")},entries:function entries(){o(this,\"entries\");return new i(this,\"key+value\")},forEach:function forEach(e){o(this,\"forEach\");var r=arguments.length>1?arguments[1]:null;var n=this.entries();for(var i=n.next();!i.done;i=n.next()){if(r){t(e,r,i.value[1],i.value[0],this)}else{e(i.value[1],i.value[0],this)}}}});Me(a,a.entries);return u}(),Set:function(){var e=function isSet(e){return e._es6set&&typeof e._storage!==\"undefined\"};var r=function requireSetSlot(t,r){if(!ce.TypeIsObject(t)||!e(t)){throw new TypeError(\"Set.prototype.\"+r+\" called on incompatible receiver \"+ce.ToString(t))}};var o;var i=function Set(){if(!(this instanceof Set)){throw new TypeError('Constructor Set requires \"new\"')}if(this&&this._es6set){throw new TypeError(\"Bad construction\")}var e=Ae(this,Set,o,{_es6set:true,\"[[SetData]]\":null,_storage:Qr()});if(!e._es6set){throw new TypeError(\"bad set\")}if(arguments.length>0){tn(Set,e,arguments[0])}return e};o=i.prototype;var a=function(e){var t=e;if(t===\"^null\"){return null}else if(t===\"^undefined\"){return void 0}else{var r=t.charAt(0);if(r===\"$\"){return C(t,1)}else if(r===\"n\"){return+C(t,1)}else if(r===\"b\"){return t===\"btrue\"}}return+t};var u=function ensureMap(e){if(!e[\"[[SetData]]\"]){var t=new rn.Map;e[\"[[SetData]]\"]=t;l(n(e._storage),function(e){var r=a(e);t.set(r,r)});e[\"[[SetData]]\"]=t}e._storage=null};m.getter(i.prototype,\"size\",function(){r(this,\"size\");if(this._storage){return n(this._storage).length}u(this);return this[\"[[SetData]]\"].size});b(i.prototype,{has:function has(e){r(this,\"has\");var t;if(this._storage&&(t=Yr(e))!==null){return!!this._storage[t]}u(this);return this[\"[[SetData]]\"].has(e)},add:function add(e){r(this,\"add\");var t;if(this._storage&&(t=Yr(e))!==null){this._storage[t]=true;return this}u(this);this[\"[[SetData]]\"].set(e,e);return this},\"delete\":function(e){r(this,\"delete\");var t;if(this._storage&&(t=Yr(e))!==null){var n=z(this._storage,t);return delete this._storage[t]&&n}u(this);return this[\"[[SetData]]\"][\"delete\"](e)},clear:function clear(){r(this,\"clear\");if(this._storage){this._storage=Qr()}if(this[\"[[SetData]]\"]){this[\"[[SetData]]\"].clear()}},values:function values(){r(this,\"values\");u(this);return new f(this[\"[[SetData]]\"].values())},entries:function entries(){r(this,\"entries\");u(this);return new f(this[\"[[SetData]]\"].entries())},forEach:function forEach(e){r(this,\"forEach\");var n=arguments.length>1?arguments[1]:null;var o=this;u(o);this[\"[[SetData]]\"].forEach(function(r,i){if(n){t(e,n,i,i,o)}else{e(i,i,o)}})}});h(i.prototype,\"keys\",i.prototype.values,true);Me(i.prototype,i.prototype.values);var f=function SetIterator(e){this.it=e};f.prototype={isSetIterator:true,next:function next(){if(!this.isSetIterator){throw new TypeError(\"Not a SetIterator\")}return this.it.next()}};Me(f.prototype);return i}()};var nn=S.Set&&!Set.prototype[\"delete\"]&&Set.prototype.remove&&Set.prototype.items&&Set.prototype.map&&Array.isArray((new Set).keys);if(nn){S.Set=rn.Set}if(S.Map||S.Set){var on=a(function(){return new Map([[1,2]]).get(1)===2});if(!on){S.Map=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}var e=new G;if(arguments.length>0){en(Map,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,S.Map.prototype);return e};S.Map.prototype=O(G.prototype);h(S.Map.prototype,\"constructor\",S.Map,true);m.preserveToString(S.Map,G)}var an=new Map;var un=function(){var e=new Map([[1,0],[2,0],[3,0],[4,0]]);e.set(-0,e);return e.get(0)===e&&e.get(-0)===e&&e.has(0)&&e.has(-0)}();var fn=an.set(1,2)===an;if(!un||!fn){ne(Map.prototype,\"set\",function set(e,r){t(U,this,e===0?0:e,r);return this})}if(!un){b(Map.prototype,{get:function get(e){return t(V,this,e===0?0:e)},has:function has(e){return t(B,this,e===0?0:e)}},true);m.preserveToString(Map.prototype.get,V);m.preserveToString(Map.prototype.has,B)}var sn=new Set;var cn=Set.prototype[\"delete\"]&&Set.prototype.add&&Set.prototype.has&&function(e){e[\"delete\"](0);e.add(-0);return!e.has(0)}(sn);var ln=sn.add(1)===sn;if(!cn||!ln){var pn=Set.prototype.add;Set.prototype.add=function add(e){t(pn,this,e===0?0:e);return this};m.preserveToString(Set.prototype.add,pn)}if(!cn){var vn=Set.prototype.has;Set.prototype.has=function has(e){return t(vn,this,e===0?0:e)};m.preserveToString(Set.prototype.has,vn);var yn=Set.prototype[\"delete\"];Set.prototype[\"delete\"]=function SetDelete(e){return t(yn,this,e===0?0:e)};m.preserveToString(Set.prototype[\"delete\"],yn)}var hn=w(S.Map,function(e){var t=new e([]);t.set(42,42);return t instanceof e});var bn=Object.setPrototypeOf&&!hn;var gn=function(){try{return!(S.Map()instanceof S.Map)}catch(e){return e instanceof TypeError}}();if(S.Map.length!==0||bn||!gn){S.Map=function Map(){if(!(this instanceof Map)){throw new TypeError('Constructor Map requires \"new\"')}var e=new G;if(arguments.length>0){en(Map,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,Map.prototype);return e};S.Map.prototype=G.prototype;h(S.Map.prototype,\"constructor\",S.Map,true);m.preserveToString(S.Map,G)}var dn=w(S.Set,function(e){var t=new e([]);t.add(42,42);return t instanceof e});var mn=Object.setPrototypeOf&&!dn;var On=function(){try{return!(S.Set()instanceof S.Set)}catch(e){return e instanceof TypeError}}();if(S.Set.length!==0||mn||!On){var wn=S.Set;S.Set=function Set(){if(!(this instanceof Set)){throw new TypeError('Constructor Set requires \"new\"')}var e=new wn;if(arguments.length>0){tn(Set,e,arguments[0])}delete e.constructor;Object.setPrototypeOf(e,Set.prototype);return e};S.Set.prototype=wn.prototype;h(S.Set.prototype,\"constructor\",S.Set,true);m.preserveToString(S.Set,wn)}var jn=new S.Map;var Sn=!a(function(){return jn.keys().next().done});if(typeof S.Map.prototype.clear!==\"function\"||(new S.Set).size!==0||jn.size!==0||typeof S.Map.prototype.keys!==\"function\"||typeof S.Set.prototype.keys!==\"function\"||typeof S.Map.prototype.forEach!==\"function\"||typeof S.Set.prototype.forEach!==\"function\"||u(S.Map)||u(S.Set)||typeof jn.keys().next!==\"function\"||Sn||!hn){b(S,{Map:rn.Map,Set:rn.Set},true)}if(S.Set.prototype.keys!==S.Set.prototype.values){h(S.Set.prototype,\"keys\",S.Set.prototype.values,true)}Me(Object.getPrototypeOf((new S.Map).keys()));Me(Object.getPrototypeOf((new S.Set).keys()));if(c&&S.Set.prototype.has.name!==\"has\"){var Tn=S.Set.prototype.has;ne(S.Set.prototype,\"has\",function has(e){return t(Tn,this,e)})}}b(S,rn);Ce(S.Map);Ce(S.Set)}var In=function throwUnlessTargetIsObject(e){if(!ce.TypeIsObject(e)){throw new TypeError(\"target must be an object\")}};var En={apply:function apply(){return ce.Call(ce.Call,null,arguments)},construct:function construct(e,t){if(!ce.IsConstructor(e)){throw new TypeError(\"First argument must be a constructor.\")}var r=arguments.length>2?arguments[2]:e;if(!ce.IsConstructor(r)){throw new TypeError(\"new.target must be a constructor.\")}return ce.Construct(e,t,r,\"internal\")},deleteProperty:function deleteProperty(e,t){In(e);if(s){var r=Object.getOwnPropertyDescriptor(e,t);if(r&&!r.configurable){return false}}return delete e[t]},has:function has(e,t){In(e);return t in e}};if(Object.getOwnPropertyNames){Object.assign(En,{ownKeys:function ownKeys(e){In(e);var t=Object.getOwnPropertyNames(e);if(ce.IsCallable(Object.getOwnPropertySymbols)){x(t,Object.getOwnPropertySymbols(e))}return t}})}var Pn=function ConvertExceptionToBoolean(e){return!i(e)};if(Object.preventExtensions){Object.assign(En,{isExtensible:function isExtensible(e){In(e);return Object.isExtensible(e)},preventExtensions:function preventExtensions(e){In(e);return Pn(function(){return Object.preventExtensions(e)})}})}if(s){var Cn=function get(e,t,r){var n=Object.getOwnPropertyDescriptor(e,t);if(!n){var o=Object.getPrototypeOf(e);if(o===null){return void 0}return Cn(o,t,r)}if(\"value\"in n){return n.value}if(n.get){return ce.Call(n.get,r)}return void 0};var Mn=function set(e,r,n,o){var i=Object.getOwnPropertyDescriptor(e,r);if(!i){var a=Object.getPrototypeOf(e);if(a!==null){return Mn(a,r,n,o)}i={value:void 0,writable:true,enumerable:true,configurable:true}}if(\"value\"in i){if(!i.writable){return false}if(!ce.TypeIsObject(o)){return false}var u=Object.getOwnPropertyDescriptor(o,r);if(u){return ae.defineProperty(o,r,{value:n})}else{return ae.defineProperty(o,r,{value:n,writable:true,enumerable:true,configurable:true})}}if(i.set){t(i.set,o,n);return true}return false};Object.assign(En,{defineProperty:function defineProperty(e,t,r){In(e);return Pn(function(){return Object.defineProperty(e,t,r)})},getOwnPropertyDescriptor:function getOwnPropertyDescriptor(e,t){In(e);return Object.getOwnPropertyDescriptor(e,t)},get:function get(e,t){In(e);var r=arguments.length>2?arguments[2]:e;return Cn(e,t,r)},set:function set(e,t,r){In(e);var n=arguments.length>3?arguments[3]:e;return Mn(e,t,r,n)}})}if(Object.getPrototypeOf){var xn=Object.getPrototypeOf;En.getPrototypeOf=function getPrototypeOf(e){In(e);return xn(e)}}if(Object.setPrototypeOf&&En.getPrototypeOf){var Nn=function(e,t){var r=t;while(r){if(e===r){return true}r=En.getPrototypeOf(r)}return false};Object.assign(En,{setPrototypeOf:function setPrototypeOf(e,t){In(e);if(t!==null&&!ce.TypeIsObject(t)){throw new TypeError(\"proto must be an object or null\")}if(t===ae.getPrototypeOf(e)){return true}if(ae.isExtensible&&!ae.isExtensible(e)){return false}if(Nn(e,t)){return false}Object.setPrototypeOf(e,t);return true}})}var An=function(e,t){if(!ce.IsCallable(S.Reflect[e])){h(S.Reflect,e,t)}else{var r=a(function(){S.Reflect[e](1);S.Reflect[e](NaN);S.Reflect[e](true);return true});if(r){ne(S.Reflect,e,t)}}};Object.keys(En).forEach(function(e){An(e,En[e])});var Rn=S.Reflect.getPrototypeOf;if(c&&Rn&&Rn.name!==\"getPrototypeOf\"){ne(S.Reflect,\"getPrototypeOf\",function getPrototypeOf(e){return t(Rn,S.Reflect,e)})}if(S.Reflect.setPrototypeOf){if(a(function(){S.Reflect.setPrototypeOf(1,{});return true})){ne(S.Reflect,\"setPrototypeOf\",En.setPrototypeOf)}}if(S.Reflect.defineProperty){if(!a(function(){var e=!S.Reflect.defineProperty(1,\"test\",{value:1});var t=typeof Object.preventExtensions!==\"function\"||!S.Reflect.defineProperty(Object.preventExtensions({}),\"test\",{});return e&&t})){ne(S.Reflect,\"defineProperty\",En.defineProperty)}}if(S.Reflect.construct){if(!a(function(){var e=function F(){};return S.Reflect.construct(function(){},[],e)instanceof e})){ne(S.Reflect,\"construct\",En.construct)}}if(String(new Date(NaN))!==\"Invalid Date\"){var _n=Date.prototype.toString;var kn=function toString(){var e=+this;if(e!==e){return\"Invalid Date\"}return ce.Call(_n,this)};ne(Date.prototype,\"toString\",kn)}var Ln={anchor:function anchor(e){return ce.CreateHTML(this,\"a\",\"name\",e)},big:function big(){return ce.CreateHTML(this,\"big\",\"\",\"\")},blink:function blink(){return ce.CreateHTML(this,\"blink\",\"\",\"\")},bold:function bold(){return ce.CreateHTML(this,\"b\",\"\",\"\")},fixed:function fixed(){return ce.CreateHTML(this,\"tt\",\"\",\"\")},fontcolor:function fontcolor(e){return ce.CreateHTML(this,\"font\",\"color\",e)},fontsize:function fontsize(e){return ce.CreateHTML(this,\"font\",\"size\",e)},italics:function italics(){return ce.CreateHTML(this,\"i\",\"\",\"\")},link:function link(e){return ce.CreateHTML(this,\"a\",\"href\",e)},small:function small(){return ce.CreateHTML(this,\"small\",\"\",\"\")},strike:function strike(){return ce.CreateHTML(this,\"strike\",\"\",\"\")},sub:function sub(){return ce.CreateHTML(this,\"sub\",\"\",\"\")},sup:function sub(){return ce.CreateHTML(this,\"sup\",\"\",\"\")}};l(Object.keys(Ln),function(e){var r=String.prototype[e];var n=false;if(ce.IsCallable(r)){var o=t(r,\"\",' \" ');var i=P([],o.match(/\"/g)).length;n=o!==o.toLowerCase()||i>2}else{n=true}if(n){ne(String.prototype,e,Ln[e])}});var Fn=function(){if(!oe){return false}var e=typeof JSON===\"object\"&&typeof JSON.stringify===\"function\"?JSON.stringify:null;if(!e){return false}if(typeof e($())!==\"undefined\"){return true}if(e([$()])!==\"[null]\"){return true}var t={a:$()};t[$()]=true;if(e(t)!==\"{}\"){return true}return false}();var Dn=a(function(){if(!oe){return true}return JSON.stringify(Object($()))===\"{}\"&&JSON.stringify([Object($())])===\"[{}]\"});if(Fn||!Dn){var zn=JSON.stringify;ne(JSON,\"stringify\",function stringify(e){if(typeof e===\"symbol\"){return}var n;if(arguments.length>1){n=arguments[1]}var o=[e];if(!r(n)){var i=ce.IsCallable(n)?n:null;var a=function(e,r){var n=i?t(i,this,e,r):r;if(typeof n!==\"symbol\"){if(re.symbol(n)){return Nt({})(n)}else{return n}}};o.push(a)}else{o.push(n)}if(arguments.length>2){o.push(arguments[2])}return zn.apply(this,o)})}return S});\n//# sourceMappingURL=es6-shim.map\n/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */\n!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return t(e)}:t(e)}(\"undefined\"!=typeof window?window:this,function(C,e){\"use strict\";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return\"function\"==typeof e&&\"number\"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement(\"script\");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?n[o.call(e)]||\"object\":typeof e}var f=\"3.4.1\",k=function(e,t){return new k.fn.init(e,t)},p=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;function d(e){var t=!!e&&\"length\"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&0<t&&t-1 in e)}k.fn=k.prototype={jquery:f,constructor:k,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=k.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return k.each(this,e)},map:function(n){return this.pushStack(k.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},k.extend=k.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for(\"boolean\"==typeof a&&(l=a,a=arguments[s]||{},s++),\"object\"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],\"__proto__\"!==t&&a!==r&&(l&&r&&(k.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||k.isPlainObject(n)?n:{},i=!1,a[t]=k.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},k.extend({expando:\"jQuery\"+(f+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||\"[object Object]\"!==o.call(e))&&(!(t=r(e))||\"function\"==typeof(n=v.call(t,\"constructor\")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t){b(e,{nonce:t&&t.nonce})},each:function(e,t){var n,r=0;if(d(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?\"\":(e+\"\").replace(p,\"\")},makeArray:function(e,t){var n=t||[];return null!=e&&(d(Object(e))?k.merge(n,\"string\"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(d(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g.apply([],a)},guid:1,support:y}),\"function\"==typeof Symbol&&(k.fn[Symbol.iterator]=t[Symbol.iterator]),k.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){n[\"[object \"+t+\"]\"]=t.toLowerCase()});var h=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,k=\"sizzle\"+1*new Date,m=n.document,S=0,r=0,p=ue(),x=ue(),N=ue(),A=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",M=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",I=\"(?:\\\\\\\\.|[\\\\w-]|[^\\0-\\\\xa0])+\",W=\"\\\\[\"+M+\"*(\"+I+\")(?:\"+M+\"*([*^$|!~]?=)\"+M+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+I+\"))|)\"+M+\"*\\\\]\",$=\":(\"+I+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+W+\")*)|.*)\\\\)|)\",F=new RegExp(M+\"+\",\"g\"),B=new RegExp(\"^\"+M+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+M+\"+$\",\"g\"),_=new RegExp(\"^\"+M+\"*,\"+M+\"*\"),z=new RegExp(\"^\"+M+\"*([>+~]|\"+M+\")\"+M+\"*\"),U=new RegExp(M+\"|>\"),X=new RegExp($),V=new RegExp(\"^\"+I+\"$\"),G={ID:new RegExp(\"^#(\"+I+\")\"),CLASS:new RegExp(\"^\\\\.(\"+I+\")\"),TAG:new RegExp(\"^(\"+I+\"|[*])\"),ATTR:new RegExp(\"^\"+W),PSEUDO:new RegExp(\"^\"+$),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+M+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+M+\"*(?:([+-]|)\"+M+\"*(\\\\d+)|))\"+M+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+R+\")$\",\"i\"),needsContext:new RegExp(\"^\"+M+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+M+\"*((?:-\\\\d)?\\\\d*)\"+M+\"*\\\\)|)(?=[^-]|$)\",\"i\")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\\d$/i,K=/^[^{]+\\{\\s*\\[native \\w/,Z=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,ee=/[+~]/,te=new RegExp(\"\\\\\\\\([\\\\da-f]{1,6}\"+M+\"?|(\"+M+\")|.)\",\"ig\"),ne=function(e,t,n){var r=\"0x\"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,ie=function(e,t){return t?\"\\0\"===e?\"\\ufffd\":e.slice(0,-1)+\"\\\\\"+e.charCodeAt(e.length-1).toString(16)+\" \":\"\\\\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&\"fieldset\"===e.nodeName.toLowerCase()},{dir:\"parentNode\",next:\"legend\"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],\"string\"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+\" \"]&&(!v||!v.test(t))&&(1!==p||\"object\"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute(\"id\"))?s=s.replace(re,ie):e.setAttribute(\"id\",s=k),o=(l=h(t)).length;while(o--)l[o]=\"#\"+s+\" \"+xe(l[o]);c=l.join(\",\"),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute(\"id\")}}}return g(t.replace(B,\"$1\"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+\" \")>b.cacheLength&&delete e[r.shift()],e[t+\" \"]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement(\"fieldset\");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split(\"|\"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return\"input\"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return(\"input\"===t||\"button\"===t)&&e.type===n}}function ge(t){return function(e){return\"form\"in e?e.parentNode&&!1===e.disabled?\"label\"in e?\"label\"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:\"label\"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&\"undefined\"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||\"HTML\")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener(\"unload\",oe,!1):n.attachEvent&&n.attachEvent(\"onunload\",oe)),d.attributes=ce(function(e){return e.className=\"i\",!e.getAttribute(\"className\")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment(\"\")),!e.getElementsByTagName(\"*\").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute(\"id\")===t}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t=\"undefined\"!=typeof e.getAttributeNode&&e.getAttributeNode(\"id\");return t&&t.value===n}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return\"undefined\"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if(\"*\"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if(\"undefined\"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML=\"<a id='\"+k+\"'></a><select id='\"+k+\"-\\r\\\\' msallowcapture=''><option selected=''></option></select>\",e.querySelectorAll(\"[msallowcapture^='']\").length&&v.push(\"[*^$]=\"+M+\"*(?:''|\\\"\\\")\"),e.querySelectorAll(\"[selected]\").length||v.push(\"\\\\[\"+M+\"*(?:value|\"+R+\")\"),e.querySelectorAll(\"[id~=\"+k+\"-]\").length||v.push(\"~=\"),e.querySelectorAll(\":checked\").length||v.push(\":checked\"),e.querySelectorAll(\"a#\"+k+\"+*\").length||v.push(\".#.+[+~]\")}),ce(function(e){e.innerHTML=\"<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>\";var t=C.createElement(\"input\");t.setAttribute(\"type\",\"hidden\"),e.appendChild(t).setAttribute(\"name\",\"D\"),e.querySelectorAll(\"[name=d]\").length&&v.push(\"name\"+M+\"*[*^$|!~]?=\"),2!==e.querySelectorAll(\":enabled\").length&&v.push(\":enabled\",\":disabled\"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(\":disabled\").length&&v.push(\":enabled\",\":disabled\"),e.querySelectorAll(\"*,:x\"),v.push(\",.*:\")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,\"*\"),c.call(e,\"[s!='']:x\"),s.push(\"!=\",$)}),v=v.length&&new RegExp(v.join(\"|\")),s=s.length&&new RegExp(s.join(\"|\")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+\" \"]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!==C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!==C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+\"\").replace(re,ie)},se.error=function(e){throw new Error(\"Syntax error, unrecognized expression: \"+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n=\"\",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if(\"string\"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||\"\").replace(te,ne),\"~=\"===e[2]&&(e[3]=\" \"+e[3]+\" \"),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),\"nth\"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*(\"even\"===e[3]||\"odd\"===e[3])),e[5]=+(e[7]+e[8]||\"odd\"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||\"\":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(\")\",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return\"*\"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+\" \"];return t||(t=new RegExp(\"(^|\"+M+\")\"+e+\"(\"+M+\"|$)\"))&&p(e,function(e){return t.test(\"string\"==typeof e.className&&e.className||\"undefined\"!=typeof e.getAttribute&&e.getAttribute(\"class\")||\"\")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?\"!=\"===r:!r||(t+=\"\",\"=\"===r?t===i:\"!=\"===r?t!==i:\"^=\"===r?i&&0===t.indexOf(i):\"*=\"===r?i&&-1<t.indexOf(i):\"$=\"===r?i&&t.slice(-i.length)===i:\"~=\"===r?-1<(\" \"+t.replace(F,\" \")+\" \").indexOf(i):\"|=\"===r&&(t===i||t.slice(0,i.length+1)===i+\"-\"))}},CHILD:function(h,e,t,g,v){var y=\"nth\"!==h.slice(0,3),m=\"last\"!==h.slice(-4),x=\"of-type\"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?\"nextSibling\":\"previousSibling\",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l=\"only\"===h&&!u&&\"nextSibling\"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[S,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[S,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error(\"unsupported pseudo: \"+e);return a[k]?a(o):1<a.length?(t=[e,e,\"\",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace(B,\"$1\"));return s[k]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||\"\")||se.error(\"unsupported lang: \"+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute(\"xml:lang\")||e.getAttribute(\"lang\"))return(t=t.toLowerCase())===n||0===t.indexOf(n+\"-\")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&!!e.checked||\"option\"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&\"button\"===e.type||\"button\"===t},text:function(e){var t;return\"input\"===e.nodeName.toLowerCase()&&\"text\"===e.type&&(null==(t=e.getAttribute(\"type\"))||\"text\"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r=\"\";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&\"parentNode\"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[S,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[k]||(e[k]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===S&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[k]&&(v=Ce(v)),y&&!y[k]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||\"*\",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[\" \"],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[k]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:\" \"===e[s-2].type?\"*\":\"\"})).replace(B,\"$1\"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+\" \"];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace(B,\" \")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=N[e+\" \"];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[k]?i.push(a):o.push(a);(a=N(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l=\"0\",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG(\"*\",i),h=S+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t===C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument===C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(S=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(S=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l=\"function\"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&\"ID\"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=k.split(\"\").sort(D).join(\"\")===k,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement(\"fieldset\"))}),ce(function(e){return e.innerHTML=\"<a href='#'></a>\",\"#\"===e.firstChild.getAttribute(\"href\")})||fe(\"type|href|height|width\",function(e,t,n){if(!n)return e.getAttribute(t,\"type\"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML=\"<input/>\",e.firstChild.setAttribute(\"value\",\"\"),\"\"===e.firstChild.getAttribute(\"value\")})||fe(\"value\",function(e,t,n){if(!n&&\"input\"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute(\"disabled\")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);k.find=h,k.expr=h.selectors,k.expr[\":\"]=k.expr.pseudos,k.uniqueSort=k.unique=h.uniqueSort,k.text=h.getText,k.isXMLDoc=h.isXML,k.contains=h.contains,k.escapeSelector=h.escape;var T=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&k(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},N=k.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var D=/^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):\"string\"!=typeof n?k.grep(e,function(e){return-1<i.call(n,e)!==r}):k.filter(n,e,r)}k.filter=function(e,t,n){var r=t[0];return n&&(e=\":not(\"+e+\")\"),1===t.length&&1===r.nodeType?k.find.matchesSelector(r,e)?[r]:[]:k.find.matches(e,k.grep(t,function(e){return 1===e.nodeType}))},k.fn.extend({find:function(e){var t,n,r=this.length,i=this;if(\"string\"!=typeof e)return this.pushStack(k(e).filter(function(){for(t=0;t<r;t++)if(k.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)k.find(e,i[t],n);return 1<r?k.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,\"string\"==typeof e&&N.test(e)?k(e):e||[],!1).length}});var q,L=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,\"string\"==typeof e){if(!(r=\"<\"===e[0]&&\">\"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(k.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a=\"string\"!=typeof e&&k(e);if(!N.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&k.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?k.uniqueSort(o):o)},index:function(e){return e?\"string\"==typeof e?i.call(k(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(k.uniqueSort(k.merge(this.get(),k(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),k.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return T(e,\"parentNode\")},parentsUntil:function(e,t,n){return T(e,\"parentNode\",n)},next:function(e){return P(e,\"nextSibling\")},prev:function(e){return P(e,\"previousSibling\")},nextAll:function(e){return T(e,\"nextSibling\")},prevAll:function(e){return T(e,\"previousSibling\")},nextUntil:function(e,t,n){return T(e,\"nextSibling\",n)},prevUntil:function(e,t,n){return T(e,\"previousSibling\",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return\"undefined\"!=typeof e.contentDocument?e.contentDocument:(A(e,\"template\")&&(e=e.content||e),k.merge([],e.childNodes))}},function(r,i){k.fn[r]=function(e,t){var n=k.map(this,i,e);return\"Until\"!==r.slice(-5)&&(t=e),t&&\"string\"==typeof t&&(n=k.filter(t,n)),1<this.length&&(O[r]||k.uniqueSort(n),H.test(r)&&n.reverse()),this.pushStack(n)}});var R=/[^\\x20\\t\\r\\n\\f]+/g;function M(e){return e}function I(e){throw e}function W(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}k.Callbacks=function(r){var e,n;r=\"string\"==typeof r?(e=r,n={},k.each(e.match(R)||[],function(e,t){n[t]=!0}),n):k.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:\"\")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){k.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&\"string\"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return k.each(arguments,function(e,t){var n;while(-1<(n=k.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<k.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t=\"\",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=\"\"),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},k.extend({Deferred:function(e){var o=[[\"notify\",\"progress\",k.Callbacks(\"memory\"),k.Callbacks(\"memory\"),2],[\"resolve\",\"done\",k.Callbacks(\"once memory\"),k.Callbacks(\"once memory\"),0,\"resolved\"],[\"reject\",\"fail\",k.Callbacks(\"once memory\"),k.Callbacks(\"once memory\"),1,\"rejected\"]],i=\"pending\",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},\"catch\":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return k.Deferred(function(r){k.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+\"With\"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError(\"Thenable self-resolution\");t=e&&(\"object\"==typeof e||\"function\"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,M,s),l(u,o,I,s)):(u++,t.call(e,l(u,o,M,s),l(u,o,I,s),l(u,o,M,o.notifyWith))):(a!==M&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){k.Deferred.exceptionHook&&k.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==I&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(k.Deferred.getStackHook&&(t.stackTrace=k.Deferred.getStackHook()),C.setTimeout(t))}}return k.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:M,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:M)),o[2][3].add(l(0,e,m(n)?n:I))}).promise()},promise:function(e){return null!=e?k.extend(e,a):a}},s={};return k.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+\"With\"](this===s?void 0:this,arguments),this},s[t[0]+\"With\"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=k.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(W(e,o.done(a(t)).resolve,o.reject,!n),\"pending\"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)W(i[t],a(t),o.reject);return o.promise()}});var $=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;k.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&$.test(e.name)&&C.console.warn(\"jQuery.Deferred exception: \"+e.message,e.stack,t)},k.readyException=function(e){C.setTimeout(function(){throw e})};var F=k.Deferred();function B(){E.removeEventListener(\"DOMContentLoaded\",B),C.removeEventListener(\"load\",B),k.ready()}k.fn.ready=function(e){return F.then(e)[\"catch\"](function(e){k.readyException(e)}),this},k.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--k.readyWait:k.isReady)||(k.isReady=!0)!==e&&0<--k.readyWait||F.resolveWith(E,[k])}}),k.ready.then=F.then,\"complete\"===E.readyState||\"loading\"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(k.ready):(E.addEventListener(\"DOMContentLoaded\",B),C.addEventListener(\"load\",B));var _=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if(\"object\"===w(n))for(s in i=!0,n)_(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(k(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},z=/^-ms-/,U=/-([a-z])/g;function X(e,t){return t.toUpperCase()}function V(e){return e.replace(z,\"ms-\").replace(U,X)}var G=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function Y(){this.expando=k.expando+Y.uid++}Y.uid=1,Y.prototype={cache:function(e){var t=e[this.expando];return t||(t={},G(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if(\"string\"==typeof t)i[V(t)]=n;else for(r in t)i[V(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][V(t)]},access:function(e,t,n){return void 0===t||t&&\"string\"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(V):(t=V(t))in r?[t]:t.match(R)||[]).length;while(n--)delete r[t[n]]}(void 0===t||k.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!k.isEmptyObject(t)}};var Q=new Y,J=new Y,K=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,Z=/[A-Z]/g;function ee(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r=\"data-\"+t.replace(Z,\"-$&\").toLowerCase(),\"string\"==typeof(n=e.getAttribute(r))){try{n=\"true\"===(i=n)||\"false\"!==i&&(\"null\"===i?null:i===+i+\"\"?+i:K.test(i)?JSON.parse(i):i)}catch(e){}J.set(e,t,n)}else n=void 0;return n}k.extend({hasData:function(e){return J.hasData(e)||Q.hasData(e)},data:function(e,t,n){return J.access(e,t,n)},removeData:function(e,t){J.remove(e,t)},_data:function(e,t,n){return Q.access(e,t,n)},_removeData:function(e,t){Q.remove(e,t)}}),k.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=J.get(o),1===o.nodeType&&!Q.get(o,\"hasDataAttrs\"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf(\"data-\")&&(r=V(r.slice(5)),ee(o,r,i[r]));Q.set(o,\"hasDataAttrs\",!0)}return i}return\"object\"==typeof n?this.each(function(){J.set(this,n)}):_(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=J.get(o,n))?t:void 0!==(t=ee(o,n))?t:void 0;this.each(function(){J.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){J.remove(this,e)})}}),k.extend({queue:function(e,t,n){var r;if(e)return t=(t||\"fx\")+\"queue\",r=Q.get(e,t),n&&(!r||Array.isArray(n)?r=Q.access(e,t,k.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||\"fx\";var n=k.queue(e,t),r=n.length,i=n.shift(),o=k._queueHooks(e,t);\"inprogress\"===i&&(i=n.shift(),r--),i&&(\"fx\"===t&&n.unshift(\"inprogress\"),delete o.stop,i.call(e,function(){k.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+\"queueHooks\";return Q.get(e,n)||Q.access(e,n,{empty:k.Callbacks(\"once memory\").add(function(){Q.remove(e,[t+\"queue\",n])})})}}),k.fn.extend({queue:function(t,n){var e=2;return\"string\"!=typeof t&&(n=t,t=\"fx\",e--),arguments.length<e?k.queue(this[0],t):void 0===n?this:this.each(function(){var e=k.queue(this,t,n);k._queueHooks(this,t),\"fx\"===t&&\"inprogress\"!==e[0]&&k.dequeue(this,t)})},dequeue:function(e){return this.each(function(){k.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||\"fx\",[])},promise:function(e,t){var n,r=1,i=k.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};\"string\"!=typeof e&&(t=e,e=void 0),e=e||\"fx\";while(a--)(n=Q.get(o[a],e+\"queueHooks\"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var te=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,ne=new RegExp(\"^(?:([+-])=|)(\"+te+\")([a-z%]*)$\",\"i\"),re=[\"Top\",\"Right\",\"Bottom\",\"Left\"],ie=E.documentElement,oe=function(e){return k.contains(e.ownerDocument,e)},ae={composed:!0};ie.getRootNode&&(oe=function(e){return k.contains(e.ownerDocument,e)||e.getRootNode(ae)===e.ownerDocument});var se=function(e,t){return\"none\"===(e=t||e).style.display||\"\"===e.style.display&&oe(e)&&\"none\"===k.css(e,\"display\")},ue=function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];for(o in i=n.apply(e,r||[]),t)e.style[o]=a[o];return i};function le(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return k.css(e,t,\"\")},u=s(),l=n&&n[3]||(k.cssNumber[t]?\"\":\"px\"),c=e.nodeType&&(k.cssNumber[t]||\"px\"!==l&&+u)&&ne.exec(k.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)k.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,k.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ce={};function fe(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?(\"none\"===n&&(l[c]=Q.get(r,\"display\")||null,l[c]||(r.style.display=\"\")),\"\"===r.style.display&&se(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ce[s])||(o=a.body.appendChild(a.createElement(s)),u=k.css(o,\"display\"),o.parentNode.removeChild(o),\"none\"===u&&(u=\"block\"),ce[s]=u)))):\"none\"!==n&&(l[c]=\"none\",Q.set(r,\"display\",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}k.fn.extend({show:function(){return fe(this,!0)},hide:function(){return fe(this)},toggle:function(e){return\"boolean\"==typeof e?e?this.show():this.hide():this.each(function(){se(this)?k(this).show():k(this).hide()})}});var pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i,he=/^$|^module$|\\/(?:java|ecma)script/i,ge={option:[1,\"<select multiple='multiple'>\",\"</select>\"],thead:[1,\"<table>\",\"</table>\"],col:[2,\"<table><colgroup>\",\"</colgroup></table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:[0,\"\",\"\"]};function ve(e,t){var n;return n=\"undefined\"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):\"undefined\"!=typeof e.querySelectorAll?e.querySelectorAll(t||\"*\"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Q.set(e[n],\"globalEval\",!t||Q.get(t[n],\"globalEval\"))}ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;var me,xe,be=/<|&#?\\w+;/;function we(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if(\"object\"===w(o))k.merge(p,o.nodeType?[o]:o);else if(be.test(o)){a=a||f.appendChild(t.createElement(\"div\")),s=(de.exec(o)||[\"\",\"\"])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+k.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;k.merge(p,a.childNodes),(a=f.firstChild).textContent=\"\"}else p.push(t.createTextNode(o));f.textContent=\"\",d=0;while(o=p[d++])if(r&&-1<k.inArray(o,r))i&&i.push(o);else if(l=oe(o),a=ve(f.appendChild(o),\"script\"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||\"\")&&n.push(o)}return f}me=E.createDocumentFragment().appendChild(E.createElement(\"div\")),(xe=E.createElement(\"input\")).setAttribute(\"type\",\"radio\"),xe.setAttribute(\"checked\",\"checked\"),xe.setAttribute(\"name\",\"t\"),me.appendChild(xe),y.checkClone=me.cloneNode(!0).cloneNode(!0).lastChild.checked,me.innerHTML=\"<textarea>x</textarea>\",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==(\"focus\"===t)}function Ae(e,t,n,r,i,o){var a,s;if(\"object\"==typeof t){for(s in\"string\"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&(\"string\"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return\"undefined\"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||\"\").match(R)||[\"\"]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(\".\")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||\"\").match(R)||[\"\"]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&(\"**\"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,\"handle events\")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,\"events\")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t<arguments.length;t++)u[t]=arguments[t];if(s.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,s)){a=k.event.handlers.call(this,s,l),t=0;while((i=a[t++])&&!s.isPropagationStopped()){s.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!s.isImmediatePropagationStopped())s.rnamespace&&!1!==o.namespace&&!s.rnamespace.test(o.namespace)||(s.handleObj=o,s.data=o.data,void 0!==(r=((k.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,u))&&!1===(s.result=r)&&(s.preventDefault(),s.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,s),s.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!(\"click\"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&(\"click\"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+\" \"]&&(a[i]=r.needsContext?-1<k(i,this).index(l):k.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(k.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[k.expando]?e:new k.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,\"input\")&&De(t,\"click\",ke),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,\"input\")&&De(t,\"click\"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,\"input\")&&Q.get(t,\"click\")||A(t,\"a\")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},k.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},k.Event=function(e,t){if(!(this instanceof k.Event))return new k.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?ke:Se,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&k.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[k.expando]=!0},k.Event.prototype={constructor:k.Event,isDefaultPrevented:Se,isPropagationStopped:Se,isImmediatePropagationStopped:Se,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=ke,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=ke,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=ke,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},k.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,\"char\":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&Te.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&Ce.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},k.event.addProp),k.each({focus:\"focusin\",blur:\"focusout\"},function(e,t){k.event.special[e]={setup:function(){return De(this,e,Ne),!1},trigger:function(){return De(this,e),!0},delegateType:t}}),k.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(e,i){k.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||k.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),k.fn.extend({on:function(e,t,n,r){return Ae(this,e,t,n,r)},one:function(e,t,n,r){return Ae(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,k(e.delegateTarget).off(r.namespace?r.origType+\".\"+r.namespace:r.origType,r.selector,r.handler),this;if(\"object\"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&\"function\"!=typeof t||(n=t,t=void 0),!1===n&&(n=Se),this.each(function(){k.event.remove(this,e,n,t)})}});var je=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)[^>]*)\\/>/gi,qe=/<script|<style|<link/i,Le=/checked\\s*(?:[^=]|=\\s*.checked.)/i,He=/^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;function Oe(e,t){return A(e,\"table\")&&A(11!==t.nodeType?t:t.firstChild,\"tr\")&&k(e).children(\"tbody\")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute(\"type\"))+\"/\"+e.type,e}function Re(e){return\"true/\"===(e.type||\"\").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute(\"type\"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n<r;n++)k.event.add(t,i,l[i][n]);J.hasData(e)&&(s=J.access(e),u=k.extend({},s),J.set(t,u))}}function Ie(n,r,i,o){r=g.apply([],r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&\"string\"==typeof d&&!y.checkClone&&Le.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Ie(t,r,i,o)});if(f&&(t=(e=we(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=k.map(ve(e,\"script\"),Pe)).length;c<f;c++)u=e,c!==p&&(u=k.clone(u,!0,!0),s&&k.merge(a,ve(u,\"script\"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,k.map(a,Re),c=0;c<s;c++)u=a[c],he.test(u.type||\"\")&&!Q.access(u,\"globalEval\")&&k.contains(l,u)&&(u.src&&\"module\"!==(u.type||\"\").toLowerCase()?k._evalUrl&&!u.noModule&&k._evalUrl(u.src,{nonce:u.nonce||u.getAttribute(\"nonce\")}):b(u.textContent.replace(He,\"\"),u,l))}return n}function We(e,t,n){for(var r,i=t?k.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||k.cleanData(ve(r)),r.parentNode&&(n&&oe(r)&&ye(ve(r,\"script\")),r.parentNode.removeChild(r));return e}k.extend({htmlPrefilter:function(e){return e.replace(je,\"<$1></$2>\")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,\"input\"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:\"input\"!==l&&\"textarea\"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Me(o[r],a[r]);else Me(e,c);return 0<(a=ve(c,\"script\")).length&&ye(a,!f&&ve(e,\"script\")),c},cleanData:function(e){for(var t,n,r,i=k.event.special,o=0;void 0!==(n=e[o]);o++)if(G(n)){if(t=n[Q.expando]){if(t.events)for(r in t.events)i[r]?k.event.remove(n,r):k.removeEvent(n,r,t.handle);n[Q.expando]=void 0}n[J.expando]&&(n[J.expando]=void 0)}}}),k.fn.extend({detach:function(e){return We(this,e,!0)},remove:function(e){return We(this,e)},text:function(e){return _(this,function(e){return void 0===e?k.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Ie(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Oe(this,e).appendChild(e)})},prepend:function(){return Ie(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Oe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(k.cleanData(ve(e,!1)),e.textContent=\"\");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return k.clone(this,e,t)})},html:function(e){return _(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if(\"string\"==typeof e&&!qe.test(e)&&!ge[(de.exec(e)||[\"\",\"\"])[1].toLowerCase()]){e=k.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(k.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Ie(this,arguments,function(e){var t=this.parentNode;k.inArray(this,n)<0&&(k.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),k.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(e,a){k.fn[e]=function(e){for(var t,n=[],r=k(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),k(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var $e=new RegExp(\"^(\"+te+\")(?!px)[a-z%]+$\",\"i\"),Fe=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},Be=new RegExp(re.join(\"|\"),\"i\");function _e(e,t,n){var r,i,o,a,s=e.style;return(n=n||Fe(e))&&(\"\"!==(a=n.getPropertyValue(t)||n[t])||oe(e)||(a=k.style(e,t)),!y.pixelBoxStyles()&&$e.test(a)&&Be.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+\"\":a}function ze(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(u){s.style.cssText=\"position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0\",u.style.cssText=\"position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%\",ie.appendChild(s).appendChild(u);var e=C.getComputedStyle(u);n=\"1%\"!==e.top,a=12===t(e.marginLeft),u.style.right=\"60%\",o=36===t(e.right),r=36===t(e.width),u.style.position=\"absolute\",i=12===t(u.offsetWidth/3),ie.removeChild(s),u=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s=E.createElement(\"div\"),u=E.createElement(\"div\");u.style&&(u.style.backgroundClip=\"content-box\",u.cloneNode(!0).style.backgroundClip=\"\",y.clearCloneStyle=\"content-box\"===u.style.backgroundClip,k.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),a},scrollboxSize:function(){return e(),i}}))}();var Ue=[\"Webkit\",\"Moz\",\"ms\"],Xe=E.createElement(\"div\").style,Ve={};function Ge(e){var t=k.cssProps[e]||Ve[e];return t||(e in Xe?e:Ve[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Ue.length;while(n--)if((e=Ue[n]+t)in Xe)return e}(e)||e)}var Ye=/^(none|table(?!-c[ea]).+)/,Qe=/^--/,Je={position:\"absolute\",visibility:\"hidden\",display:\"block\"},Ke={letterSpacing:\"0\",fontWeight:\"400\"};function Ze(e,t,n){var r=ne.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||\"px\"):t}function et(e,t,n,r,i,o){var a=\"width\"===t?1:0,s=0,u=0;if(n===(r?\"border\":\"content\"))return 0;for(;a<4;a+=2)\"margin\"===n&&(u+=k.css(e,n+re[a],!0,i)),r?(\"content\"===n&&(u-=k.css(e,\"padding\"+re[a],!0,i)),\"margin\"!==n&&(u-=k.css(e,\"border\"+re[a]+\"Width\",!0,i))):(u+=k.css(e,\"padding\"+re[a],!0,i),\"padding\"!==n?u+=k.css(e,\"border\"+re[a]+\"Width\",!0,i):s+=k.css(e,\"border\"+re[a]+\"Width\",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e[\"offset\"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function tt(e,t,n){var r=Fe(e),i=(!y.boxSizingReliable()||n)&&\"border-box\"===k.css(e,\"boxSizing\",!1,r),o=i,a=_e(e,t,r),s=\"offset\"+t[0].toUpperCase()+t.slice(1);if($e.test(a)){if(!n)return a;a=\"auto\"}return(!y.boxSizingReliable()&&i||\"auto\"===a||!parseFloat(a)&&\"inline\"===k.css(e,\"display\",!1,r))&&e.getClientRects().length&&(i=\"border-box\"===k.css(e,\"boxSizing\",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+et(e,t,n||(i?\"border\":\"content\"),o,r,a)+\"px\"}function nt(e,t,n,r,i){return new nt.prototype.init(e,t,n,r,i)}k.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=_e(e,\"opacity\");return\"\"===n?\"1\":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=V(t),u=Qe.test(t),l=e.style;if(u||(t=Ge(s)),a=k.cssHooks[t]||k.cssHooks[s],void 0===n)return a&&\"get\"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];\"string\"===(o=typeof n)&&(i=ne.exec(n))&&i[1]&&(n=le(e,t,i),o=\"number\"),null!=n&&n==n&&(\"number\"!==o||u||(n+=i&&i[3]||(k.cssNumber[s]?\"\":\"px\")),y.clearCloneStyle||\"\"!==n||0!==t.indexOf(\"background\")||(l[t]=\"inherit\"),a&&\"set\"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=V(t);return Qe.test(t)||(t=Ge(s)),(a=k.cssHooks[t]||k.cssHooks[s])&&\"get\"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=_e(e,t,r)),\"normal\"===i&&t in Ke&&(i=Ke[t]),\"\"===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),k.each([\"height\",\"width\"],function(e,u){k.cssHooks[u]={get:function(e,t,n){if(t)return!Ye.test(k.css(e,\"display\"))||e.getClientRects().length&&e.getBoundingClientRect().width?tt(e,u,n):ue(e,Je,function(){return tt(e,u,n)})},set:function(e,t,n){var r,i=Fe(e),o=!y.scrollboxSize()&&\"absolute\"===i.position,a=(o||n)&&\"border-box\"===k.css(e,\"boxSizing\",!1,i),s=n?et(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e[\"offset\"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-et(e,u,\"border\",!1,i)-.5)),s&&(r=ne.exec(t))&&\"px\"!==(r[3]||\"px\")&&(e.style[u]=t,t=k.css(e,u)),Ze(0,t,s)}}}),k.cssHooks.marginLeft=ze(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(_e(e,\"marginLeft\"))||e.getBoundingClientRect().left-ue(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+\"px\"}),k.each({margin:\"\",padding:\"\",border:\"Width\"},function(i,o){k.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r=\"string\"==typeof e?e.split(\" \"):[e];t<4;t++)n[i+re[t]+o]=r[t]||r[t-2]||r[0];return n}},\"margin\"!==i&&(k.cssHooks[i+o].set=Ze)}),k.fn.extend({css:function(e,t){return _(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Fe(e),i=t.length;a<i;a++)o[t[a]]=k.css(e,t[a],!1,r);return o}return void 0!==n?k.style(e,t,n):k.css(e,t)},e,t,1<arguments.length)}}),((k.Tween=nt).prototype={constructor:nt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||k.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(k.cssNumber[n]?\"\":\"px\")},cur:function(){var e=nt.propHooks[this.prop];return e&&e.get?e.get(this):nt.propHooks._default.get(this)},run:function(e){var t,n=nt.propHooks[this.prop];return this.options.duration?this.pos=t=k.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):nt.propHooks._default.set(this),this}}).init.prototype=nt.prototype,(nt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=k.css(e.elem,e.prop,\"\"))&&\"auto\"!==t?t:0},set:function(e){k.fx.step[e.prop]?k.fx.step[e.prop](e):1!==e.elem.nodeType||!k.cssHooks[e.prop]&&null==e.elem.style[Ge(e.prop)]?e.elem[e.prop]=e.now:k.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=nt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},k.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:\"swing\"},k.fx=nt.prototype.init,k.fx.step={};var rt,it,ot,at,st=/^(?:toggle|show|hide)$/,ut=/queueHooks$/;function lt(){it&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(lt):C.setTimeout(lt,k.fx.interval),k.fx.tick())}function ct(){return C.setTimeout(function(){rt=void 0}),rt=Date.now()}function ft(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i[\"margin\"+(n=re[r])]=i[\"padding\"+n]=e;return t&&(i.opacity=i.width=e),i}function pt(e,t,n){for(var r,i=(dt.tweeners[t]||[]).concat(dt.tweeners[\"*\"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function dt(o,e,t){var n,a,r=0,i=dt.prefilters.length,s=k.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=rt||ct(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:k.extend({},e),opts:k.extend(!0,{specialEasing:{},easing:k.easing._default},t),originalProperties:e,originalOptions:t,startTime:rt||ct(),duration:t.duration,tweens:[],createTween:function(e,t){var n=k.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=V(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=k.cssHooks[r])&&\"expand\"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=dt.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(k._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return k.map(c,pt,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),k.fx.timer(k.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}k.Animation=k.extend(dt,{tweeners:{\"*\":[function(e,t){var n=this.createTween(e,t);return le(n.elem,e,ne.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=[\"*\"]):e=e.match(R);for(var n,r=0,i=e.length;r<i;r++)n=e[r],dt.tweeners[n]=dt.tweeners[n]||[],dt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f=\"width\"in t||\"height\"in t,p=this,d={},h=e.style,g=e.nodeType&&se(e),v=Q.get(e,\"fxshow\");for(r in n.queue||(null==(a=k._queueHooks(e,\"fx\")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,k.queue(e,\"fx\").length||a.empty.fire()})})),t)if(i=t[r],st.test(i)){if(delete t[r],o=o||\"toggle\"===i,i===(g?\"hide\":\"show\")){if(\"show\"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||k.style(e,r)}if((u=!k.isEmptyObject(t))||!k.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Q.get(e,\"display\")),\"none\"===(c=k.css(e,\"display\"))&&(l?c=l:(fe([e],!0),l=e.style.display||l,c=k.css(e,\"display\"),fe([e]))),(\"inline\"===c||\"inline-block\"===c&&null!=l)&&\"none\"===k.css(e,\"float\")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l=\"none\"===c?\"\":c)),h.display=\"inline-block\")),n.overflow&&(h.overflow=\"hidden\",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?\"hidden\"in v&&(g=v.hidden):v=Q.access(e,\"fxshow\",{display:l}),o&&(v.hidden=!g),g&&fe([e],!0),p.done(function(){for(r in g||fe([e]),Q.remove(e,\"fxshow\"),d)k.style(e,r,d[r])})),u=pt(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?dt.prefilters.unshift(e):dt.prefilters.push(e)}}),k.speed=function(e,t,n){var r=e&&\"object\"==typeof e?k.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return k.fx.off?r.duration=0:\"number\"!=typeof r.duration&&(r.duration in k.fx.speeds?r.duration=k.fx.speeds[r.duration]:r.duration=k.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue=\"fx\"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&k.dequeue(this,r.queue)},r},k.fn.extend({fadeTo:function(e,t,n,r){return this.filter(se).css(\"opacity\",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=k.isEmptyObject(t),o=k.speed(e,n,r),a=function(){var e=dt(this,k.extend({},t),o);(i||Q.get(this,\"finish\"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return\"string\"!=typeof i&&(o=e,e=i,i=void 0),e&&!1!==i&&this.queue(i||\"fx\",[]),this.each(function(){var e=!0,t=null!=i&&i+\"queueHooks\",n=k.timers,r=Q.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&ut.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||k.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||\"fx\"),this.each(function(){var e,t=Q.get(this),n=t[a+\"queue\"],r=t[a+\"queueHooks\"],i=k.timers,o=n?n.length:0;for(t.finish=!0,k.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),k.each([\"toggle\",\"show\",\"hide\"],function(e,r){var i=k.fn[r];k.fn[r]=function(e,t,n){return null==e||\"boolean\"==typeof e?i.apply(this,arguments):this.animate(ft(r,!0),e,t,n)}}),k.each({slideDown:ft(\"show\"),slideUp:ft(\"hide\"),slideToggle:ft(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(e,r){k.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),k.timers=[],k.fx.tick=function(){var e,t=0,n=k.timers;for(rt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||k.fx.stop(),rt=void 0},k.fx.timer=function(e){k.timers.push(e),k.fx.start()},k.fx.interval=13,k.fx.start=function(){it||(it=!0,lt())},k.fx.stop=function(){it=null},k.fx.speeds={slow:600,fast:200,_default:400},k.fn.delay=function(r,e){return r=k.fx&&k.fx.speeds[r]||r,e=e||\"fx\",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},ot=E.createElement(\"input\"),at=E.createElement(\"select\").appendChild(E.createElement(\"option\")),ot.type=\"checkbox\",y.checkOn=\"\"!==ot.value,y.optSelected=at.selected,(ot=E.createElement(\"input\")).value=\"t\",ot.type=\"radio\",y.radioValue=\"t\"===ot.value;var ht,gt=k.expr.attrHandle;k.fn.extend({attr:function(e,t){return _(this,k.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){k.removeAttr(this,e)})}}),k.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return\"undefined\"==typeof e.getAttribute?k.prop(e,t,n):(1===o&&k.isXMLDoc(e)||(i=k.attrHooks[t.toLowerCase()]||(k.expr.match.bool.test(t)?ht:void 0)),void 0!==n?null===n?void k.removeAttr(e,t):i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+\"\"),n):i&&\"get\"in i&&null!==(r=i.get(e,t))?r:null==(r=k.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&\"radio\"===t&&A(e,\"input\")){var n=e.value;return e.setAttribute(\"type\",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(R);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),ht={set:function(e,t,n){return!1===t?k.removeAttr(e,n):e.setAttribute(n,n),n}},k.each(k.expr.match.bool.source.match(/\\w+/g),function(e,t){var a=gt[t]||k.find.attr;gt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=gt[o],gt[o]=r,r=null!=a(e,t,n)?o:null,gt[o]=i),r}});var vt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;function mt(e){return(e.match(R)||[]).join(\" \")}function xt(e){return e.getAttribute&&e.getAttribute(\"class\")||\"\"}function bt(e){return Array.isArray(e)?e:\"string\"==typeof e&&e.match(R)||[]}k.fn.extend({prop:function(e,t){return _(this,k.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[k.propFix[e]||e]})}}),k.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&k.isXMLDoc(e)||(t=k.propFix[t]||t,i=k.propHooks[t]),void 0!==n?i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&\"get\"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=k.find.attr(e,\"tabindex\");return t?parseInt(t,10):vt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{\"for\":\"htmlFor\",\"class\":\"className\"}}),y.optSelected||(k.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),k.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){k.propFix[this.toLowerCase()]=this}),k.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).addClass(t.call(this,e,xt(this)))});if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&\" \"+mt(i)+\" \"){a=0;while(o=e[a++])r.indexOf(\" \"+o+\" \")<0&&(r+=o+\" \");i!==(s=mt(r))&&n.setAttribute(\"class\",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).removeClass(t.call(this,e,xt(this)))});if(!arguments.length)return this.attr(\"class\",\"\");if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&\" \"+mt(i)+\" \"){a=0;while(o=e[a++])while(-1<r.indexOf(\" \"+o+\" \"))r=r.replace(\" \"+o+\" \",\" \");i!==(s=mt(r))&&n.setAttribute(\"class\",s)}return this},toggleClass:function(i,t){var o=typeof i,a=\"string\"===o||Array.isArray(i);return\"boolean\"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){k(this).toggleClass(i.call(this,e,xt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=k(this),r=bt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&\"boolean\"!==o||((e=xt(this))&&Q.set(this,\"__className__\",e),this.setAttribute&&this.setAttribute(\"class\",e||!1===i?\"\":Q.get(this,\"__className__\")||\"\"))})},hasClass:function(e){var t,n,r=0;t=\" \"+e+\" \";while(n=this[r++])if(1===n.nodeType&&-1<(\" \"+mt(xt(n))+\" \").indexOf(t))return!0;return!1}});var wt=/\\r/g;k.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,k(this).val()):n)?t=\"\":\"number\"==typeof t?t+=\"\":Array.isArray(t)&&(t=k.map(t,function(e){return null==e?\"\":e+\"\"})),(r=k.valHooks[this.type]||k.valHooks[this.nodeName.toLowerCase()])&&\"set\"in r&&void 0!==r.set(this,t,\"value\")||(this.value=t))})):t?(r=k.valHooks[t.type]||k.valHooks[t.nodeName.toLowerCase()])&&\"get\"in r&&void 0!==(e=r.get(t,\"value\"))?e:\"string\"==typeof(e=t.value)?e.replace(wt,\"\"):null==e?\"\":e:void 0}}),k.extend({valHooks:{option:{get:function(e){var t=k.find.attr(e,\"value\");return null!=t?t:mt(k.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a=\"select-one\"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,\"optgroup\"))){if(t=k(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=k.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<k.inArray(k.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),k.each([\"radio\",\"checkbox\"],function(){k.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<k.inArray(k(e).val(),t)}},y.checkOn||(k.valHooks[this].get=function(e){return null===e.getAttribute(\"value\")?\"on\":e.value})}),y.focusin=\"onfocusin\"in C;var Tt=/^(?:focusinfocus|focusoutblur)$/,Ct=function(e){e.stopPropagation()};k.extend(k.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,\"type\")?e.type:e,h=v.call(e,\"namespace\")?e.namespace.split(\".\"):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!Tt.test(d+k.event.triggered)&&(-1<d.indexOf(\".\")&&(d=(h=d.split(\".\")).shift(),h.sort()),u=d.indexOf(\":\")<0&&\"on\"+d,(e=e[k.expando]?e:new k.Event(d,\"object\"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join(\".\"),e.rnamespace=e.namespace?new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:k.makeArray(t,[e]),c=k.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,Tt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Q.get(o,\"events\")||{})[e.type]&&Q.get(o,\"handle\"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&G(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!G(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),k.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,Ct),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,Ct),k.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=k.extend(new k.Event,n,{type:e,isSimulated:!0});k.event.trigger(r,null,t)}}),k.fn.extend({trigger:function(e,t){return this.each(function(){k.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return k.event.trigger(e,t,n,!0)}}),y.focusin||k.each({focus:\"focusin\",blur:\"focusout\"},function(n,r){var i=function(e){k.event.simulate(r,e.target,k.event.fix(e))};k.event.special[r]={setup:function(){var e=this.ownerDocument||this,t=Q.access(e,r);t||e.addEventListener(n,i,!0),Q.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this,t=Q.access(e,r)-1;t?Q.access(e,r,t):(e.removeEventListener(n,i,!0),Q.remove(e,r))}}});var Et=C.location,kt=Date.now(),St=/\\?/;k.parseXML=function(e){var t;if(!e||\"string\"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,\"text/xml\")}catch(e){t=void 0}return t&&!t.getElementsByTagName(\"parsererror\").length||k.error(\"Invalid XML: \"+e),t};var Nt=/\\[\\]$/,At=/\\r?\\n/g,Dt=/^(?:submit|button|image|reset|file)$/i,jt=/^(?:input|select|textarea|keygen)/i;function qt(n,e,r,i){var t;if(Array.isArray(e))k.each(e,function(e,t){r||Nt.test(n)?i(n,t):qt(n+\"[\"+(\"object\"==typeof t&&null!=t?e:\"\")+\"]\",t,r,i)});else if(r||\"object\"!==w(e))i(n,e);else for(t in e)qt(n+\"[\"+t+\"]\",e[t],r,i)}k.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+\"=\"+encodeURIComponent(null==n?\"\":n)};if(null==e)return\"\";if(Array.isArray(e)||e.jquery&&!k.isPlainObject(e))k.each(e,function(){i(this.name,this.value)});else for(n in e)qt(n,e[n],t,i);return r.join(\"&\")},k.fn.extend({serialize:function(){return k.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=k.prop(this,\"elements\");return e?k.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!k(this).is(\":disabled\")&&jt.test(this.nodeName)&&!Dt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=k(this).val();return null==n?null:Array.isArray(n)?k.map(n,function(e){return{name:t.name,value:e.replace(At,\"\\r\\n\")}}):{name:t.name,value:n.replace(At,\"\\r\\n\")}}).get()}});var Lt=/%20/g,Ht=/#.*$/,Ot=/([?&])_=[^&]*/,Pt=/^(.*?):[ \\t]*([^\\r\\n]*)$/gm,Rt=/^(?:GET|HEAD)$/,Mt=/^\\/\\//,It={},Wt={},$t=\"*/\".concat(\"*\"),Ft=E.createElement(\"a\");function Bt(o){return function(e,t){\"string\"!=typeof e&&(t=e,e=\"*\");var n,r=0,i=e.toLowerCase().match(R)||[];if(m(t))while(n=i[r++])\"+\"===n[0]?(n=n.slice(1)||\"*\",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function _t(t,i,o,a){var s={},u=t===Wt;function l(e){var r;return s[e]=!0,k.each(t[e]||[],function(e,t){var n=t(i,o,a);return\"string\"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s[\"*\"]&&l(\"*\")}function zt(e,t){var n,r,i=k.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&k.extend(!0,e,r),e}Ft.href=Et.href,k.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Et.href,type:\"GET\",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Et.protocol),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":$t,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":JSON.parse,\"text xml\":k.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,k.ajaxSettings),t):zt(k.ajaxSettings,e)},ajaxPrefilter:Bt(It),ajaxTransport:Bt(Wt),ajax:function(e,t){\"object\"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=k.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?k(y):k.event,x=k.Deferred(),b=k.Callbacks(\"once memory\"),w=v.statusCode||{},a={},s={},u=\"canceled\",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Pt.exec(p))n[t[1].toLowerCase()+\" \"]=(n[t[1].toLowerCase()+\" \"]||[]).concat(t[2])}t=n[e.toLowerCase()+\" \"]}return null==t?null:t.join(\", \")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Et.href)+\"\").replace(Mt,Et.protocol+\"//\"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||\"*\").toLowerCase().match(R)||[\"\"],null==v.crossDomain){r=E.createElement(\"a\");try{r.href=v.url,r.href=r.href,v.crossDomain=Ft.protocol+\"//\"+Ft.host!=r.protocol+\"//\"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&\"string\"!=typeof v.data&&(v.data=k.param(v.data,v.traditional)),_t(It,v,t,T),h)return T;for(i in(g=k.event&&v.global)&&0==k.active++&&k.event.trigger(\"ajaxStart\"),v.type=v.type.toUpperCase(),v.hasContent=!Rt.test(v.type),f=v.url.replace(Ht,\"\"),v.hasContent?v.data&&v.processData&&0===(v.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&(v.data=v.data.replace(Lt,\"+\")):(o=v.url.slice(f.length),v.data&&(v.processData||\"string\"==typeof v.data)&&(f+=(St.test(f)?\"&\":\"?\")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Ot,\"$1\"),o=(St.test(f)?\"&\":\"?\")+\"_=\"+kt+++o),v.url=f+o),v.ifModified&&(k.lastModified[f]&&T.setRequestHeader(\"If-Modified-Since\",k.lastModified[f]),k.etag[f]&&T.setRequestHeader(\"If-None-Match\",k.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader(\"Content-Type\",v.contentType),T.setRequestHeader(\"Accept\",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+(\"*\"!==v.dataTypes[0]?\", \"+$t+\"; q=0.01\":\"\"):v.accepts[\"*\"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u=\"abort\",b.add(v.complete),T.done(v.success),T.fail(v.error),c=_t(Wt,v,t,T)){if(T.readyState=1,g&&m.trigger(\"ajaxSend\",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort(\"timeout\")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,\"No Transport\");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||\"\",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while(\"*\"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader(\"Content-Type\"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+\" \"+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if(\"*\"===o)o=u;else if(\"*\"!==u&&u!==o){if(!(a=l[u+\" \"+o]||l[\"* \"+o]))for(i in l)if((s=i.split(\" \"))[1]===o&&(a=l[u+\" \"+s[0]]||l[\"* \"+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e[\"throws\"])t=a(t);else try{t=a(t)}catch(e){return{state:\"parsererror\",error:a?e:\"No conversion from \"+u+\" to \"+o}}}return{state:\"success\",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader(\"Last-Modified\"))&&(k.lastModified[f]=u),(u=T.getResponseHeader(\"etag\"))&&(k.etag[f]=u)),204===e||\"HEAD\"===v.type?l=\"nocontent\":304===e?l=\"notmodified\":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l=\"error\",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+\"\",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?\"ajaxSuccess\":\"ajaxError\",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger(\"ajaxComplete\",[T,v]),--k.active||k.event.trigger(\"ajaxStop\")))}return T},getJSON:function(e,t,n){return k.get(e,t,n,\"json\")},getScript:function(e,t){return k.get(e,void 0,t,\"script\")}}),k.each([\"get\",\"post\"],function(e,i){k[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),k.ajax(k.extend({url:e,type:i,dataType:r,data:t,success:n},k.isPlainObject(e)&&e))}}),k._evalUrl=function(e,t){return k.ajax({url:e,type:\"GET\",dataType:\"script\",cache:!0,async:!1,global:!1,converters:{\"text script\":function(){}},dataFilter:function(e){k.globalEval(e,t)}})},k.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=k(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){k(this).wrapInner(n.call(this,e))}):this.each(function(){var e=k(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){k(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not(\"body\").each(function(){k(this).replaceWith(this.childNodes)}),this}}),k.expr.pseudos.hidden=function(e){return!k.expr.pseudos.visible(e)},k.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},k.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var Ut={0:200,1223:204},Xt=k.ajaxSettings.xhr();y.cors=!!Xt&&\"withCredentials\"in Xt,y.ajax=Xt=!!Xt,k.ajaxTransport(function(i){var o,a;if(y.cors||Xt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e[\"X-Requested-With\"]||(e[\"X-Requested-With\"]=\"XMLHttpRequest\"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,\"abort\"===e?r.abort():\"error\"===e?\"number\"!=typeof r.status?t(0,\"error\"):t(r.status,r.statusText):t(Ut[r.status]||r.status,r.statusText,\"text\"!==(r.responseType||\"text\")||\"string\"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o(\"error\"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o(\"abort\");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),k.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),k.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(e){return k.globalEval(e),e}}}),k.ajaxPrefilter(\"script\",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type=\"GET\")}),k.ajaxTransport(\"script\",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=k(\"<script>\").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on(\"load error\",i=function(e){r.remove(),i=null,e&&t(\"error\"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\\?(?=&|$)|\\?\\?/;k.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var e=Gt.pop()||k.expando+\"_\"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter(\"json jsonp\",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?\"url\":\"string\"==typeof e.data&&0===(e.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&Yt.test(e.data)&&\"data\");if(a||\"jsonp\"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,\"$1\"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?\"&\":\"?\")+e.jsonp+\"=\"+r),e.converters[\"script json\"]=function(){return o||k.error(r+\" was not called\"),o[0]},e.dataTypes[0]=\"json\",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),\"script\"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument(\"\").body).innerHTML=\"<form></form><form></form>\",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return\"string\"!=typeof e?[]:(\"boolean\"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument(\"\")).createElement(\"base\")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(\" \");return-1<s&&(r=mt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&\"object\"==typeof t&&(i=\"POST\"),0<a.length&&k.ajax({url:e,type:i||\"GET\",dataType:\"html\",data:t}).done(function(e){o=arguments,a.html(r?k(\"<div>\").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,\"position\"),c=k(e),f={};\"static\"===l&&(e.style.position=\"relative\"),s=c.offset(),o=k.css(e,\"top\"),u=k.css(e,\"left\"),(\"absolute\"===l||\"fixed\"===l)&&-1<(o+u).indexOf(\"auto\")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),\"using\"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if(\"fixed\"===k.css(r,\"position\"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&\"static\"===k.css(e,\"position\"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,\"borderTopWidth\",!0),i.left+=k.css(e,\"borderLeftWidth\",!0))}return{top:t.top-i.top-k.css(r,\"marginTop\",!0),left:t.left-i.left-k.css(r,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&\"static\"===k.css(e,\"position\"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(t,i){var o=\"pageYOffset\"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each([\"top\",\"left\"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+\"px\":t})}),k.each({Height:\"height\",Width:\"width\"},function(a,s){k.each({padding:\"inner\"+a,content:s,\"\":\"outer\"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||\"boolean\"!=typeof e),i=r||(!0===e||!0===t?\"margin\":\"border\");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf(\"outer\")?e[\"inner\"+a]:e.document.documentElement[\"client\"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body[\"scroll\"+a],r[\"scroll\"+a],e.body[\"offset\"+a],r[\"offset\"+a],r[\"client\"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each(\"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu\".split(\" \"),function(e,n){k.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}}),k.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),k.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)}}),k.proxy=function(e,t){var n,r,i;if(\"string\"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||k.guid++,i},k.holdReady=function(e){e?k.readyWait++:k.ready(!0)},k.isArray=Array.isArray,k.parseJSON=JSON.parse,k.nodeName=A,k.isFunction=m,k.isWindow=x,k.camelCase=V,k.type=w,k.now=Date.now,k.isNumeric=function(e){var t=k.type(e);return(\"number\"===t||\"string\"===t)&&!isNaN(e-parseFloat(e))},\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return k});var Qt=C.jQuery,Jt=C.$;return k.noConflict=function(e){return C.$===k&&(C.$=Jt),e&&C.jQuery===k&&(C.jQuery=Qt),k},e||(C.jQuery=C.$=k),k});\n/*\n * jQuery throttle / debounce - v1.1 - 3/7/2010\n * http://benalman.com/projects/jquery-throttle-debounce-plugin/\n * \n * Copyright (c) 2010 \"Cowboy\" Ben Alman\n * Dual licensed under the MIT and GPL licenses.\n * http://benalman.com/about/license/\n */\n(function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!==\"boolean\"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this);\n/*!\n * imagesLoaded PACKAGED v4.1.0\n * JavaScript is all like \"You images are done yet or what?\"\n * MIT License\n */\n!function(t,e){\"function\"==typeof define&&define.amd?define(\"ev-emitter/ev-emitter\",e):\"object\"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}(this,function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var i=this._events=this._events||{},n=i[t]=i[t]||[];return-1==n.indexOf(e)&&n.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var i=this._onceEvents=this._onceEvents||{},n=i[t]=i[t]||[];return n[e]=!0,this}},e.off=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=i.indexOf(e);return-1!=n&&i.splice(n,1),this}},e.emitEvent=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=0,o=i[n];e=e||[];for(var r=this._onceEvents&&this._onceEvents[t];o;){var s=r&&r[o];s&&(this.off(t,o),delete r[o]),o.apply(this,e),n+=s?0:1,o=i[n]}return this}},t}),function(t,e){\"use strict\";\"function\"==typeof define&&define.amd?define([\"ev-emitter/ev-emitter\"],function(i){return e(t,i)}):\"object\"==typeof module&&module.exports?module.exports=e(t,require(\"ev-emitter\")):t.imagesLoaded=e(t,t.EvEmitter)}(window,function(t,e){function i(t,e){for(var i in e)t[i]=e[i];return t}function n(t){var e=[];if(Array.isArray(t))e=t;else if(\"number\"==typeof t.length)for(var i=0;i<t.length;i++)e.push(t[i]);else e.push(t);return e}function o(t,e,r){return this instanceof o?(\"string\"==typeof t&&(t=document.querySelectorAll(t)),this.elements=n(t),this.options=i({},this.options),\"function\"==typeof e?r=e:i(this.options,e),r&&this.on(\"always\",r),this.getImages(),h&&(this.jqDeferred=new h.Deferred),void setTimeout(function(){this.check()}.bind(this))):new o(t,e,r)}function r(t){this.img=t}function s(t,e){this.url=t,this.element=e,this.img=new Image}var h=t.jQuery,a=t.console;o.prototype=Object.create(e.prototype),o.prototype.options={},o.prototype.getImages=function(){this.images=[],this.elements.forEach(this.addElementImages,this)},o.prototype.addElementImages=function(t){\"IMG\"==t.nodeName&&this.addImage(t),this.options.background===!0&&this.addElementBackgroundImages(t);var e=t.nodeType;if(e&&d[e]){for(var i=t.querySelectorAll(\"img\"),n=0;n<i.length;n++){var o=i[n];this.addImage(o)}if(\"string\"==typeof this.options.background){var r=t.querySelectorAll(this.options.background);for(n=0;n<r.length;n++){var s=r[n];this.addElementBackgroundImages(s)}}}};var d={1:!0,9:!0,11:!0};return o.prototype.addElementBackgroundImages=function(t){var e=getComputedStyle(t);if(e)for(var i=/url\\((['\"])?(.*?)\\1\\)/gi,n=i.exec(e.backgroundImage);null!==n;){var o=n&&n[2];o&&this.addBackground(o,t),n=i.exec(e.backgroundImage)}},o.prototype.addImage=function(t){var e=new r(t);this.images.push(e)},o.prototype.addBackground=function(t,e){var i=new s(t,e);this.images.push(i)},o.prototype.check=function(){function t(t,i,n){setTimeout(function(){e.progress(t,i,n)})}var e=this;return this.progressedCount=0,this.hasAnyBroken=!1,this.images.length?void this.images.forEach(function(e){e.once(\"progress\",t),e.check()}):void this.complete()},o.prototype.progress=function(t,e,i){this.progressedCount++,this.hasAnyBroken=this.hasAnyBroken||!t.isLoaded,this.emitEvent(\"progress\",[this,t,e]),this.jqDeferred&&this.jqDeferred.notify&&this.jqDeferred.notify(this,t),this.progressedCount==this.images.length&&this.complete(),this.options.debug&&a&&a.log(\"progress: \"+i,t,e)},o.prototype.complete=function(){var t=this.hasAnyBroken?\"fail\":\"done\";if(this.isComplete=!0,this.emitEvent(t,[this]),this.emitEvent(\"always\",[this]),this.jqDeferred){var e=this.hasAnyBroken?\"reject\":\"resolve\";this.jqDeferred[e](this)}},r.prototype=Object.create(e.prototype),r.prototype.check=function(){var t=this.getIsImageComplete();return t?void this.confirm(0!==this.img.naturalWidth,\"naturalWidth\"):(this.proxyImage=new Image,this.proxyImage.addEventListener(\"load\",this),this.proxyImage.addEventListener(\"error\",this),this.img.addEventListener(\"load\",this),this.img.addEventListener(\"error\",this),void(this.proxyImage.src=this.img.src))},r.prototype.getIsImageComplete=function(){return this.img.complete&&void 0!==this.img.naturalWidth},r.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent(\"progress\",[this,this.img,e])},r.prototype.handleEvent=function(t){var e=\"on\"+t.type;this[e]&&this[e](t)},r.prototype.onload=function(){this.confirm(!0,\"onload\"),this.unbindEvents()},r.prototype.onerror=function(){this.confirm(!1,\"onerror\"),this.unbindEvents()},r.prototype.unbindEvents=function(){this.proxyImage.removeEventListener(\"load\",this),this.proxyImage.removeEventListener(\"error\",this),this.img.removeEventListener(\"load\",this),this.img.removeEventListener(\"error\",this)},s.prototype=Object.create(r.prototype),s.prototype.check=function(){this.img.addEventListener(\"load\",this),this.img.addEventListener(\"error\",this),this.img.src=this.url;var t=this.getIsImageComplete();t&&(this.confirm(0!==this.img.naturalWidth,\"naturalWidth\"),this.unbindEvents())},s.prototype.unbindEvents=function(){this.img.removeEventListener(\"load\",this),this.img.removeEventListener(\"error\",this)},s.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent(\"progress\",[this,this.element,e])},o.makeJQueryPlugin=function(e){e=e||t.jQuery,e&&(h=e,h.fn.imagesLoaded=function(t,e){var i=new o(this,t,e);return i.jqDeferred.promise(h(this))})},o.makeJQueryPlugin(),o});\n/*! lz-string-1.3.3-min.js | (c) 2013 Pieroxy | Licensed under a WTFPL license */\nvar LZString={_keyStr:\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\",_f:String.fromCharCode,compressToBase64:function(e){if(e==null)return\"\";var t=\"\";var n,r,i,s,o,u,a;var f=0;e=LZString.compress(e);while(f<e.length*2){if(f%2==0){n=e.charCodeAt(f/2)>>8;r=e.charCodeAt(f/2)&255;if(f/2+1<e.length)i=e.charCodeAt(f/2+1)>>8;else i=NaN}else{n=e.charCodeAt((f-1)/2)&255;if((f+1)/2<e.length){r=e.charCodeAt((f+1)/2)>>8;i=e.charCodeAt((f+1)/2)&255}else r=i=NaN}f+=3;s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+LZString._keyStr.charAt(s)+LZString._keyStr.charAt(o)+LZString._keyStr.charAt(u)+LZString._keyStr.charAt(a)}return t},decompressFromBase64:function(e){if(e==null)return\"\";var t=\"\",n=0,r,i,s,o,u,a,f,l,c=0,h=LZString._f;e=e.replace(/[^A-Za-z0-9\\+\\/\\=]/g,\"\");while(c<e.length){u=LZString._keyStr.indexOf(e.charAt(c++));a=LZString._keyStr.indexOf(e.charAt(c++));f=LZString._keyStr.indexOf(e.charAt(c++));l=LZString._keyStr.indexOf(e.charAt(c++));i=u<<2|a>>4;s=(a&15)<<4|f>>2;o=(f&3)<<6|l;if(n%2==0){r=i<<8;if(f!=64){t+=h(r|s)}if(l!=64){r=o<<8}}else{t=t+h(r|i);if(f!=64){r=s<<8}if(l!=64){t+=h(r|o)}}n+=3}return LZString.decompress(t)},compressToUTF16:function(e){if(e==null)return\"\";var t=\"\",n,r,i,s=0,o=LZString._f;e=LZString.compress(e);for(n=0;n<e.length;n++){r=e.charCodeAt(n);switch(s++){case 0:t+=o((r>>1)+32);i=(r&1)<<14;break;case 1:t+=o(i+(r>>2)+32);i=(r&3)<<13;break;case 2:t+=o(i+(r>>3)+32);i=(r&7)<<12;break;case 3:t+=o(i+(r>>4)+32);i=(r&15)<<11;break;case 4:t+=o(i+(r>>5)+32);i=(r&31)<<10;break;case 5:t+=o(i+(r>>6)+32);i=(r&63)<<9;break;case 6:t+=o(i+(r>>7)+32);i=(r&127)<<8;break;case 7:t+=o(i+(r>>8)+32);i=(r&255)<<7;break;case 8:t+=o(i+(r>>9)+32);i=(r&511)<<6;break;case 9:t+=o(i+(r>>10)+32);i=(r&1023)<<5;break;case 10:t+=o(i+(r>>11)+32);i=(r&2047)<<4;break;case 11:t+=o(i+(r>>12)+32);i=(r&4095)<<3;break;case 12:t+=o(i+(r>>13)+32);i=(r&8191)<<2;break;case 13:t+=o(i+(r>>14)+32);i=(r&16383)<<1;break;case 14:t+=o(i+(r>>15)+32,(r&32767)+32);s=0;break}}return t+o(i+32)},decompressFromUTF16:function(e){if(e==null)return\"\";var t=\"\",n,r,i=0,s=0,o=LZString._f;while(s<e.length){r=e.charCodeAt(s)-32;switch(i++){case 0:n=r<<1;break;case 1:t+=o(n|r>>14);n=(r&16383)<<2;break;case 2:t+=o(n|r>>13);n=(r&8191)<<3;break;case 3:t+=o(n|r>>12);n=(r&4095)<<4;break;case 4:t+=o(n|r>>11);n=(r&2047)<<5;break;case 5:t+=o(n|r>>10);n=(r&1023)<<6;break;case 6:t+=o(n|r>>9);n=(r&511)<<7;break;case 7:t+=o(n|r>>8);n=(r&255)<<8;break;case 8:t+=o(n|r>>7);n=(r&127)<<9;break;case 9:t+=o(n|r>>6);n=(r&63)<<10;break;case 10:t+=o(n|r>>5);n=(r&31)<<11;break;case 11:t+=o(n|r>>4);n=(r&15)<<12;break;case 12:t+=o(n|r>>3);n=(r&7)<<13;break;case 13:t+=o(n|r>>2);n=(r&3)<<14;break;case 14:t+=o(n|r>>1);n=(r&1)<<15;break;case 15:t+=o(n|r);i=0;break}s++}return LZString.decompress(t)},compress:function(e){if(e==null)return\"\";var t,n,r={},i={},s=\"\",o=\"\",u=\"\",a=2,f=3,l=2,c=\"\",h=0,p=0,d,v=LZString._f;for(d=0;d<e.length;d+=1){s=e.charAt(d);if(!Object.prototype.hasOwnProperty.call(r,s)){r[s]=f++;i[s]=true}o=u+s;if(Object.prototype.hasOwnProperty.call(r,o)){u=o}else{if(Object.prototype.hasOwnProperty.call(i,u)){if(u.charCodeAt(0)<256){for(t=0;t<l;t++){h=h<<1;if(p==15){p=0;c+=v(h);h=0}else{p++}}n=u.charCodeAt(0);for(t=0;t<8;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}else{n=1;for(t=0;t<l;t++){h=h<<1|n;if(p==15){p=0;c+=v(h);h=0}else{p++}n=0}n=u.charCodeAt(0);for(t=0;t<16;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}delete i[u]}else{n=r[u];for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}r[o]=f++;u=String(s)}}if(u!==\"\"){if(Object.prototype.hasOwnProperty.call(i,u)){if(u.charCodeAt(0)<256){for(t=0;t<l;t++){h=h<<1;if(p==15){p=0;c+=v(h);h=0}else{p++}}n=u.charCodeAt(0);for(t=0;t<8;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}else{n=1;for(t=0;t<l;t++){h=h<<1|n;if(p==15){p=0;c+=v(h);h=0}else{p++}n=0}n=u.charCodeAt(0);for(t=0;t<16;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}delete i[u]}else{n=r[u];for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}}a--;if(a==0){a=Math.pow(2,l);l++}}n=2;for(t=0;t<l;t++){h=h<<1|n&1;if(p==15){p=0;c+=v(h);h=0}else{p++}n=n>>1}while(true){h=h<<1;if(p==15){c+=v(h);break}else p++}return c},decompress:function(e){if(e==null)return\"\";if(e==\"\")return null;var t=[],n,r=4,i=4,s=3,o=\"\",u=\"\",a,f,l,c,h,p,d,v=LZString._f,m={string:e,val:e.charCodeAt(0),position:32768,index:1};for(a=0;a<3;a+=1){t[a]=a}l=0;h=Math.pow(2,2);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}switch(n=l){case 0:l=0;h=Math.pow(2,8);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}d=v(l);break;case 1:l=0;h=Math.pow(2,16);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}d=v(l);break;case 2:return\"\"}t[3]=d;f=u=d;while(true){if(m.index>m.string.length){return\"\"}l=0;h=Math.pow(2,s);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}switch(d=l){case 0:l=0;h=Math.pow(2,8);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}t[i++]=v(l);d=i-1;r--;break;case 1:l=0;h=Math.pow(2,16);p=1;while(p!=h){c=m.val&m.position;m.position>>=1;if(m.position==0){m.position=32768;m.val=m.string.charCodeAt(m.index++)}l|=(c>0?1:0)*p;p<<=1}t[i++]=v(l);d=i-1;r--;break;case 2:return u}if(r==0){r=Math.pow(2,s);s++}if(t[d]){o=t[d]}else{if(d===i){o=f+f.charAt(0)}else{return null}}u+=o;t[i++]=f+o.charAt(0);r--;f=o;if(r==0){r=Math.pow(2,s);s++}}}};if(typeof module!==\"undefined\"&&module!=null){module.exports=LZString}\n/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */\nvar saveAs=saveAs||navigator.msSaveBlob&&navigator.msSaveBlob.bind(navigator)||function(e){\"use strict\";var t=e.document,n=function(){return e.URL||e.webkitURL||e},r=e.URL||e.webkitURL||e,i=t.createElementNS(\"http://www.w3.org/1999/xhtml\",\"a\"),s=\"download\"in i,o=function(n){var r=t.createEvent(\"MouseEvents\");r.initMouseEvent(\"click\",true,false,e,0,0,0,0,0,false,false,false,false,0,null);n.dispatchEvent(r)},u=e.webkitRequestFileSystem,a=e.requestFileSystem||u||e.mozRequestFileSystem,f=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},l=\"application/octet-stream\",c=0,h=[],p=function(){var e=h.length;while(e--){var t=h[e];if(typeof t===\"string\"){r.revokeObjectURL(t)}else{t.remove()}}h.length=0},d=function(e,t,n){t=[].concat(t);var r=t.length;while(r--){var i=e[\"on\"+t[r]];if(typeof i===\"function\"){try{i.call(e,n||e)}catch(s){f(s)}}}},v=function(t,r){var f=this,p=t.type,v=false,m,g,y=function(){var e=n().createObjectURL(t);h.push(e);return e},b=function(){d(f,\"writestart progress write writeend\".split(\" \"))},w=function(){if(v||!m){m=y(t)}if(g){g.location.href=m}else{window.open(m,\"_blank\")}f.readyState=f.DONE;b()},E=function(e){return function(){if(f.readyState!==f.DONE){return e.apply(this,arguments)}}},S={create:true,exclusive:false},x;f.readyState=f.INIT;if(!r){r=\"download\"}if(s){m=y(t);i.href=m;i.download=r;o(i);f.readyState=f.DONE;b();return}if(e.chrome&&p&&p!==l){x=t.slice||t.webkitSlice;t=x.call(t,0,t.size,l);v=true}if(u&&r!==\"download\"){r+=\".download\"}if(p===l||u){g=e}if(!a){w();return}c+=t.size;a(e.TEMPORARY,c,E(function(e){e.root.getDirectory(\"saved\",S,E(function(e){var n=function(){e.getFile(r,S,E(function(e){e.createWriter(E(function(n){n.onwriteend=function(t){g.location.href=e.toURL();h.push(e);f.readyState=f.DONE;d(f,\"writeend\",t)};n.onerror=function(){var e=n.error;if(e.code!==e.ABORT_ERR){w()}};\"writestart progress write abort\".split(\" \").forEach(function(e){n[\"on\"+e]=f[\"on\"+e]});n.write(t);f.abort=function(){n.abort();f.readyState=f.DONE};f.readyState=f.WRITING}),w)}),w)};e.getFile(r,{create:false},E(function(e){e.remove();n()}),E(function(e){if(e.code===e.NOT_FOUND_ERR){n()}else{w()}}))}),w)}),w)},m=v.prototype,g=function(e,t){return new v(e,t)};m.abort=function(){var e=this;e.readyState=e.DONE;d(e,\"abort\")};m.readyState=m.INIT=0;m.WRITING=1;m.DONE=2;m.error=m.onwritestart=m.onprogress=m.onwrite=m.onabort=m.onerror=m.onwriteend=null;e.addEventListener(\"unload\",p,false);return g}(self)\n/*! seedrandom.js v2.3.3 | (c) 2013 David Bau, all rights reserved. | Licensed under a BSD-style license */\n!function(a,b,c,d,e,f,g,h,i){function j(a){var b,c=a.length,e=this,f=0,g=e.i=e.j=0,h=e.S=[];for(c||(a=[c++]);d>f;)h[f]=f++;for(f=0;d>f;f++)h[f]=h[g=r&g+a[f%c]+(b=h[f])],h[g]=b;(e.g=function(a){for(var b,c=0,f=e.i,g=e.j,h=e.S;a--;)b=h[f=r&f+1],c=c*d+h[r&(h[f]=h[g=r&g+b])+(h[g]=b)];return e.i=f,e.j=g,c})(d)}function k(a,b){var c,d=[],e=typeof a;if(b&&\"object\"==e)for(c in a)try{d.push(k(a[c],b-1))}catch(f){}return d.length?d:\"string\"==e?a:a+\"\\0\"}function l(a,b){for(var c,d=a+\"\",e=0;e<d.length;)b[r&e]=r&(c^=19*b[r&e])+d.charCodeAt(e++);return n(b)}function m(c){try{return a.crypto.getRandomValues(c=new Uint8Array(d)),n(c)}catch(e){return[+new Date,a,(c=a.navigator)&&c.plugins,a.screen,n(b)]}}function n(a){return String.fromCharCode.apply(0,a)}var o=c.pow(d,e),p=c.pow(2,f),q=2*p,r=d-1,s=c[\"seed\"+i]=function(a,f,g){var h=[],r=l(k(f?[a,n(b)]:null==a?m():a,3),h),s=new j(h);return l(n(s.S),b),(g||function(a,b,d){return d?(c[i]=a,b):a})(function(){for(var a=s.g(e),b=o,c=0;p>a;)a=(a+c)*d,b*=d,c=s.g(1);for(;a>=q;)a/=2,b/=2,c>>>=1;return(a+c)/b},r,this==c)};l(c[i](),b),g&&g.exports?g.exports=s:h&&h.amd&&h(function(){return s})}(this,[],Math,256,6,52,\"object\"==typeof module&&module,\"function\"==typeof define&&define,\"random\");\n/*! console_hack.js | (c) 2015 Thomas Michael Edwards | Licensed under SugarCube's Simple BSD license */\n!function(){for(var methods=[\"assert\",\"clear\",\"count\",\"debug\",\"dir\",\"dirxml\",\"error\",\"exception\",\"group\",\"groupCollapsed\",\"groupEnd\",\"info\",\"log\",\"markTimeline\",\"profile\",\"profileEnd\",\"table\",\"time\",\"timeEnd\",\"timeline\",\"timelineEnd\",\"timeStamp\",\"trace\",\"warn\"],length=methods.length,noop=function(){},console=window.console=window.console||{};length--;){var method=methods[length];console[method]||(console[method]=noop)}}();\n}else{document.documentElement.setAttribute(\"data-init\", \"lacking\");}\n</script>\n<style id=\"style-normalize\" type=\"text/css\">/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\n\n/**\n * 1. Set default font family to sans-serif.\n * 2. Prevent iOS and IE text size adjust after device orientation change,\n *    without disabling user zoom.\n */\n\nhtml {\n  font-family: sans-serif; /* 1 */\n  -ms-text-size-adjust: 100%; /* 2 */\n  -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/**\n * Remove default margin.\n */\n\nbody {\n  margin: 0;\n}\n\n/* HTML5 display definitions\n   ========================================================================== */\n\n/**\n * Correct `block` display not defined for any HTML5 element in IE 8/9.\n * Correct `block` display not defined for `details` or `summary` in IE 10/11\n * and Firefox.\n * Correct `block` display not defined for `main` in IE 11.\n */\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\n\n/**\n * 1. Correct `inline-block` display not defined in IE 8/9.\n * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n */\n\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block; /* 1 */\n  vertical-align: baseline; /* 2 */\n}\n\n/**\n * Prevent modern browsers from displaying `audio` without controls.\n * Remove excess height in iOS 5 devices.\n */\n\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n\n/**\n * Address `[hidden]` styling not present in IE 8/9/10.\n * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.\n */\n\n[hidden],\ntemplate {\n  display: none;\n}\n\n/* Links\n   ========================================================================== */\n\n/**\n * Remove the gray background color from active links in IE 10.\n */\n\na {\n  background-color: transparent;\n}\n\n/**\n * Improve readability of focused elements when they are also in an\n * active/hover state.\n */\n\na:active,\na:hover {\n  outline: 0;\n}\n\n/* Text-level semantics\n   ========================================================================== */\n\n/**\n * Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n */\n\nabbr[title] {\n  border-bottom: 1px dotted;\n}\n\n/**\n * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n */\n\nb,\nstrong {\n  font-weight: bold;\n}\n\n/**\n * Address styling not present in Safari and Chrome.\n */\n\ndfn {\n  font-style: italic;\n}\n\n/**\n * Address variable `h1` font-size and margin within `section` and `article`\n * contexts in Firefox 4+, Safari, and Chrome.\n */\n\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\n/**\n * Address styling not present in IE 8/9.\n */\n\nmark {\n  background: #ff0;\n  color: #000;\n}\n\n/**\n * Address inconsistent and variable font size in all browsers.\n */\n\nsmall {\n  font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` affecting `line-height` in all browsers.\n */\n\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\n/* Embedded content\n   ========================================================================== */\n\n/**\n * Remove border when inside `a` element in IE 8/9/10.\n */\n\nimg {\n  border: 0;\n}\n\n/**\n * Correct overflow not hidden in IE 9/10/11.\n */\n\nsvg:not(:root) {\n  overflow: hidden;\n}\n\n/* Grouping content\n   ========================================================================== */\n\n/**\n * Address margin not present in IE 8/9 and Safari.\n */\n\nfigure {\n  margin: 1em 40px;\n}\n\n/**\n * Address differences between Firefox and other browsers.\n */\n\nhr {\n  box-sizing: content-box;\n  height: 0;\n}\n\n/**\n * Contain overflow in all browsers.\n */\n\npre {\n  overflow: auto;\n}\n\n/**\n * Address odd `em`-unit font size rendering in all browsers.\n */\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\n\n/* Forms\n   ========================================================================== */\n\n/**\n * Known limitation: by default, Chrome and Safari on OS X allow very limited\n * styling of `select`, unless a `border` property is set.\n */\n\n/**\n * 1. Correct color not being inherited.\n *    Known issue: affects color of disabled elements.\n * 2. Correct font properties not being inherited.\n * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit; /* 1 */\n  font: inherit; /* 2 */\n  margin: 0; /* 3 */\n}\n\n/**\n * Address `overflow` set to `hidden` in IE 8/9/10/11.\n */\n\nbutton {\n  overflow: visible;\n}\n\n/**\n * Address inconsistent `text-transform` inheritance for `button` and `select`.\n * All other form control elements do not inherit `text-transform` values.\n * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n * Correct `select` style inheritance in Firefox.\n */\n\nbutton,\nselect {\n  text-transform: none;\n}\n\n/**\n * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n *    and `video` controls.\n * 2. Correct inability to style clickable `input` types in iOS.\n * 3. Improve usability and consistency of cursor style between image-type\n *    `input` and others.\n */\n\nbutton,\nhtml input[type=\"button\"], /* 1 */\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button; /* 2 */\n  cursor: pointer; /* 3 */\n}\n\n/**\n * Re-set default cursor for disabled elements.\n */\n\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\n\n/**\n * Remove inner padding and border in Firefox 4+.\n */\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\n\n/**\n * Address Firefox 4+ setting `line-height` on `input` using `!important` in\n * the UA stylesheet.\n */\n\ninput {\n  line-height: normal;\n}\n\n/**\n * It's recommended that you don't attempt to style these elements.\n * Firefox's implementation doesn't respect box-sizing, padding, or width.\n *\n * 1. Address box sizing set to `content-box` in IE 8/9/10.\n * 2. Remove excess padding in IE 8/9/10.\n */\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Fix the cursor style for Chrome's increment/decrement buttons. For certain\n * `font-size` values of the `input`, it causes the cursor style of the\n * decrement button to change from `default` to `text`.\n */\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\n/**\n * 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.\n */\n\ninput[type=\"search\"] {\n  -webkit-appearance: textfield; /* 1 */\n  box-sizing: content-box; /* 2 */\n}\n\n/**\n * Remove inner padding and search cancel button in Safari and Chrome on OS X.\n * Safari (but not Chrome) clips the cancel button when the search input has\n * padding (and `textfield` appearance).\n */\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n/**\n * Define consistent border, margin, and padding.\n */\n\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\n\n/**\n * 1. Correct `color` not being inherited in IE 8/9/10/11.\n * 2. Remove padding so people aren't caught out if they zero out fieldsets.\n */\n\nlegend {\n  border: 0; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Remove default vertical scrollbar in IE 8/9/10/11.\n */\n\ntextarea {\n  overflow: auto;\n}\n\n/**\n * Don't inherit the `font-weight` (applied by a rule above).\n * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n */\n\noptgroup {\n  font-weight: bold;\n}\n\n/* Tables\n   ========================================================================== */\n\n/**\n * Remove most spacing between table cells.\n */\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\ntd,\nth {\n  padding: 0;\n}\n</style>\n<style id=\"style-init-screen\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/init-screen.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n@-webkit-keyframes init-loading-spin {\n\t0%   { -webkit-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); }\n}\n\n@-o-keyframes init-loading-spin {\n\t0%   { -o-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -o-transform: rotate(360deg); transform: rotate(360deg); }\n}\n\n@keyframes init-loading-spin {\n\t0%   { -webkit-transform: rotate(0deg); -o-transform: rotate(0deg); transform: rotate(0deg); }\n\t100% { -webkit-transform: rotate(360deg); -o-transform: rotate(360deg); transform: rotate(360deg); }\n}\n#init-screen {\n\tdisplay: none;\n\tz-index: 500000;\n\tposition: fixed;\n\ttop: 0px;\n\tleft: 0px;\n\theight: 100%;\n\twidth: 100%;\n\tfont: 28px/1 Helmet, Freesans, sans-serif;\n\tfont-weight: bold;\n\tcolor: #eee;\n\tbackground-color: #111;\n\ttext-align: center;\n}\n#init-screen > div {\n\tdisplay: none;\n\tposition: relative;\n\tmargin: 0 auto;\n\tmax-width: 1136px;\n\ttop: 25%;\n}\nhtml[data-init=\"no-js\"] #init-screen, html[data-init=\"lacking\"] #init-screen, html[data-init=\"loading\"] #init-screen {\n\tdisplay: block;\n}\nhtml[data-init=\"no-js\"] #init-no-js, html[data-init=\"lacking\"] #init-lacking {\n\tdisplay: block;\n\tpadding: 0 1em;\n}\nhtml[data-init=\"no-js\"] #init-no-js {\n\tcolor: red;\n}\nhtml[data-init=\"loading\"] #init-loading {\n\tdisplay: block;\n\tborder: 24px solid transparent;\n\tborder-radius: 50%;\n\tborder-top-color: #7f7f7f;\n\tborder-bottom-color: #7f7f7f;\n\twidth: 100px;\n\theight: 100px;\n\t-webkit-animation: init-loading-spin 2s linear infinite;\n\t     -o-animation: init-loading-spin 2s linear infinite;\n\t        animation: init-loading-spin 2s linear infinite;\n}\nhtml[data-init=\"loading\"] #init-loading > div {\n\ttext-indent: 9999em;\n\toverflow: hidden;\n\twhite-space: nowrap;\n}\nhtml[data-init=\"loading\"] #ui-bar, html[data-init=\"loading\"] #passages {\n\tdisplay: none;\n}\n</style>\n<style id=\"style-font\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/font.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n@font-face {\n\t/*\n\t\ttme-fa-icons (2020-03-27)\n\n\t\t`tme-fa-icons` is a subset of the Font Awesome font v4.7.0 by Dave Gandy (http://fontawesome.com)\n\t\tand is licensed under the SIL OFL 1.1 (http://scripts.sil.org/OFL).\n\t*/\n\tfont-family: \"tme-fa-icons\";\n\tsrc: url('data:application/octet-stream;base64,d09GRgABAAAAADLAAA8AAAAAWHgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABWAAAADsAAABUIIslek9TLzIAAAGUAAAAQwAAAFY+IEkIY21hcAAAAdgAAAG8AAAF3rob9jFjdnQgAAADlAAAABMAAAAgBtX/BGZwZ20AAAOoAAAFkAAAC3CKkZBZZ2FzcAAACTgAAAAIAAAACAAAABBnbHlmAAAJQAAAI6gAADv+gJOpzGhlYWQAACzoAAAAMwAAADYY1IZaaGhlYQAALRwAAAAgAAAAJAfCBClobXR4AAAtPAAAAJEAAAFMBfb/0WxvY2EAAC3QAAAAqAAAAKhjiHI5bWF4cAAALngAAAAgAAAAIAFjDA9uYW1lAAAumAAAAY0AAAL94+zEpHBvc3QAADAoAAACHAAAA11cG/YjcHJlcAAAMkQAAAB6AAAAhuVBK7x4nGNgZGBg4GIwYLBjYHJx8wlh4MtJLMljkGJgYYAAkDwymzEnMz2RgQPGA8qxgGkOIGaDiAIAJjsFSAB4nGNgZNZgnMDAysDAVMW0h4GBoQdCMz5gMGRkAooysDIzYAUBaa4pDA4vGF4EMgf9z2KIYg5imAYUZgTJAQDSIQumAHic7dTVbltRAETR7dpNCikzQ8rMzMxt/M39mHnsU1/TfZz5jFpaV7pXJunMDLAZmOqaZjD5y4Tx+uPTyeL5lG2L5zN+L94zG8+ztr7ulXH1fra4bvK9M79xiWW2sNXPbWeFHexkF7vZw172sZ8DHOQQhznCUY5xnBOc5BSnOcNZVjnHeS5wkUtc5gpX/f3r3OAmt7jNHe5yj/s84CGPeMwTnvKM57zgJa94zRve8o73fOAjn/jMF77yje/84Ce/WGPun1zi/2tlXKbp3Xyc44bFyZanSWokJDXOOjXSk/LUSXn+pEwCKTNBaqQqZU5IjX+XMjukTBEp80TKZJEyY6RMGylzR8oEkjKLpEwlKfNJyqSSMrOkTC8pc0zKRJMy26RMOSnzTsrkk7IDpGwDKXtByoaQsiukbA0p+0PKJpGyU6RsFyl7RmosQcrukbKFpOwjKZtJyo6Ssq2k7C0pG0zKLpOy1aTsNymbTsrOk7L9pNwBUi4CKbeBlCtByr0g5XKQckNIuSak3BVSLgwpt4aUq0PK/SHlEpFyk0i5TqTcKVIuFim3i5QrRso9I+WykXLjXOYNzP8BuAPUwHicY2BAAxIQyBz0PwuEARJsA90AeJytVml300YUHXlJnIQsJQstamHExGmwRiZswYAJQbJjIF2crZWgixQ76b7xid/gX/Nk2nPoN35a7xsvJJC053Cak6N3583VzNtlElqS2AvrkZSbL8XU1iaN7DwJ6YZNy1F8KDt7IWWKyd8FURCtltq3HYdERCJQta6wRBD7HlmaZHzoUUbLtqRXTcotPekuW+NBvVXffho6yrE7oaRmM3RoPbIlVRhVokimPVLSpmWo+itJK7y/wsxXzVDCiE4iabwZxtBI3htntMpoNbbjKIpsstwoUiSa4UEUeZTVEufkigkMygfNkPLKpxHlw/yIrNijnFawS7bT/L4vead3OT+xX29RtuRAH8iO7ODsdCVfhFtbYdy0k+0oVBF213dCbNnsVP9mj/KaRgO3KzK90IxgqXyFECs/ocz+IVktnE/5kkejWrKRE0HrZU7sSz6B1uOIKXHNGFnQ3dEJEdT9kjMM9pg+Hvzx3imWCxMCeBzLekclnAgTKWFzNEnaMHJgJWWLKqn1rpg45XVaxFvCfu3a0ZfOaONQd2I8Ww8dWzlRyfFoUqeZTJ3aSc2jKQ2ilHQmeMyvAyg/oklebWM1iZVH0zhmxoREIgIt3EtTQSw7saQpBM2jGb25G6a5di1apMkD9dyj9/TmVri501PaDvSzRn9Wp2I62AvT6WnkL/Fp2uUiRen66Rl+TOJB1gIykS02w5SDB2/9DtLL15YchdcG2O7t8yuofdZE8KQB+xvQHk/VKQlMhZhViFZAYq1rWZbJ1awWqcjUd0OaVr6s0wSKchwXx76Mcf1fMzOWmBK+34nTsyMuPXPtSwjTHHybdT2a16nFcgFxZnlOp1mW7+s0x/IDneZZntfpCEtbp6MsP9RpgeVHOh1jeUELmnTfwZCLMOQCDpAwhKUDQ1hegiEsFQxhuQhDWBZhCMslGMLyYxjCchmGsLysZdXUU0nj2plYBmxCYGKOHrnMReVqKrlUQrtoVGpDnhJulVQUz6p/ZaBePPKGObAWSJfIml8xzpWPRuX41hUtbxo7V8Cx6m8fjvY58VLWi4U/Bf/V1lQlvWLNw5Or8BuGnmwnqjapeHRNl89VPbr+X1RUWAv0G0iFWCjKsmxwZyKEjzqdhmqglUPMbMw8tOt1y5qfw/03MUIWUP34NxQaC9yDTllJWe3grNXX27LcO4NyOBMsSTE38/pW+CIjs9J+kVnKno98HnAFjEpl2GoDrRW82ScxD5neJM8EcVtRNkja2M4EiQ0c84B5850EJmHqqg3kTuGGDfgFYW7BeSdconqjLIfuRezzKKT8W6fiRPaoaIzAs9kbYa/vQspvcQwkNPmlfgxUFaGpGDUV0DRSbqgGX8bZum1Cxg70Iyp2w7Ks4sPHFveVkm0ZhHykiNWjo5/WXqJOqtx+ZhSX752+BcEgNTF/e990cZDKu1rJMkdtA1O3GpVT15pD41WH6uZR9b3j7BM5a5puuiceel/TqtvBxVwssPZtDtJSJhfU9WGFDaLLxaVQ6mU0Se+4BxgWGNDvUIqN/6v62HyeK1WF0XEk307Ut9HnYAz8D9h/R/UD0Pdj6HINLs/3mhOfbvThbJmuohfrp+g3MGutuVm6BtzQdAPiIUetjrjKDXynBnF6pLkc6SHgY90V4gHAJoDF4BPdtYzmUwCj+Yw5PsDnzGHQZA6DLeYw2GbOGsAOcxjsMofBHnMYfMGcdYAvmcMgZA6DiDkMnjAnAHjKHAZfMYfB18xh8A1z7gN8yxwGMXMYJMxhsK/p1jDMLV7QXaC2QVWgA1NPWNzD4lBTZcj+jheG/b1BzP7BIKb+qOn2kPoTLwz1Z4OY+otBTP1V050h9TdeGOrvBjH1D4OY+ky/GMtlBr+MfJcKB5RdbD7n74n3D9vFQLkAAQAB//8AD3icrXsLcFzlleZ//v+++nb37dfte/VotVrdrW5JltuKpO6WJVluPyXbsmOEbGRjO4KVjWPZlsM4QIU4IYGlgCE2yxqKIQkJg2GreKQCTCZb1CZkiswjzOwOmSTATNVWTZLdDUwSMrVDsomD23vOf69assFAqgbk+773P4//nPOdc/5mwNjFl8WjosbaWblmxiOmIlTGYXzb11M7Z2ohAMbZCcZ5iG9prZl4whfwGju05xtttitUdwXYEUgkbQtWga5lC+XBaqJI285qpb8dVEc8Gnm5L5QM/f58yAlB399a7dD0mWAmdAqaMvBmKPKX9TdDwSjod9yhx03FAPcvI6Gk2lV33XoXUtKgL8C6Wa0WSzXbVjhg6JoqIPShCK0FOvOuE48K1V4B1VUQAVevugmP7Fz2CmTzW5/8+ZGP/+Kp7h/8oI4MuOZ7M5B9IvujH2Wf+PnCAjzn8ZK6AieMKRcvXnxWWSWCzGARlPcqtqs21WZzEBFgYIVDAYWzVJIrXBlH+hXGlWNM00GAJmYZ8sKBzTJFVZVppijqDFMVdTIWLa0o5JrdaHusPZGIG1IjFhQGK2mAZEe56kJnR1bTY7ZT7eivFGODBTdma3pHtlCNDVbwmgMHx/aO4R8ffeet5/ZCG6TfuV03IaSJU3oIzKsGO9+5PV+BwU5xqnOQx1aO8fW71yvD9fPn55/fA22PmsaFvfSgwZ8wzPiFvZ2DUMnzJ2hHVDMmHucPsSRrq7UQo4DMAV/AW7CANw/Zru3NIx20bBEpXwukArlxxOPReibaG63/SyQyiftzcBy3k1HuOHgjEgFHnkYfh4VodDJC4138Ff8hv5PlWbrWmm2O6grNEgGNCWGnbFtRm1Z04gzQPPWvkqMWF4eWU8DB267Df+gNe84bBvfRpfNI5Ny5yAmHDh5/PPLuByMlekDS9DsRR73nWHetwBShSO5PqCBQONO4E2wGlSvYZG6gMzeQ09SWFZC0tWION3oOVVXGTbGM+hrAzQj0O25yoN8R8YzzRsaZdzLwhpsGPEm783hAJ9+kq286eDX5pn/VydDjvk7i8EuchU21JJ3DNOqFzeABmywPcNXxhu/wB+3whrqwVw7Cn1j8vPfdDH6O7PR3fDV/Cb85wua/waSit309grZJHHOhHEQ9CA7zTGVCUb0ZvXzc1lrRe5Af+4An0aSL9op0IU9y6vRFtAYGKy7KJGFbQrdg2dXqGAwWilld0zUy9xLqd6A/zeFuy7gzYFmBOwOhZ6NNhZakm8YTI7S1pyM1mM032V26qevXGlzZ8+TKvROlB/BBkO9ACDalB7OZuBnuC5tRcAItpalENNOfhajVH1A2a1HjbHZ4N4r54oWLz4qPoe4jrMo2sonapm5QRQBQ3XycKVxwRRxjQuVCnWc6mrzOZ5FvBiraOmia5FubYRpok8n0ioRTKOQMNbWiszxYWAFZrQ1sB+dDJTFYghzyiBN3oB857ndIAha4Se/+YGUtjAkXXUO2xPE2eoe3TWPeMOXmzNi+j9w1HghvVbSAmu4c6nFac6MgbzXFU2baDr1241+98TfHtU/9t7df+MzU4msmfPYj06Wbw8Gqohda0/FkSyiyvtPGG/FsMKq1pLqmPvndkye/+y+08eYIHEJZpFmJra2Nop/VWuKcCwPvgRhnGlOFps6iIdAEmFVAKh53jblZyBU6nAFdbfX03tGwioZ9oGnEyDSWTQCyFzhoR+s/jdjgWLmc3L2K21zEmXCsM5aDm4g9Ny5v0PZVb+dY9Rcd/sl5eTiPj0nTaeiU+BhhW2qbuzJcUy2Nc2gCrjBkxWCqZiArGgOuwSzjAlDb5L91XfpvfYbpij6ZRIUWYoVcLqC2+UqNLddsMrekY3GZztVl2uQjpl4xjedIM+Uybc/r5viShuHgcgXuwQtpuoMHz8utCe/s8S+Y/7xMaYu2DX1yDrez3lp3cyyKdop+HLcLi878Uh9SKOSlj73cOIUFRVKVKHhaSS9JP452RCcYoJ3w85bz8Ckp9VN4xeZj9atpH4FnPCV4OtiDNIVYCrWwsbauK81VxUlaQnA+riFBisoUsiU0LbQpASCmmRAwg1MNJoH19uQ6WpriUV1jIQjphA5QjosiTfiy1tF+kPJKMTFYpAu6lkx40odnTv7VjYtC/QtTJyGH9HmMnKamGrcaqmaagRsMUwR9WeLmwsQREvIRevSvYa8uVFXo9Sc0w5A8/Rp5+jcxhXLuYAOIx/pbY+ggFp0FV8lNoLNAEQvyDkwBZR9T1ZC6xR0qFgsybix3DJcR7iIGwCsCHHQM0nYKVSBXQZPnqG7KDZiqrn8K524gpN9ghAx42k4GsvF3nohnA0kbnglkC9mrl7h4Db2TommKcVE1QOPRd97K5WJxsKO5nIjHbHtx/og3kK8iWys1he/EkKlqCbFOB6iKQp5Q5Yp6DB0AsjmPvHEFSGsoFraPaVpI2zLc2lmudErjJ/eeQwbKPoRBZulcwhwXYc6i1SdiEpiCF+KrFOIrAzKaHdhQ79tw4MAGuJv4rt8sQQu80jloGnnDfNVJBa+vn1WjSg1d8NHrg44FbTgdJ5+T77yy/gDI5wY7633yTbI7+CdyMDyEL2paDd0BvZjyfIYXH2/H+aqjDfXUisgnk3rFYMePoyZBegWanQpM5hKdlUSU1JnoQH2iG1d90IYADi0JPV2/oxMEeB7apm+aBngFw/ObMjzHzv7dgzyOh48fHZnmO9c8Wv+2RAGwHiP20UNnzx46mvYxyaMixDpZX22lQqQgRDqG4kYcMo92cpypAOo0Ti+iSYXJRGc5l8wvQhPfqpE0SYa7nDwkeQyh26OOlbecqVumoCwJ8+mDm+9/5T4eOyOt+4wk8WjavYTIG+7nD5Li2cWv8zGkMYoz51q2u3Y1JQSwfcumSn9JUxW0CZIWQ5isqKCo8zoGFPybx/lyHD2w4AaCBw7Ap1HIxAaHyZlr1tXG1owMt7h5Ox5QmxF4Iv6vDhaQoTFAYADuYIlnLa7b7RwtiOBDtVK1dbyCMXXxn5azOIIKfLFKaQP9K3HKIMYEQosvhkIWH23TQ9wIpCq9M4WxycnJsQIUYrEJ/bPGuOZohfHVzdmMaAmHm418c7DU3xdoyYPebFktPJtpHu7fefjw4R0VHiNTa06ZUTPe09a1sdTUVNrYtbo3nth11VW7tBa1d/U1a1t71rdG2u1IJNkWDYdbUs0pnnFT+OloWzISsdsjqVpvy9prqrNjed41POfPx2+J7TIXaWP5Wgf5bvToBEvpppQYOXPOJoda4gTQE6TsNK8sAvUSSHBFygfnfM9wL+8aK/Bddv0tZ8SufyKZ7ml7s20iCWdsPpPu4YVaXuur/2M6WX8riReTE21vtPUAnn4iyTxdf0vJ+/QM0pwsUL4D5BmUBQEeXpaU4W6RtExzN1In7eT9qHPpIoUdqAzSrdyHIPo1JNRps1uioCWJyIm2U/JG8oO4aZMXozF8b4RupRd5JJv7Nn8ZeUyxjlrakhJHcwO2gHMUDgGLR0MmS0GrIoMRWos0K81LUnPZYgmkw6sM8HtCoQTaT9y0Wu3f/MZuCYfijhMPhUVQNdL2hY8kMroS/8UvEqqeSfC/xzPV07k3vsqyrL+2ykYnhJjEz45OLIdbu4ncrbrWhImzltU7oqqaXAEdMWiHxPsSdvuF70K6/xf6FejjL13YBvFVP+UXrkwnyelZjBcltoLypQIoEmsoiDUw4C2QFS/I/J6yx5ybWOOqaMad0kJlKo+ElAdLqvRTMqOsgucuM64j3hgHU1H1mIkQ084Oje3eXT1lZwL1nwaD0BZMNfFTcHpv+sf7v6LEo4oZMlRbFNqH9tb60nEN0UkQ0mYawZNpR878eFuD1lWsl/Jb9J5iMbPlDKnkh3raBmS66U1M9Jm5rKUmMel1dKLOcxrVSgf5dJqU4o0g0pJyTlV37x4bytpCATOG8VUT4+m9cPoURiakE34ZMes/wbB0Roun+2p7h9oLSlwzQqZq2eIr+xe2/Rhp5QF8hHn5Hh/FfM9ibs32UrNG+l22ZbrnJ8N+fERAcD6YCp6nuPc2Aq/vWXiMfzKaye/BDfzTLPwe33MT8ns4P/y0uiLBdyZw3qRvNvGZegjF6H+escXvreOnkD7zm7IkADTbJEkU4sdw1jmwzpTj42smHLB82ijenjfx9YsXkccR+B5+I1azGtQk+4maTpnLlsBL75E7O1IPea+mzfPmUwQt00FJoG+nPxN/zruZzZprTljyx2GpXiHdYWBZtcINeB+2xVP16/GT9euDwf00TbqgK5gK7QvCmfp/wPn15WDa3BcM1l/Hy8F9wZQ31nf4Q2IjjrXyG+BnzXnMmqXiTuB5CLa01gINjvb8mesSTwHuSAEtzm8anp+uvwbdprkfhUs0wCNIxH6TP1l/vf6aPDThK0TXI5I+tjj+SX/8wIcaPxWX4y+CqsCiEIiAIzhsKrgfh+6qv+4L4RETPl6/zqMKukki9AA96OseZb3Zk7UKVKxZKt65tpR1J9p1sTGgP5Z4ah+KEzl73R/xEfr+I8H5fchlN/Jr0n0c3fSGkrz+vbhd5m2ZWltThDeKUaKh3WTZXWauS+WomBdMkjGvOCRuT9YfcIZxk0x24/5cT3q8redxe8TpTsLn03b9LIaFo/I0eQ7uxtjQm6rffI4elnTcJfbwX/qRFyG+Vw+SaJdyFIpugk0WXCcnaZFo1323viNAWHZPvk1+ugfjTf2sbcPR5LDT442bhwPj6Z5z9qi9wr8B85Ji51yXb3tISxlpSUtaZEYnFX8ZbHI6C8vk4ll2h5/YdRQbM0CUbSmXHsd5rH5zWz7fBnc/5iA1NLANwyQZ2+5JjiYfQ4mle+BxJA1prT9g+770dv4zTz9RnTPp+JlY4DJKoroOucmyT4fnsGIeFC3H9EtmB+qnGyP6413tPvs4BhIwipskDKakeIg+KKTgbl92JBkkHn1J3c8t+9ia2vBKhMFkGBJtEjrGDIzKE1SeAgTJiDAVRYpKmSGwMlksJor5gUWgjKlXYS0gurS4neaYflXJnaWBUjDKNAVhkWoF1WhHz7uJ2PapE8NHJkulySPD62/qVmLapMq10a997JqvnphQarc8dO3UQ2smYr38pfOWszK6fTs+eBKfHy4j8t2uWNrWnbDx5CNfe+TkxrHVE/EEW4ynxM9H2FhtpAeE2tnGFUH1J4xXChxD5hACLNXbLgOA3WU353rI37Y44SipbwdxwED/mEC0rOmuIzmlGkw7SBzNxZ6NN3519+zXRhV1Uosp3TdtGD68s4eXJo8uzHVtjyXc85gC9MYmRh+euuaRk+vhAG43Tm3RLGW7Clp52Oesq3N7dKVjnW9KxCdWjyFvi/nUs+Ja5CnPxtn+2t4NnVwLrELw76JqDMz1MacMGJoR0I5RVsA1lR/DLEdonLJLQWnOMcSamKlrszLnWWZ3mzcVOjsrnYWynTfVNmQ6aQFxrWtL9SQtgjqsojbxf5lp+qquSF1rVGyk02qZZEEKRkPdlv9ff3LVQ6MTFMas8xSft3fNVbd+vqg1KaF5w7RwBsirUye24UVXDS3oIcj/nz+56mF6qQlUAQ++gGoNytcxFG7P98DWMXMoHIL/6l/Z7p1riv8ko2oiyiru129WsSrmUjO1XdtWc0Pr7miOoWOV9YUQ07WQPmsCisWYDge5puAUAI3NIk6EQACmaQ+BGRaAwOSemV1TH90+vnlDrZBNFOi/nEUlLL96lYx5VZLqB5zDQLFQzGm6KuUX89L6YqxRuaPsCwXYTlJE1EVJt9ycWTo8bereoW7Wv38ewfOzmgI/N42Kn53LatjTxUCv85zbEyg+Y5hTcDddq99M2ysc8/51lABfjZ++8KvSxvUlnpCj7U+mIG3vR8yhXSbXEbaB3cDmatdds4lrhi9Z8hskNo2hkI+RQHWN6fMIUwKGFZiNhDmCNq6BoR1gejCoTzNdD86woB6cPDh33YFr91w99dHJLePr1tp525NylKZkzJtthLplN+ADzhOxjpiN1trRPwb/vhKfqIcMg8Mr3DDqd38o4cM36y9KWa+Tsn7v4/ocj134Vcg2TZsf/ABFKH4tYwrtObZYYxoF3QiQC+PjATwUho5+W8MkQlOOqUDxnlMNjZpsfB8zjJCxZe2afKeTjXeuboqT2XcOlsACB6XROFhWch7AeNy/VsZfx4fO5Aj8EjTVRPjLdtrmTS1NX7Azce6kmjZnnHf+1iuBiG0duzsmQTiZPzfjEoTGAqZ7xqt/nmmai8gXOWb0/sG9z8vyyPNOZjKDf9DlRgmQR93keVlHOU/9RTkfH8W8ieTQzWpsc21DGRM0Xw4soAUWDEDPtMB0oS9I5qeXC0PhMySPyTWjuYFctn9JEgWLp6FSXdz71TeSgzuQBmnXVHPXGqWhIhXkF+H2lQXxVqiSO5OthN9CQQSazmBOhdycwSgoZRJvQ28Yz8SVltDiwd3PUxMLN9De1dWehinH5783RvA9xhpyoHgnWAfGvE3sqtqOFT25rGIoMB4GBa0NAaepg2KYyiwVijQqFKGtopEeUFFYgQCboj0jZ8cCk7U1Q2W3MBBLjMRi0SCKxO0od6gD6Muon6Q35JGLDZS9DEpfLNZTA4aqrmrD0rwHCAO8Cs/Ur4a3J0Lql9WU4RfBJiYySfg+cviqaczLvipt59LuhbjXflPdSuRLUUd/9VV422jRv6SF/NbehYrcQ1p2AZ6jd80L5+kSRwE3WV+OVGTs9GvnU6yLDbJsrZ2aE+iijskqPtuHgTAktgz0r+xtaUaslZRRH6FKlRJrBwO9bK+lef8YXipg7j8GSJjM+GRPmSApRv6n//T4VrH3qqbRaNxoqoxSNMfwD6MV18yPulftrX+xZ7gXeka7vMCPgf2aQ8+N4bPuaKz7lg2LIGjjTT3x4T4jvubPYKL+cFtPTxscwm0DA+yVNaMjbFNt/cE9k+sUpoxgas8Gu1qjhG7GqUu+oAFel8B2gTDcgt+54If2XXv1VVsmVvRkM4m4TnnrYCGLtt5foc4F2rWO/NrIbxENvBHUy0WJBYqEg8hbyklAxoATvupfHMCZ3wAHaASEAFz/Y7pUPh+ZumWK7z65G1KGftgMJro0NbIzrOvbm1sCuhL9tBGKtrof1aLaZkdRjS4zYhzSDTDVw4bldnrPGtubWgKGiH0adR1JuR9VI/qErSgB72HMk0emp2+anr6F7kfTydZ+zdKSO0EdDRuTqaip3xAIjapaLa1aWqg/kmqNQEiXzza3ZFbqId3euezR4Iiqbkj5j7ZEIeTX7X4n9vLvLmKL2mAXILVUp0WPoyLCVJVGQ+/yNlGhjP8PNLq4y9vNy9rPrn+eW36OaPmdX0nTF7EIpu9XPlvW1XMgOiHbSHIL1ji1nsbpBdbAyXtlTRwjSHuCqyJvkjfAVEiMe317oeLEURlNKa/CI7tfVLxLp5qb4tFwUFVYJ3R6/STHqy1Xi1R9RLvvd6lSPIba14rZoo6zwa3w/7L18OGzRwC+N7B52+HD2zYPfA8OP3iIH9kyjkd4Fdwj9x85skUPzfXhQd9cSN96mB+97yjgoYUXvZ7kxYu/UW7mL7Eo+rwKK9byTKWsSWWz6N8VBaZxB5ShgDJZHerscm0J6L1at2fNGPH4CqQNZ+gAGTeaPZVNBB52IJ7nt/uI3N/B0707Do+8vmEH37rpdTLX8eEDd47Xr564Y3aIj+67azM8Q4dwYHjpHbJoOu1/8OkH++lk4s59Y2Lo+tsevG1ukA/N3uHb9f9TbkFebNRET61I/GEuOEtdCkxKcdfISpPptmSn01kdVNF4Y4NjHF1rWnh0cxWZKImsJdKcKPPIkZR5RIoYkcJ7dh665dDOHqV/4jgc2ILXkYz77zgwypGsH1zKst/L+ir6nJVsPdtR2zaC4aQTZC9CR4p0jigDQ6gmexJcUeeXdbS0xY7WslzDdpPF8uryAPX0L+tqoVNFD5QrFi7rbKGXwYnkJGCpwra4XMZe1th6JZcOCL0VgV445HepqL+l5jVdKMHP1VeH89a/WtYaK2/9Z/g4noyFYduzjf6WpSS0FIKDRovrC4aaQ9ZArQ9b1r/K58P0Yhi/4Msl4WPhFbUuzCTBb1OitsjmCVsAn+Qs3eokTJ1FeEQlI1nGXNlfnbS8tcc/sYz4wU8vsbd+lr/UII5u7mncOYBJ+WKc+5jsETe/L03AXCfmN4IlTVnCOYiVSxyWr5h45up7d/Lpu568c7ey4zRcu6yjzk9P3Xvu3im5qb9yaf98ab2AwZIsy0Zrq6nXxkG22zi121ScGiC71IoiZwcZqlAmzUCmvaU5GgkkzaQfoNCjlKimWnxvGhtR5b4r0roYFX59BZLFsvVB5NMRIVAGQ65bJoBsRuaFbLJM/0n3nZCLlZaWYKj+efWy88WezKv+yiG5dKnN23mX2uUJbi5bY+Rc4XgxBrHXGnlYb637gwLPEuXVBmD1ViiIyzgRfl5f9NddvfoB9NDxw0clWD9KV0FbdhMMjzfc+H7uJXEG8fo6Ns4O1q5fU+KCCq16PhXG3JuJcczFw6GwEaLSBXkQwNwF4DgLs1AgHDqA2FToAXEgCDpj+jTudDaDgUmnGsaG9bWx1UOVctJGzBlDf2HJWgZyh1HHkeV53RK5WC6Gc8fr45AzKSByxwlWHShTsxydSgfVLhALUZsXOiS8w0TlVOdJ006bC4ZayA43j7cN9WCqeCgYDTvGJzKnKG0Jn7ou6KSC18Frs8FUk2Jch1frv65/kWLdMMbf2fWfDKac4HFdaYpb8HY9ZDXZhnEylEgHP7t2L6YMcO46M22b111HA113zoFBDJQUpy/WLx6B36K+MxQdmlHBKerm0BIJKqUu68GgoLY0VSpexdChJiDC1WpC9qwK1cQYpS7U0BW0JAzeMrX6P+hRI2Dy4z/hqqmb4gS3jG8GLT77P1Ue5E4wfOFTFoioAS8NYVYZhv9umJapaPV6hct6wHdkHiowcqVYnvUivt5Qa+3vK/X2dBXy2Uy6pclBE4pR4XkwxWHTtq93vH+tv0l2U6pFvbNRePWrv51uBFbBWmgHbw/upXv+0LnRc1AxL/RjLrVgmvx/yP0Fq1KJxarV2A+PHct2HDvWwbvxJIYX60/THfzHrcdGH7shQm/iC2l6E/fXRumtaPU/ybeyx+p34UkVL0LJv9PAUHOomzL1w8q9uZaYoV3SIOoujHBKKii60eKMxhJHXUMgTQW0InVqqErq22AbYN6BHOMkFCMtlpWLDDc/0NM23tYLZ1uGMX5ZrWfPtkQj+chQ61lZiH+gZSiai0Sbz4JhDbeswXd2PSVr8E/twqtr8KXdu690Q2KpI6jHMMuhBjdRdbG9iQslEae6YVhDV7gBdOiHgK4iKtSERkv4yOpAP8ZMpimmNqtSRuUFG50FDD2AeaYRNrasGS0P2LTwuGDncpRJNtZ5Fpev85SVhMY6T3ewBJrtjAFIs8XZi95eSXOXLJkW75wKaXmE7afkst1TsjBDJxP3v3I//kG6Z9R+ce7WnfcfrvHRo6fPnT46CpteTMJZ7yXKMb2XTlHieMpspgUYLz+k3UsJV/LFTWNH7vvT08eHlfWHHtx+69yLSbZMRhHWhDn2SG0oYCC3qE/B0qAKuZqPg+b5XkErlwWmYkKlMkNY2eLmUAqF3OJinmKjrPIhuK1/W/IJ6z8kh5K1D2aK+/UTWqOzkz1fC4xVOgKKKqgjZqKV9nhTGGOgUGnZjiK4Mq8jJFKOMwJ0UxSLdlO/Ymvrtq8H3/UG+nBNcG0e7Vh79xt/yOf37KklDMPYaeyc3LZ1y8hwT671KoP8BApooL9agOqYUm2FATeRptTcdeQGxexmC3pWyw2u5ZSr4l9xsLCKW+DaaeqxVskXZql+XdTggY9NDrcHk331MoTzqZSj3fGlCe3GxJQT6IsGjeBkQOGQO53v+VKSb9E1EVMQ5vKs2/R7axiimWAmiVCh4/MZ1eYrecvvMWx9oa71KppmNkVhBs6G6m+veHkw8amOFi0QFY4pTI7RrikRxSd1jgBaCeytDEHmYSsUN/HTEEyqQVQ6ppY4937ER/nPmMXaWK6W8TvQy1cj+s28wcIlS70LHqQsSoS5rB18abP70ubwv0VMqrRhJALnb2SJXZ76vg7pAPc9++oF2+s8XzLyZUMt/3ajhy35encPGy4n+lIy4Xvvou1JERMJFmTa8zqHldSwlaBa9k6VC63heDzM/3cYttfndDMiKlbIwCN7eV2F8FS61toUNZhCzHltUoKChwg/yah6WVnr8jIXJer+ultoizj14CWn/GfvvEU5uIjTdtnx8nw86K1TlzWF5QsXBhYXGlw+3rLk/5IB/G8+gzZuYUagPa8ByoUaWfiRIuA35I4CrJOMVariLtOCaKD+Ryq3gvWTwSDci1AAfVtQi7zzsmWE4F5Vq/+RPKDe8714vX5SVSVGuXjxa2K/iCyN42qyOkbLkXwt6FIjmt5sRsHC11VB2yANZQl1HL+GWjFC9Em4Vx7Q2oKTeB2+oKkeL3xEkBU015zWlri4VEBrpICIlwZ7Eso2mgSVKs8GLeJN5YsLnmn7Lh7/45KS6ncSg5I/Por8NcaWi7UW27Te2JeyTGPqPg3VS9j2CzJyeznjn1qaGXCrpsq8ro655n7+1zi3WwkBRkGuRl5e3eMyi6L0TvDJcnYwTnM14fWG5Xyh5nXVLya56BmNJRUi25oYoiGRJBGXdaO+Rb1Y9R861mlZYzodsf21K8/wZ1mC8I75Hr9viTsF+fsW5BzxTSO1IFQNz6DJvnC/lPv9L6Ab4KcvfJU6gC94y9NfMP31s7i5XY5RIn6LJqKRxjAKDuOVppiQA65ycUhaEvVeQya8dVuF6uCYKClVFADVGd5FyGt9RTWAAgg50ahiNFm2YkcCarHv3QTW/6Jna0TY0VA0FEpnMkbciKJ0RGSrrMN/XzzKfy7p3saOsq21cUl7FVQ2Dboqxg8D38S4hnxooL2bGRU1qurqAtP1Q1M7xzd3Sd4MKlx9aN7cxtWq/1OQAi25ohrK0s0ilVHwbgmKVNGWD1T/IMmcmd2u68h5MhPsLpW6Mf7ZEUPfceC+0zfhdXy9uTm5cQffujnZrMQFzmZdv+n0HyDOnl33Z4RjOcFoIL338N50IIpBxBEd9+2+7fV+vGGHQ5Y18NCTDw1EwkITYRu/JwZe9fPMI+IfxFUsyjbSqvKhAcwt168pdedsTBbTzZxTnRzRxQyV/if8uggP8y2VcpqWw7iyTmgJOy3GuEu5oK35P5xC0L6GZFag308hopD9/6r3KyoE7rKG5Tqi3D9z8s6TM/3+7mEeeCxiPDanxdWDjxmRxwKIeebmVFVePajGtTl5VaWLcGDdLdMVpbTvxD0n9pWUyvQtew1RfioQFOU/1vU/Lotg4KmyMEz9nnuM2OINTVu8ETPuuUeXPuNZUcFYEmd9rFRbYSxfVUjLiN9dFerqyvd2yKWFBEEB548Fup3m1PWnBQHUERnjyKYur0O1v1pBfvl30u2Hnj4EwydOw/CBOyd23vd4+YefpuUbvHb84elmO9HXD1P3Tq1f48YM5VZ17msH5/d1fPtmWQndeOwTd1EnZNeXbtwsoBRbcbJ29T3T0GbGDO+3J95aen6KxViWDVCHL8i5wsPAxPLfE1FDb55RmQnmCYgrEoijOyX+6KeDoE66Tt5ONjkSgheKBA9LqL6qpqchU0E7QaSYtJ3+irSVimrrmpLJU3ej0gsK6vTRXbdlEXtnb9u17Z9B+Un9m9Hg5rmoE93YF4zCPwZ31H9b/6f6b3cEgzvAgAIYO4IwfMe64Q03nOX3fXzD8Lo7brzrLtiCz85tCkajwb6N0b9LJD738MOfSxTs2x7mj3yGsEgjzzBYB9Xw2hGCYAZOzYWG2uR6nFlvxlJeEZfO732ziNsX84be4ffMGz7/gRmQb1dyTX8Q/dtArU8Hb8Wybmgod53NBlQOilxbg9mPCIstK3sTAzE7O5BMJuTKkvJgwfulBskXM0CBMymXLQrpkSoDMVmJ6aA2QjGG4SJkRk38g5sd61dtYGoQ4St+jHY+U23r4aVWOEjtseoMnDgvfwCEm2+hp6r/X91AK4zYkU3HMVEaxnR3qBfqPzn+/wHPnsOreJxjYGRgYABi1vIsoXh+m68M3MwvgCIMt5YoxkDp2P9f/2exVDAHAbkcDEwgUQAz1Qu/AHicY2BkYGAO+p/FwMBS9v/r/68sFQxAERQQDACh8QbyeJxdT0sVwzAMy49AkAxAkbT3UQiAITGAISmAYQiA9th4ttUs7Q568UeSlVidiwSkB3PUPg+ESd6ZD/+8v7HyrtzwghY89ZB6BcyrYqc6RZhw48YhaA1Wc/v1PQtdeXJ/HppUmFM597nvBVK7D+Z+E8/uQZLBgDyaz3Llvxx02S3c/Hv813JrznryZP4F+6lSfQAAAAAAAAAAUAC2ATABaAGyAfoCJAKwAzYDmgQSBFwExgUyBbQF/AZOBvwHRAe2B/YISgigCPIJGglCCWQJignACgAKQAp2CroLAAtGC4oL8gxcDPINng5iDuYPag/6EF4RIBGGEeQSShKYEyQTbhOyFAoUYhS+FVoVphYoFooXHBeGGFoYnhjGGOwZChlOGXgZrBneGhwaWhqgGtIbLhvyHHQc2B1QHZ4d/wABAAAAUwBtAAYAAAAAAAIAIAAwAHMAAAB2C3AAAAAAeJx1kN9q2zAUh39q0441YxcbjN3tXJWWEcc1lEGvWkLbXZeSu8JUV/6T2VKQlY48w95ifYa9zt6jd/vFESUUYiP5O5/O8ZEE4AP+QWH9nHKsWeEdozXv4A0uIu/Sf488IN9G3sMQPyLv0/+MfICv+BV5iI/4wz+owVtGM/yNrPBZfYm8g/fqW+Rd+svIA/Jd5D18UovI+/S/Ix9gqp4iD3GoniduvvR1WQU5mhxLlmap3C/FUdVWN6IXoXK+k3MpnA2maVySuza0ZlToUZ07292YctFov6k2eWp8VzsrJ0m6qa+NNV4H87Dq1j2WWQiFFN61chX7yNy7mclDUoUwPxuPN/tjAoc5lvCoUaJCgOCI9pjfDGk/BPfMEGaus2pYaDQ0GgtWVP1Kx/ico2BkaQ0zGnKCnHNL09KNuK451721rLqhLfmfht5vzdrmp7Sr3nUfC07YL92afU1r+wrd7/Dh5WwdHrmLjDawanUK3+9acPXqPML7Wq3NaHL6pL+1QHuGMd8t5/8PvPGO3QAAAHicbZLnlpswEIV9DRiwvZtseu89Ib333vvmBWRZYMVC0pHEEufpg8BO/kTncOfTaLgMOtPr97o17P1/baKPACEiDBAjQYohRhhjDevYhu3YwA7sxC7sxh7sxT7sxwEcxCEcxhEcxTEcxwmcxCmcxhmcxTmcxwVcxCVkuIwruIpruI4buIlbuI07uIt7uI8HeIhHeIwneIpneI4XeIlXeI03eIt3eI8P+IhP+Iwv+Ipv+I5N/OiF1hEz9JKxUrtFrDl1lWF9NR9QIikToRaVjUouKxvOmNBjLxnlhgo2DbnM1djLKrNGnGPScSUzItzGv93yPP2bSQSX84z9cqFQdJ56yZRmMhW8mLlJJSaBI0XYPDaZKDUviZmvr6DrNjJMi0WcK1MTM02mqpbZlJtEsNx5SI238jSodJtoS7qv+BpPw67IY9xU+dg5TXjROTWwdGrIOzWhT+uA0jolxqjaZrSOnCF2Nmq16651EYpMm1fakAul9SJQeR5QVYQlk1VkZ8SwoVNFIVjWnKQrlBGdMToftdoZjrs77DajqXKrS02YEFxbbtdWkG0x44JJVUS5aBqKSlJwmhDrmOF2Hv9Wqsy4TNqoKhfmSrrQKuNSL5nvPG6p0s0AkEWkSWVZMy1Kx3ljk03qLuZ14lTmB8gNGmByGrGfjLrhlhJV2f7SaIneNF1ypQNbybBUSgZswQaWEUNngeay1/sD4l/60HicY/DewXAiKGIjI2Nf5AbGnRwMHAzJBRsZWJ02MTAyaIEYm7mYGDkgLD4GMIvNaRfTAaA0J5DN7rSLwQHCZmZw2ajC2BEYscGhI2Ijc4rLRjUQbxdHAwMji0NHckgESEkkEGzmYWLk0drB+L91A0vvRiYGFwAMdiP0AAA=') format('woff');\n}\n</style>\n<style id=\"style-core\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\nhtml {\n\t/*\n\t\tWe define the base font size and line height here as they affect the layout\n\t\tof the base page elements (i.e. `#ui-bar`, `#ui-dialog`, and `#story`).\n\t*/\n\tfont: 16px/1 Helmet, Freesans, sans-serif;\n}\n\n/* Story data styling. */\n#store-area, tw-storydata {\n\tdisplay: none !important;\n\tz-index: 0;\n}\n\n/* Special no transition styling. */\n.no-transition {\n\t-webkit-transition: none !important;\n\t-o-transition: none !important;\n\ttransition: none !important;\n}\n\n\n/*\n\tFullscreen appearance styles.\n*/\n*:-webkit-full-screen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\n*:-ms-fullscreen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\n*:fullscreen { /* Cause Blink/WebKit to behave like Gecko. */\n\theight: 100%;\n\twidth: 100%;\n}\nbody::-ms-backdrop { /* Prevent IE 11 from hiding the `body` element's background. */\n\tbackground: none;\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n*:focus {\n\toutline: thin dotted;\n}\n*:disabled {\n\tcursor: not-allowed !important;\n}\nbody {\n\tcolor: #eee;\n\tbackground-color: #111;\n\toverflow: auto;\n}\na {\n\tcursor: pointer;\n\tcolor: #68d;\n\ttext-decoration: none;\n\t-webkit-transition-duration: 200ms;\n\t     -o-transition-duration: 200ms;\n\t        transition-duration: 200ms;\n}\na:hover {\n\tcolor: #8af;\n\ttext-decoration: underline;\n}\na.link-broken {\n\tcolor: #c22;\n}\na.link-broken:hover {\n\tcolor: #e44;\n}\na[disabled], span.link-disabled {\n\tcolor: #aaa;\n\tcursor: not-allowed !important;\n\t/*\n\t\tNOTE: Do not use `pointer-events` here as it disables\n\t\tthe display of a cursor in some browsers.\n\n\t\tpointer-events: none;\n\t*/\n\ttext-decoration: none;\n}\narea {\n\tcursor: pointer;\n}\nbutton {\n\tcursor: pointer;\n\tcolor: #eee;\n\tbackground-color: #35a;\n\tborder: 1px solid #57c;\n\tline-height: normal;\n\tpadding: 0.4em;\n\t-webkit-transition-duration: 200ms;\n\t     -o-transition-duration: 200ms;\n\t        transition-duration: 200ms;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\nbutton:hover {\n\tbackground-color: #57c;\n\tborder-color: #79e;\n}\nbutton:disabled {\n\tbackground-color: #444;\n\tborder: 1px solid #666;\n}\ninput, select, textarea {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tpadding: 0.4em;\n}\nselect {\n\tpadding: 0.34em 0.4em;\n}\ninput[type=\"text\"] {\n\tmin-width: 18em;\n}\ntextarea {\n\tmin-width: 30em;\n\tresize: vertical;\n}\ninput[type=\"checkbox\"], input[type=\"file\"], input[type=\"radio\"], select {\n\tcursor: pointer;\n}\n/* BEGIN: input[type=\"range\"] */\ninput[type=\"range\"] {\n\t-webkit-appearance: none;\n\tmin-height: 1.2em;\n}\ninput[type=\"range\"]:focus {\n\toutline: none;\n}\ninput[type=\"range\"]::-webkit-slider-runnable-track {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: 100%;\n}\ninput[type=\"range\"]::-webkit-slider-thumb {\n\t-webkit-appearance: none;\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 18px;\n\t/*\n\t\tNOTE: Ideally, `margin-top` should be `0` for Edge/Spartan (ca. v17), but\n\t\treal WebKit/Blink-based browsers need it.  Since there's more of them and\n\t\tEdge is co-opting the prefix anyway, we cater to them.  Edge will simply\n\t\thave to look ever so slightly off.\n\t*/\n\tmargin-top: -5px;\n\twidth: 33px;\n}\ninput[type=\"range\"]:focus::-webkit-slider-runnable-track {\n\tbackground: #222;\n}\ninput[type=\"range\"]::-moz-range-track {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: 100%;\n}\ninput[type=\"range\"]::-moz-range-thumb {\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 18px;\n\twidth: 33px;\n}\ninput[type=\"range\"]::-ms-track {\n\tbackground: transparent;\n\tborder-color: transparent;\n\tcolor: transparent;\n\tcursor: pointer;\n\theight: 10px;\n\twidth: calc(100% - 1px);\n}\ninput[type=\"range\"]::-ms-fill-lower {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n}\ninput[type=\"range\"]::-ms-fill-upper {\n\tbackground: #222;\n\tborder: 1px solid #444;\n\tborder-radius: 0;\n}\ninput[type=\"range\"]::-ms-thumb {\n\tbackground: #35a;\n\tborder: 1px solid #57c;\n\tborder-radius: 0;\n\tcursor: pointer;\n\theight: 16px;\n\twidth: 33px;\n}\n/* END: input[type=\"range\"] */\ninput:not(:disabled):focus, select:not(:disabled):focus, textarea:not(:disabled):focus,\ninput:not(:disabled):hover, select:not(:disabled):hover, textarea:not(:disabled):hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\nhr {\n\tdisplay: block;\n\theight: 1px;\n\tborder: none;\n\tborder-top: 1px solid #eee;\n\tmargin: 1em 0;\n\tpadding: 0;\n}\naudio, canvas, progress, video {\n\tmax-width: 100%;\n\tvertical-align: middle;\n}\n\n.error-view {\n\tbackground-color: #511;\n\tborder-left: 0.5em solid #c22;\n\tdisplay: inline-block;\n\tmargin: 0.1em;\n\tmax-width: 100%;\n\tpadding: 0 0.25em;\n\tposition: relative;\n}\n.error-view > .error-toggle {\n\tbackground-color: transparent;\n\tborder: none;\n\tline-height: inherit;\n\tleft: 0;\n\tpadding: 0;\n\tposition: absolute;\n\ttop: 0;\n\twidth: 1.75em;\n}\n.error-view > .error {\n\tdisplay: inline-block;\n\tmargin-left: 0.25em;\n}\n.error-view > .error-toggle + .error {\n\tmargin-left: 1.5em;\n}\n.error-view > .error-source[hidden] {\n\tdisplay: none;\n}\n.error-view > .error-source:not([hidden]) {\n\tbackground-color: rgba(0, 0, 0, 0.2);\n\tdisplay: block;\n\tmargin: 0 0 0.25em;\n\toverflow-x: auto;\n\tpadding: 0.25em;\n}\n\n.highlight, .marked {\n\tcolor: yellow;\n\tfont-weight: bold;\n\tfont-style: italic;\n}\n.nobr {\n\twhite-space: nowrap;\n}\n\n[data-icon]:before,\n[data-icon-before]:before,\n[data-icon-after]:after,\n.error-view > .error-toggle:before,\n.error-view > .error:before,\na.link-external:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n[data-icon]:before {\n\tcontent: attr(data-icon);\n}\n[data-icon-before]:before {\n\tcontent: attr(data-icon-before) \"\\00a0\";\n}\n[data-icon-after]:after {\n\tcontent: \"\\00a0\" attr(data-icon-after);\n}\n.error-view > .error-toggle:before {\n\tcontent: \"\\e81a\";\n}\n.error-view > .error-toggle.enabled:before {\n\tcontent: \"\\e818\";\n}\n.error-view > .error:before {\n\tcontent: \"\\e80d\\00a0\\00a0\";\n}\na.link-external:after {\n\tcontent: \"\\00a0\\e80e\";\n}\n</style>\n<style id=\"style-core-display\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-display.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\n#story {\n\tz-index: 10;\n\tmargin: 2.5em;\n}\n@media screen and (max-width: 1136px) {\n\t#story {\n\t\tmargin-right: 1.5em;\n\t}\n}\n#passages {\n\tmax-width: 54em;\n\tmargin: 0 auto;\n}\n</style>\n<style id=\"style-core-passage\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-passage.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault appearance styles.\n*/\n.passage {\n\tline-height: 1.75;\n\ttext-align: left;\n\t-webkit-transition: opacity 400ms ease-in;\n\t-o-transition: opacity 400ms ease-in;\n\ttransition: opacity 400ms ease-in;\n}\n.passage-in {\n\topacity: 0;\n}\n.passage ul, .passage ol {\n\tmargin-left: 0.5em;\n\tpadding-left: 1.5em;\n}\n.passage table {\n\tmargin: 1em 0;\n\tborder-collapse: collapse;\n\tfont-size: 100%;\n}\n.passage tr, .passage th, .passage td, .passage caption {\n\tpadding: 3px;\n}\n</style>\n<style id=\"style-core-macro\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/core-macro.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault appearance styles.\n*/\n.macro-linkappend-insert,\n.macro-linkprepend-insert,\n.macro-linkreplace-insert,\n.macro-append-insert,\n.macro-prepend-insert,\n.macro-replace-insert,\n.macro-repeat-insert,\n.macro-timed-insert {\n\t-webkit-transition: opacity 400ms ease-in;\n\t-o-transition: opacity 400ms ease-in;\n\ttransition: opacity 400ms ease-in;\n}\n.macro-linkappend-in,\n.macro-linkprepend-in,\n.macro-linkreplace-in,\n.macro-append-in,\n.macro-prepend-in,\n.macro-replace-in,\n.macro-repeat-in,\n.macro-timed-in {\n\topacity: 0;\n}\n</style>\n<style id=\"style-ui-dialog\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-dialog.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tPatches to the core styles.\n*/\nhtml[data-dialog] body {\n\toverflow: hidden;\n}\n\n\n/*\n\tDefault structural styles.\n*/\n#ui-overlay.open {\n\tvisibility: visible;\n\t-webkit-transition: opacity 200ms ease-in;\n\t-o-transition: opacity 200ms ease-in;\n\ttransition: opacity 200ms ease-in;\n}\n#ui-overlay:not(.open) {\n\t-webkit-transition: visibility 200ms step-end, opacity 200ms ease-in;\n\t-o-transition: visibility 200ms step-end, opacity 200ms ease-in;\n\ttransition: visibility 200ms step-end, opacity 200ms ease-in;\n}\n#ui-overlay {\n\tvisibility: hidden;\n\topacity: 0;\n\tz-index: 100000;\n\tposition: fixed;\n\t/*\n\ttop: -50vh;\n\tleft: -50vw;\n\theight: 200vh;\n\twidth: 200vw;\n\t*/\n\ttop: -50%;\n\tleft: -50%;\n\theight: 200%;\n\twidth: 200%;\n}\n#ui-dialog.open {\n\tdisplay: block;\n\t-webkit-transition: opacity 200ms ease-in;\n\t-o-transition: opacity 200ms ease-in;\n\ttransition: opacity 200ms ease-in;\n}\n/*\n\tWe do not animate `#ui-dialog:not(.open)` for various reasons.  Chief among\n\tthem, however, is so that the dialog isn't in the middle of its animation\n\twhen other page updates happen.\n\n\te.g. The restoration of `overflow` on `body` would cause the still animating\n\t     dialog to jump around a little if a scrollbar were to pop in.\n\n\t     Any dialog action which performs a task which has its own animations\n\t     (e.g. passage display) or causes the page to reload in addition to\n\t     closing the dialog could cause display shenanigans.\n*/\n#ui-dialog {\n\tdisplay: none;\n\topacity: 0;\n\tz-index: 100100;\n\tposition: fixed;\n\ttop: 50px;\n\tmargin: 0;\n\tpadding: 0;\n}\n#ui-dialog > * {\n\t-webkit-box-sizing: border-box;\n\t        box-sizing: border-box;\n}\n#ui-dialog-titlebar {\n\tposition: relative;\n}\n#ui-dialog-close {\n\tdisplay: block;\n\tposition: absolute;\n\tright: 0;\n\ttop: 0;\n\twhite-space: nowrap;\n}\n#ui-dialog-body {\n\toverflow: auto;\n\tmin-width: 280px;\n\theight: 92%; /* fallback for browsers without support for calc() */\n\theight: calc(100% - 2.1em); /* parent - title(2.1em) */\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n#ui-overlay {\n\tbackground-color: #000;\n}\n#ui-overlay.open {\n\topacity: 0.8;\n}\n#ui-dialog {\n\tmax-width: 66em;\n}\n#ui-dialog.open {\n\topacity: 1;\n}\n#ui-dialog-titlebar {\n\tbackground-color: #444;\n\tmin-height: 24px;\n}\n#ui-dialog-title {\n\tmargin: 0;\n\tpadding: 0.2em 3.5em 0.2em 0.5em;\n\tfont-size: 1.5em;\n\ttext-align: center;\n\ttext-transform: uppercase;\n}\n#ui-dialog-close {\n\tcursor: pointer;\n\tfont-size: 120%;\n\tmargin: 0;\n\tpadding: 0;\n\twidth: 3.6em;\n\theight: 92%;\n\tbackground-color: transparent;\n\tborder: 1px solid transparent;\n\t-webkit-transition-duration: 200ms;\n\t     -o-transition-duration: 200ms;\n\t        transition-duration: 200ms;\n}\n#ui-dialog-close:hover {\n\tbackground-color: #b44;\n\tborder-color: #d66;\n}\n#ui-dialog-body {\n\tbackground-color: #111;\n\tborder: 1px solid #444;\n\ttext-align: left;\n\tline-height: 1.5;\n\tpadding: 1em;\n}\n#ui-dialog-body > *:first-child {\n\tmargin-top: 0;\n}\n#ui-dialog-body hr {\n\tbackground-color: #444;\n}\n\n/* Default dialog button bar styling. */\n#ui-dialog-body ul.buttons {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n#ui-dialog-body ul.buttons li {\n\tdisplay: inline-block;\n\tmargin: 0;\n\tpadding: 0.4em 0.4em 0 0;\n}\n#ui-dialog-body ul.buttons > li + li > button {\n\tmargin-left: 1em;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-dialog-close {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-dialog-close {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n</style>\n<style id=\"style-ui\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault structural styles.\n*/\n/* Settings dialog styling. */\n#ui-dialog-body.settings [id|=\"setting-body\"] > div:first-child {\n\tdisplay: table;\n\twidth: 100%;\n}\n#ui-dialog-body.settings [id|=\"setting-label\"] {\n\tdisplay: table-cell;\n\tpadding: 0.4em 2em 0.4em 0;\n}\n#ui-dialog-body.settings [id|=\"setting-label\"] + div {\n\tdisplay: table-cell;\n\tmin-width: 8em;\n\ttext-align: right;\n\tvertical-align: middle;\n\twhite-space: nowrap;\n}\n\n\n/*\n\tBuilt-in dialog appearance styles.\n*/\n/* List-based dialog styling (primarily for the Jumpto & Share dialogs). */\n#ui-dialog-body.list {\n\tpadding: 0;\n}\n#ui-dialog-body.list ul {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n\tborder: 1px solid transparent;\n}\n#ui-dialog-body.list li {\n\tmargin: 0;\n}\n#ui-dialog-body.list li:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.list li a {\n\tdisplay: block;\n\tpadding: 0.25em 0.75em;\n\tborder: 1px solid transparent;\n\tcolor: #eee;\n\ttext-decoration: none;\n}\n#ui-dialog-body.list li a:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n\n/* Saves dialog styling. */\n#ui-dialog-body.saves {\n\tpadding: 0 0 1px; /* Webkit/Blink need 1px bottom padding or they'll trigger the scroll bar */\n}\n#ui-dialog-body.saves > *:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.saves table {\n\tborder-spacing: 0;\n\twidth: 100%;\n}\n#ui-dialog-body.saves tr:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#ui-dialog-body.saves td {\n\tpadding: 0.33em 0.33em;\n}\n#ui-dialog-body.saves td:first-child {\n\tmin-width: 1.5em;\n\ttext-align: center;\n}\n#ui-dialog-body.saves td:nth-child(3) {\n\tline-height: 1.2;\n}\n#ui-dialog-body.saves td:last-child {\n\ttext-align: right;\n}\n#ui-dialog-body.saves .empty {\n\tcolor: #999;\n\tspeak: none;\n\ttext-align: center;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n#ui-dialog-body.saves .datestamp {\n\tfont-size: 75%;\n\tmargin-left: 1em;\n}\n#ui-dialog-body.saves ul.buttons li {\n\tpadding: 0.4em;\n}\n#ui-dialog-body.saves ul.buttons > li + li > button {\n\tmargin-left: 0.2em;\n}\n#ui-dialog-body.saves ul.buttons li:last-child {\n\t/*\n\t\tUsing `position:absolute;right:0;` here can produce poor results,\n\t\tso we use `float:right` instead.\n\t*/\n\tfloat: right;\n}\n\n/* Settings dialog styling. */\n#ui-dialog-body.settings div[id|=\"header-body\"] {\n\tmargin: 1em 0;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"]:first-child {\n\tmargin-top: 0;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"]:not(:first-child) {\n\tborder-top: 1px solid #444;\n\tpadding-top: 1em;\n}\n#ui-dialog-body.settings div[id|=\"header-body\"] > * {\n\tmargin: 0;\n}\n#ui-dialog-body.settings h2[id|=\"header-heading\"] {\n\tfont-size: 1.375em;\n}\n#ui-dialog-body.settings p[id|=\"header-desc\"],\n#ui-dialog-body.settings p[id|=\"setting-desc\"] {\n\tfont-size: 87.5%;\n\tmargin: 0 0 0 0.5em;\n}\n#ui-dialog-body.settings div[id|=\"setting-body\"] + div[id|=\"setting-body\"] {\n\tmargin: 1em 0;\n}\n#ui-dialog-body.settings [id|=\"setting-control\"] {\n\twhite-space: nowrap;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"] {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tpadding: 0.4em;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"]:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled {\n\tbackground-color: #282;\n\tborder-color: #4a4;\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:hover {\n\tbackground-color: #4a4;\n\tborder-color: #6c6;\n}\n#ui-dialog-body.settings input[type=\"range\"][id|=\"setting-control\"] {\n\tmax-width: 35vw;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-dialog-body.list a,\n#ui-dialog-body.settings span[id|=\"setting-input\"] {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-dialog-body.saves button[id=\"saves-export\"]:before,\n#ui-dialog-body.saves button[id=\"saves-import\"]:before,\n#ui-dialog-body.saves button[id=\"saves-clear\"]:before,\n#ui-dialog-body.settings button[id|=\"setting-control\"]:after,\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#ui-dialog-body.saves button[id=\"saves-export\"]:before {\n\tcontent: \"\\e829\\00a0\";\n}\n#ui-dialog-body.saves button[id=\"saves-import\"]:before {\n\tcontent: \"\\e82a\\00a0\";\n}\n#ui-dialog-body.saves button[id=\"saves-clear\"]:before {\n\tcontent: \"\\e827\\00a0\";\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"]:after {\n\tcontent: \"\\00a0\\00a0\\e830\";\n}\n#ui-dialog-body.settings button[id|=\"setting-control\"].enabled:after {\n\tcontent: \"\\00a0\\00a0\\e831\";\n}\n</style>\n<style id=\"style-ui-bar\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-bar.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tPatches to the core styles.\n*/\n#story {\n\tmargin-left: 20em;\n\t-webkit-transition: margin-left 200ms ease-in;\n\t-o-transition: margin-left 200ms ease-in;\n\ttransition: margin-left 200ms ease-in;\n}\n#ui-bar.stowed ~ #story {\n\tmargin-left: 4.5em;\n}\n@media screen and (max-width: 1136px) {\n\t#story {\n\t\tmargin-left: 19em;\n\t}\n\t#ui-bar.stowed ~ #story {\n\t\tmargin-left: 3.5em;\n\t}\n}\n/*\n\tAt very narrow viewport widths, set `#story{margin-left}` equal to the value\n\tof `#ui-bar.stowed~#story{margin-left}`, so that `#ui-bar` will side over top\n\tof `#story` when unstowed, rather than shoving it over.\n*/\n@media screen and (max-width: 768px) {\n\t#story {\n\t\tmargin-left: 3.5em;\n\t}\n}\n\n\n/*\n\tDefault structural styles.\n*/\n#ui-bar {\n\tposition: fixed;\n\tz-index: 50;\n\ttop: 0;\n\tleft: 0;\n\twidth: 17.5em;\n\theight: 100%;\n\tmargin: 0;\n\tpadding: 0;\n\t-webkit-transition: left 200ms ease-in;\n\t-o-transition: left 200ms ease-in;\n\ttransition: left 200ms ease-in;\n}\n#ui-bar.stowed {\n\tleft: -15.5em;\n}\n#ui-bar-tray {\n\tposition: absolute;\n\ttop: 0.2em;\n\tleft: 0;\n\tright: 0;\n}\n#ui-bar-body {\n\theight: 90%; /* fallback for browsers without support for calc() */\n\theight: calc(100% - 2.5em);\n\tmargin: 2.5em 0;\n\tpadding: 0 1.5em;\n}\n#ui-bar.stowed #ui-bar-history,\n#ui-bar.stowed #ui-bar-body {\n\tvisibility: hidden;\n\t-webkit-transition: visibility 200ms step-end;\n\t-o-transition: visibility 200ms step-end;\n\ttransition: visibility 200ms step-end;\n}\n\n\n/*\n\tDefault appearance styles.\n*/\n#ui-bar {\n\tbackground-color: #222;\n\tborder-right: 1px solid #444;\n\ttext-align: center;\n}\n#ui-bar a {\n\ttext-decoration: none;\n}\n#ui-bar hr {\n\tborder-color: #444;\n}\n#ui-bar-toggle,\n#ui-bar-history [id|=\"history\"] {\n\tfont-size: 1.2em;\n\tline-height: inherit;\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n}\n#ui-bar-toggle {\n\tdisplay: block;\n\tposition: absolute;\n\ttop: 0;\n\tright: 0;\n\tborder-right: none;\n\tpadding: 0.3em 0.45em 0.25em;\n}\n#ui-bar.stowed #ui-bar-toggle {\n\tpadding: 0.3em 0.35em 0.25em 0.55em;\n}\n#ui-bar-toggle:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n#ui-bar-history {\n\tmargin: 0 auto;\n}\n#ui-bar-history [id|=\"history\"] {\n\tpadding: 0.2em 0.45em 0.35em;\n}\n#ui-bar-history #history-jumpto {\n\tpadding: 0.2em 0.665em 0.35em;\n}\n#ui-bar-history [id|=\"history\"]:not(:first-child) {\n\tmargin-left: 1.2em;\n}\n#ui-bar-history [id|=\"history\"]:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n#ui-bar-history [id|=\"history\"]:disabled {\n\tcolor: #444;\n\tbackground-color: transparent;\n\tborder-color: #444;\n}\n#ui-bar-body {\n\tline-height: 1.5;\n\toverflow: auto;\n}\n#ui-bar-body > :not(:first-child) {\n\tmargin-top: 2em;\n}\n#story-title {\n\tmargin: 0;\n\tfont-size: 162.5%;\n}\n#story-author {\n\tmargin-top: 2em;\n\tfont-weight: bold;\n}\n#menu ul {\n\tmargin: 1em 0 0;\n\tpadding: 0;\n\tlist-style: none;\n\tborder: 1px solid #444;\n}\n#menu ul:empty {\n\tdisplay: none;\n}\n#menu li {\n\tmargin: 0;\n}\n#menu li:not(:first-child) {\n\tborder-top: 1px solid #444;\n}\n#menu li a {\n\tdisplay: block;\n\tpadding: 0.25em 0.75em;\n\tborder: 1px solid transparent;\n\tcolor: #eee;\n\ttext-transform: uppercase;\n}\n#menu li a:hover {\n\tbackground-color: #444;\n\tborder-color: #eee;\n}\n\n/* Stop text selection on certain UI elements. */\n#ui-bar-history [id|=\"history\"],\n#ui-bar-toggle,\n#menu a {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n}\n\n\n/*\n\tDefault font icon styles.\n*/\n#ui-bar-toggle:before,\n#ui-bar-history [id|=\"history\"],\n#menu-core li[id|=\"menu-item\"] a:before {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#ui-bar-toggle:before {\n\tcontent: \"\\e81d\";\n}\n#ui-bar.stowed #ui-bar-toggle:before {\n\tcontent: \"\\e81e\";\n}\n#menu-item-saves a:before {\n\tcontent: \"\\e82b\\00a0\";\n}\n#menu-item-settings a:before {\n\tcontent: \"\\e82d\\00a0\";\n}\n#menu-item-restart a:before {\n\tcontent: \"\\e82c\\00a0\";\n}\n#menu-item-share a:before {\n\tcontent: \"\\e82f\\00a0\";\n}\n</style>\n<style id=\"style-ui-debug\" type=\"text/css\">/***********************************************************************************************************************\n\n\tcss/ui-debug.css\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tDefault debug bar styles.\n*/\n#debug-bar {\n\tbackground-color: #222;\n\tborder-left: 1px solid #444;\n\tborder-top: 1px solid #444;\n\tbottom: 0;\n\tmargin: 0;\n\tmax-height: 75%;\n\t/* max-width: 28em;\n\tmin-width: 22em; */\n\tpadding: 0.5em;\n\tposition: fixed;\n\tright: 0;\n\tz-index: 99900;\n}\n#debug-bar > div:not([id]) + div {\n\tmargin-top: 0.5em;\n}\n#debug-bar > div > label {\n\tmargin-right: 0.5em;\n}\n#debug-bar > div > input[type=\"text\"] {\n\tmin-width: 0;\n\twidth: 8em;\n}\n#debug-bar > div > select {\n\twidth: 15em;\n}\n\n#debug-bar-toggle {\n\tcolor: #eee;\n\tbackground-color: #222;\n\tborder: 1px solid #444;\n\theight: 101%; /* fallback for browsers without support for calc() */\n\theight: calc(100% + 1px);\n\tleft: -2em; /* fallback for browsers without support for calc() */\n\tleft: calc(-2em - 1px);\n\tposition: absolute;\n\ttop: -1px;\n\twidth: 2em;\n}\n#debug-bar-toggle:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n\n#debug-bar-hint {\n\tbottom: 0.175em;\n\tfont-size: 4.5em;\n\topacity: 0.33;\n\tpointer-events: none;\n\tposition: fixed;\n\tright: 0.6em;\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t    -ms-user-select: none;\n\t        user-select: none;\n\twhite-space: nowrap;\n}\n\n#debug-bar-watch {\n\tbackground-color: #222;\n\tborder-left: 1px solid #444;\n\tborder-top: 1px solid #444;\n\tbottom: 102%; /* fallback for browsers without support for calc() */\n\tbottom: calc(100% + 1px);\n\tfont-size: 0.9em;\n\tleft: -1px;\n\tmax-height: 650%; /* fallback for browsers without support for vh units */\n\tmax-height: 65vh;\n\tposition: absolute;\n\toverflow-x: hidden;\n\toverflow-y: scroll;\n\tright: 0;\n\tz-index: 99800;\n}\n#debug-bar-watch[hidden] {\n\tdisplay: none;\n}\n#debug-bar-watch div {\n\tcolor: #999;\n\tfont-style: italic;\n\tmargin: 1em auto;\n\ttext-align: center;\n}\n#debug-bar-watch table {\n\twidth: 100%;\n}\n#debug-bar-watch tr:nth-child(2n) {\n\tbackground-color: rgba(127, 127, 127, 0.15);\n}\n#debug-bar-watch td {\n\tpadding: 0.2em 0;\n}\n#debug-bar-watch td:first-child + td {\n\tpadding: 0.2em 0.3em 0.2em 0.1em;\n}\n#debug-bar-watch .watch-delete {\n\tbackground-color: transparent;\n\tborder: none;\n\tcolor: #c00;\n}\n#debug-bar-watch-all,\n#debug-bar-watch-none {\n\tmargin-left: 0.5em;\n}\n#debug-bar-watch-toggle,\n#debug-bar-views-toggle {\n\tcolor: #eee;\n\tbackground-color: transparent;\n\tborder: 1px solid #444;\n\tmargin-right: 1em;\n\tpadding: 0.4em;\n}\n#debug-bar-watch-toggle:hover,\n#debug-bar-views-toggle:hover {\n\tbackground-color: #333;\n\tborder-color: #eee;\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle,\nhtml[data-debug-view] #debug-bar-views-toggle {\n\tbackground-color: #282;\n\tborder-color: #4a4;\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle:hover,\nhtml[data-debug-view] #debug-bar-views-toggle:hover {\n\tbackground-color: #4a4;\n\tborder-color: #6c6;\n}\n\n#debug-bar-toggle:before,\n#debug-bar-hint:after,\n#debug-bar-watch .watch-delete:before,\n#debug-bar-watch-add:before,\n#debug-bar-watch-all:before,\n#debug-bar-watch-none:before,\n#debug-bar-watch-toggle:after,\n#debug-bar-views-toggle:after {\n\tfont-family: \"tme-fa-icons\";\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\tspeak: none;\n}\n#debug-bar-toggle:before {\n\tcontent: \"\\e838\";\n}\n#debug-bar-hint:after {\n\tcontent: \"\\e838\\202f\\e822\";\n}\n#debug-bar-watch .watch-delete:before {\n\tcontent: \"\\e804\";\n}\n#debug-bar-watch-add:before {\n\tcontent: \"\\e805\";\n}\n#debug-bar-watch-all:before {\n\tcontent: \"\\e83a\";\n}\n#debug-bar-watch-none:before {\n\tcontent: \"\\e827\";\n}\n#debug-bar-watch-toggle:after,\n#debug-bar-views-toggle:after {\n\tcontent: \"\\00a0\\00a0\\e830\";\n}\n#debug-bar-watch:not([hidden]) ~ div #debug-bar-watch-toggle:after,\nhtml[data-debug-view] #debug-bar-views-toggle:after {\n\tcontent: \"\\00a0\\00a0\\e831\";\n}\n\n\n/*\n\tDefault debug view styles.\n*/\nhtml[data-debug-view] .debug {\n\tpadding: 0.25em;\n\tbackground-color: #234; /* #541, #151 */\n}\nhtml[data-debug-view] .debug[title] {\n\tcursor: help;\n}\nhtml[data-debug-view] .debug.block {\n\tdisplay: inline-block;\n\tvertical-align: middle;\n}\nhtml[data-debug-view] .debug.invalid {\n\ttext-decoration: line-through;\n}\nhtml[data-debug-view] .debug.hidden,\nhtml[data-debug-view] .debug.hidden .debug {\n\tbackground-color: #555;\n}\nhtml:not([data-debug-view]) .debug.hidden {\n\tdisplay: none;\n}\n\nhtml[data-debug-view] .debug[data-name][data-type]:before,\nhtml[data-debug-view] .debug[data-name][data-type].nonvoid:after {\n\tbackground-color: rgba(0,0,0,0.25);\n\tfont-family: monospace, monospace;\n\twhite-space: pre;\n}\nhtml[data-debug-view] .debug[data-name][data-type]:before {\n\tcontent: attr(data-name);\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"macro\"]:before {\n\tcontent: \"<<\" attr(data-name) \">>\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"macro\"].nonvoid:after {\n\tcontent: \"<</\" attr(data-name) \">>\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"html\"]:before {\n\tcontent: \"<\" attr(data-name) \">\";\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"html\"].nonvoid:after {\n\tcontent: \"</\" attr(data-name) \">\";\n}\nhtml[data-debug-view] .debug[data-name][data-type]:not(:empty):before {\n\tmargin-right: 0.25em;\n}\nhtml[data-debug-view] .debug[data-name][data-type].nonvoid:not(:empty):after {\n\tmargin-left: 0.25em;\n}\nhtml[data-debug-view] .debug[data-name][data-type|=\"special\"],\nhtml[data-debug-view] .debug[data-name][data-type|=\"special\"]:before {\n\tdisplay: block;\n}\n</style>\n</head>\n<body>\n\t<div id=\"init-screen\">\n\t\t<div id=\"init-no-js\"><noscript>JavaScript is required. Please enable it to continue.</noscript></div>\n\t\t<div id=\"init-lacking\">Your browser lacks required capabilities. Please upgrade it or switch to another to continue.</div>\n\t\t<div id=\"init-loading\"><div>Loading&hellip;</div></div>\n\t</div>\n\t{{STORY_DATA}}\n\t<script id=\"script-sugarcube\" type=\"text/javascript\">\n\t/*! SugarCube JS */\n\tif(document.documentElement.getAttribute(\"data-init\")===\"loading\"){window.TWINE1=false;\nwindow.DEBUG=false;\n(function (window, document, jQuery, undefined) {\n\"use strict\";\n\n/***********************************************************************************************************************\n\n\tlib/alert.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tTODO: This regular expression should be elsewhere.\n\n\tError prologs by engine/browser: (ca. 2018)\n\t\tChrome, Opera, & Vivaldi → `Uncaught \\w*Error: …`\n\t\tEdge & IE                → `…`\n\t\tFirefox                  → `Error: …`\n\t\tOpera (Presto)           → `Uncaught exception: \\w*(?:Error|Exception): …`\n\t\tSafari (ca. v5.1)        → `\\w*(?:Error|_ERR): …`\n*/\nvar errorPrologRegExp = /^(?:(?:uncaught\\s+(?:exception:\\s+)?)?\\w*(?:error|exception|_err):\\s+)+/i; // eslint-disable-line no-unused-vars, no-var\n\nvar Alert = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tError Functions.\n\t*******************************************************************************************************************/\n\tfunction _alertMesg(type, where, what, error) {\n\t\tconst isFatal = type === 'fatal';\n\t\tlet mesg = `Apologies! ${isFatal ? 'A fatal' : 'An'} error has occurred.`;\n\n\t\tif (isFatal) {\n\t\t\tmesg += ' Aborting.';\n\t\t}\n\t\telse {\n\t\t\tmesg += ' You may be able to continue, but some parts may not work properly.';\n\t\t}\n\n\t\tif (where != null || what != null) { // lazy equality for null\n\t\t\tmesg += '\\n\\nError';\n\n\t\t\tif (where != null) { // lazy equality for null\n\t\t\t\tmesg += ` [${where}]`;\n\t\t\t}\n\n\t\t\tif (what != null) { // lazy equality for null\n\t\t\t\tmesg += `: ${what.replace(errorPrologRegExp, '')}.`;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tmesg += ': unknown error.';\n\t\t\t}\n\t\t}\n\n\t\tif (typeof error === 'object' && error !== null && error.stack) {\n\t\t\tmesg += `\\n\\nStack Trace:\\n${error.stack}`;\n\t\t}\n\n\t\twindow.alert(mesg); // eslint-disable-line no-alert\n\t}\n\n\tfunction alertError(where, what, error) {\n\t\t_alertMesg(null, where, what, error);\n\t}\n\n\tfunction alertFatal(where, what, error) {\n\t\t_alertMesg('fatal', where, what, error);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tError Event.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSet up a global error handler for uncaught exceptions.\n\t*/\n\t(origOnError => {\n\t\twindow.onerror = function (what, source, lineNum, colNum, error) {\n\t\t\t// Uncaught exceptions during play may be recoverable/ignorable.\n\t\t\tif (document.readyState === 'complete') {\n\t\t\t\talertError(null, what, error);\n\t\t\t}\n\n\t\t\t// Uncaught exceptions during startup should be fatal.\n\t\t\telse {\n\t\t\t\talertFatal(null, what, error);\n\t\t\t\twindow.onerror = origOnError;\n\n\t\t\t\tif (typeof window.onerror === 'function') {\n\t\t\t\t\twindow.onerror.apply(this, arguments);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t})(window.onerror);\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\terror : { value : alertError },\n\t\tfatal : { value : alertFatal }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/patterns.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tTODO: Move all markup patterns into here.\n*/\n\nvar Patterns = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tPatterns.\n\t*******************************************************************************************************************/\n\t/*\n\t\tWhitespace patterns.\n\n\t\tSpace class (equivalent to `\\s`):\n\t\t\t[\\u0020\\f\\n\\r\\t\\v\\u00a0\\u1680\\u180e\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000\\ufeff]\n\t\tSpace class, sans line terminators:\n\t\t\t[\\u0020\\f\\t\\v\\u00a0\\u1680\\u180e\\u2000-\\u200a\\u202f\\u205f\\u3000\\ufeff]\n\t\tLine Terminator class:\n\t\t\t[\\n\\r\\u2028\\u2029]\n\t*/\n\tconst space = (() => {\n\t\t/*\n\t\t\tSome browsers still supported by SugarCube have faulty space classes (`\\s`).\n\t\t\tWe check for that lossage here and, if necessary, build our own class from\n\t\t\tthe component pieces.\n\t\t*/\n\t\tconst wsMap = new Map([\n\t\t\t['\\u0020', '\\\\u0020'],\n\t\t\t['\\f', '\\\\f'],\n\t\t\t['\\n', '\\\\n'],\n\t\t\t['\\r', '\\\\r'],\n\t\t\t['\\t', '\\\\t'],\n\t\t\t['\\v', '\\\\v'],\n\t\t\t['\\u00a0', '\\\\u00a0'],\n\t\t\t['\\u1680', '\\\\u1680'],\n\t\t\t['\\u180e', '\\\\u180e'],\n\t\t\t['\\u2000', '\\\\u2000'],\n\t\t\t['\\u2001', '\\\\u2001'],\n\t\t\t['\\u2002', '\\\\u2002'],\n\t\t\t['\\u2003', '\\\\u2003'],\n\t\t\t['\\u2004', '\\\\u2004'],\n\t\t\t['\\u2005', '\\\\u2005'],\n\t\t\t['\\u2006', '\\\\u2006'],\n\t\t\t['\\u2007', '\\\\u2007'],\n\t\t\t['\\u2008', '\\\\u2008'],\n\t\t\t['\\u2009', '\\\\u2009'],\n\t\t\t['\\u200a', '\\\\u200a'],\n\t\t\t['\\u2028', '\\\\u2028'],\n\t\t\t['\\u2029', '\\\\u2029'],\n\t\t\t['\\u202f', '\\\\u202f'],\n\t\t\t['\\u205f', '\\\\u205f'],\n\t\t\t['\\u3000', '\\\\u3000'],\n\t\t\t['\\ufeff', '\\\\ufeff']\n\t\t]);\n\t\tconst wsRe = /^\\s$/;\n\t\tlet missing = '';\n\n\t\twsMap.forEach((pat, char) => {\n\t\t\tif (!wsRe.test(char)) {\n\t\t\t\tmissing += pat;\n\t\t\t}\n\t\t});\n\n\t\treturn missing ? `[\\\\s${missing}]` : '\\\\s';\n\t})();\n\tconst spaceNoTerminator = '[\\\\u0020\\\\f\\\\t\\\\v\\\\u00a0\\\\u1680\\\\u180e\\\\u2000-\\\\u200a\\\\u202f\\\\u205f\\\\u3000\\\\ufeff]';\n\tconst lineTerminator    = '[\\\\n\\\\r\\\\u2028\\\\u2029]';\n\tconst notSpace          = space === '\\\\s' ? '\\\\S' : space.replace(/^\\[/, '[^');\n\n\t/*\n\t\tCharacter patterns.\n\t*/\n\tconst anyChar = `(?:.|${lineTerminator})`;\n\n\t/*\n\t\tLetter patterns.\n\n\t\tFIXME:\n\t\t\t1. The existing set, which is a TiddlyWiki holdover, should probably\n\t\t\t   encompass a significantly greater range of BMP code points.\n\t\t\t2. Should we include the surrogate pair code units (\\uD800-\\uDBFF &\n\t\t\t   \\uDC00-\\uDFFF) to handle non-BMP code points?  Further, should we\n\t\t\t   simply be checking for the code units themselves or checking for\n\t\t\t   properly mated pairs?\n\t*/\n\tconst anyLetter       = '[0-9A-Z_a-z\\\\-\\\\u00c0-\\\\u00d6\\\\u00d8-\\\\u00f6\\\\u00f8-\\\\u00ff\\\\u0150\\\\u0170\\\\u0151\\\\u0171]';\n\tconst anyLetterStrict = anyLetter.replace('\\\\-', ''); // anyLetter sans hyphen\n\n\t/*\n\t\tIdentifier patterns.\n\n\t\tNOTE: Since JavaScript's RegExp syntax does not support Unicode character\n\t\tclasses, the correct regular expression to match a valid identifier name,\n\t\twithin the scope of our needs, would be on the order of approximately 5–6\n\t\tor 11–16 KiB, depending on how the pattern was built.  That being the case,\n\t\tfor the moment we restrict valid TwineScript identifiers to US-ASCII.\n\n\t\tFIXME: Fix this to, at least, approximate the correct range.\n\t*/\n\tconst identifierFirstChar = '[$A-Z_a-z]';\n\tconst identifierNextChar  = '[$0-9A-Z_a-z]';\n\tconst identifier          = `${identifierFirstChar}${identifierNextChar}*`;\n\n\t// Variable patterns.\n\tconst variableSigil = '[$_]';\n\tconst variable      = variableSigil + identifier;\n\n\t// Macro name pattern.\n\tconst macroName = '[A-Za-z][\\\\w-]*|[=-]';\n\n\t// Template name pattern.\n\tconst templateName = '[A-Za-z][\\\\w-]*';\n\n\t// CSS ID or class sigil pattern.\n\tconst cssIdOrClassSigil = '[#.]';\n\n\t// CSS image transclusion template pattern.\n\t//\n\t// NOTE: The alignment syntax isn't supported, but removing it might break uses\n\t// of the template in the wild, so we leave it alone for now.\n\tconst cssImage = '\\\\[[<>]?[Ii][Mm][Gg]\\\\[(?:\\\\s|\\\\S)*?\\\\]\\\\]+';\n\n\t// Inline CSS pattern.\n\tconst inlineCss = (() => {\n\t\t/* legacy */\n\t\tconst twStyle   = `(${anyLetter}+)\\\\(([^\\\\)\\\\|\\\\n]+)\\\\):`;\n\t\t/* /legacy */\n\t\tconst cssStyle  = `${spaceNoTerminator}*(${anyLetter}+)${spaceNoTerminator}*:([^;\\\\|\\\\n]+);`;\n\t\tconst idOrClass = `${spaceNoTerminator}*((?:${cssIdOrClassSigil}${anyLetter}+${spaceNoTerminator}*)+);`;\n\n\t\t// [1,2] = style(value):\n\t\t// [3,4] = style:value;\n\t\t// [5]   = #id.className;\n\t\treturn `${twStyle}|${cssStyle}|${idOrClass}`;\n\t})();\n\n\t// URL pattern.\n\tconst url = '(?:file|https?|mailto|ftp|javascript|irc|news|data):[^\\\\s\\'\"]+';\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze({\n\t\tspace,\n\t\tspaceNoTerminator,\n\t\tlineTerminator,\n\t\tnotSpace,\n\t\tanyChar,\n\t\tanyLetter,\n\t\tanyLetterStrict,\n\t\tidentifierFirstChar,\n\t\tidentifierNextChar,\n\t\tidentifier,\n\t\tvariableSigil,\n\t\tvariable,\n\t\tmacroName,\n\t\ttemplateName,\n\t\tcssIdOrClassSigil,\n\t\tcssImage,\n\t\tinlineCss,\n\t\turl\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/extensions.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns */\n\n/*\n\tJavaScript Polyfills.\n\n\tNOTE: The ES5 and ES6 polyfills come from the vendored `es5-shim.js` and `es6-shim.js` libraries.\n*/\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tTrims whitespace from either the start or end of the given string.\n\t*/\n\tconst _trimString = (() => {\n\t\t// Whitespace regular expressions.\n\t\tconst startWSRe = new RegExp(`^${Patterns.space}${Patterns.space}*`);\n\t\tconst endWSRe   = new RegExp(`${Patterns.space}${Patterns.space}*$`);\n\n\t\tfunction trimString(str, where) {\n\t\t\tconst val = String(str);\n\n\t\t\tif (!val) {\n\t\t\t\treturn val;\n\t\t\t}\n\n\t\t\tswitch (where) {\n\t\t\tcase 'start':\n\t\t\t\treturn startWSRe.test(val) ? val.replace(startWSRe, '') : val;\n\n\t\t\tcase 'end':\n\t\t\t\treturn endWSRe.test(val) ? val.replace(endWSRe, '') : val;\n\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`_trimString called with incorrect where parameter value: \"${where}\"`);\n\t\t\t}\n\t\t}\n\n\t\treturn trimString;\n\t})();\n\n\t/*\n\t\tGenerates a pad string based upon the given string and length.\n\t*/\n\tfunction _createPadString(length, padding) {\n\t\tconst targetLength = Number.parseInt(length, 10) || 0;\n\n\t\tif (targetLength < 1) {\n\t\t\treturn '';\n\t\t}\n\n\t\tlet padString = typeof padding === 'undefined' ? '' : String(padding);\n\n\t\tif (padString === '') {\n\t\t\tpadString = ' ';\n\t\t}\n\n\t\twhile (padString.length < targetLength) {\n\t\t\tconst curPadLength    = padString.length;\n\t\t\tconst remainingLength = targetLength - curPadLength;\n\n\t\t\tpadString += curPadLength > remainingLength\n\t\t\t\t? padString.slice(0, remainingLength)\n\t\t\t\t: padString;\n\t\t}\n\n\t\tif (padString.length > targetLength) {\n\t\t\tpadString = padString.slice(0, targetLength);\n\t\t}\n\n\t\treturn padString;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPolyfills.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[ES2019] Returns a new array consisting of the source array with all sub-array elements\n\t\tconcatenated into it recursively up to the given depth.\n\t*/\n\tif (!Array.prototype.flat) {\n\t\tObject.defineProperty(Array.prototype, 'flat', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\t\t\tvalue        : (() => {\n\t\t\t\tfunction flat(/* depth */) {\n\t\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\t\tthrow new TypeError('Array.prototype.flat called on null or undefined');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst depth = arguments.length === 0 ? 1 : Number(arguments[0]) || 0;\n\n\t\t\t\t\tif (depth < 1) {\n\t\t\t\t\t\treturn Array.prototype.slice.call(this);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn Array.prototype.reduce.call(\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\t(acc, cur) => {\n\t\t\t\t\t\t\tif (cur instanceof Array) {\n\t\t\t\t\t\t\t\t// acc.push.apply(acc, flat.call(cur, depth - 1));\n\t\t\t\t\t\t\t\tacc.push(...flat.call(cur, depth - 1));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tacc.push(cur);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn acc;\n\t\t\t\t\t\t},\n\t\t\t\t\t\t[]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn flat;\n\t\t\t})()\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a new array consisting of the result of calling the given mapping function\n\t\ton every element in the source array and then concatenating all sub-array elements into it\n\t\trecursively up to a depth of `1`.  Identical to calling `<Array>.map(fn).flat()`.\n\t*/\n\tif (!Array.prototype.flatMap) {\n\t\tObject.defineProperty(Array.prototype, 'flatMap', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(/* callback [, thisArg] */) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Array.prototype.flatMap called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.map.apply(this, arguments).flat();\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2016] Returns whether the given element was found within the array.\n\t*/\n\tif (!Array.prototype.includes) {\n\t\tObject.defineProperty(Array.prototype, 'includes', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Array.prototype.includes called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tif (arguments.length === 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst length = this.length >>> 0;\n\n\t\t\t\tif (length === 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst needle = arguments[0];\n\t\t\t\tlet i = Number(arguments[1]) || 0;\n\n\t\t\t\tif (i < 0) {\n\t\t\t\t\ti = Math.max(0, length + i);\n\t\t\t\t}\n\n\t\t\t\tfor (/* empty */; i < length; ++i) {\n\t\t\t\t\tconst value = this[i];\n\n\t\t\t\t\tif (value === needle || value !== value && needle !== needle) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a new array consisting of the given object's own enumerable property/value\n\t\tpairs as `[key, value]` arrays.\n\t*/\n\tif (!Object.entries) {\n\t\tObject.defineProperty(Object, 'entries', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (typeof obj !== 'object' || obj === null) {\n\t\t\t\t\tthrow new TypeError('Object.entries object parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\treturn Object.keys(obj).map(key => [key, obj[key]]);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a new generic object consisting of the given list's key/value pairs.\n\t*/\n\tif (!Object.fromEntries) {\n\t\tObject.defineProperty(Object, 'fromEntries', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(iter) {\n\t\t\t\treturn Array.from(iter).reduce(\n\t\t\t\t\t(acc, pair) => {\n\t\t\t\t\t\tif (Object(pair) !== pair) {\n\t\t\t\t\t\t\tthrow new TypeError('Object.fromEntries iterable parameter must yield objects');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (pair[0] in acc) {\n\t\t\t\t\t\t\tObject.defineProperty(acc, pair[0], {\n\t\t\t\t\t\t\t\tconfigurable : true,\n\t\t\t\t\t\t\t\tenumerable   : true,\n\t\t\t\t\t\t\t\twritable     : true,\n\t\t\t\t\t\t\t\tvalue        : pair[1]\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tacc[pair[0]] = pair[1]; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{}\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns all own property descriptors of the given object.\n\t*/\n\tif (!Object.getOwnPropertyDescriptors) {\n\t\tObject.defineProperty(Object, 'getOwnPropertyDescriptors', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (obj == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('Object.getOwnPropertyDescriptors object parameter is null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst O = Object(obj);\n\n\t\t\t\treturn Reflect.ownKeys(O).reduce(\n\t\t\t\t\t(acc, key) => {\n\t\t\t\t\t\tconst desc = Object.getOwnPropertyDescriptor(O, key);\n\n\t\t\t\t\t\tif (typeof desc !== 'undefined') {\n\t\t\t\t\t\t\tif (key in acc) {\n\t\t\t\t\t\t\t\tObject.defineProperty(acc, key, {\n\t\t\t\t\t\t\t\t\tconfigurable : true,\n\t\t\t\t\t\t\t\t\tenumerable   : true,\n\t\t\t\t\t\t\t\t\twritable     : true,\n\t\t\t\t\t\t\t\t\tvalue        : desc\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tacc[key] = desc; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{}\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a new array consisting of the given object's own enumerable property values.\n\t*/\n\tif (!Object.values) {\n\t\tObject.defineProperty(Object, 'values', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(obj) {\n\t\t\t\tif (typeof obj !== 'object' || obj === null) {\n\t\t\t\t\tthrow new TypeError('Object.values object parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\treturn Object.keys(obj).map(key => obj[key]);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a string based on concatenating the given padding, repeated as necessary,\n\t\tto the start of the string so that the given length is reached.\n\n\t\tNOTE: This pads based upon Unicode code units, rather than code points.\n\t*/\n\tif (!String.prototype.padStart) {\n\t\tObject.defineProperty(String.prototype, 'padStart', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(length, padding) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.padStart called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst baseString   = String(this);\n\t\t\t\tconst baseLength   = baseString.length;\n\t\t\t\tconst targetLength = Number.parseInt(length, 10);\n\n\t\t\t\tif (targetLength <= baseLength) {\n\t\t\t\t\treturn baseString;\n\t\t\t\t}\n\n\t\t\t\treturn _createPadString(targetLength - baseLength, padding) + baseString;\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2017] Returns a string based on concatenating the given padding, repeated as necessary,\n\t\tto the end of the string so that the given length is reached.\n\n\t\tNOTE: This pads based upon Unicode code units, rather than code points.\n\t*/\n\tif (!String.prototype.padEnd) {\n\t\tObject.defineProperty(String.prototype, 'padEnd', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(length, padding) {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.padEnd called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\tconst baseString   = String(this);\n\t\t\t\tconst baseLength   = baseString.length;\n\t\t\t\tconst targetLength = Number.parseInt(length, 10);\n\n\t\t\t\tif (targetLength <= baseLength) {\n\t\t\t\t\treturn baseString;\n\t\t\t\t}\n\n\t\t\t\treturn baseString + _createPadString(targetLength - baseLength, padding);\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a string with all whitespace removed from the start of the string.\n\t*/\n\tif (!String.prototype.trimStart) {\n\t\tObject.defineProperty(String.prototype, 'trimStart', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimStart called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'start');\n\t\t\t}\n\t\t});\n\t}\n\n\tif (!String.prototype.trimLeft) {\n\t\tObject.defineProperty(String.prototype, 'trimLeft', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimLeft called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'start');\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\t[ES2019] Returns a string with all whitespace removed from the end of the string.\n\t*/\n\tif (!String.prototype.trimEnd) {\n\t\tObject.defineProperty(String.prototype, 'trimEnd', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimEnd called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'end');\n\t\t\t}\n\t\t});\n\t}\n\n\tif (!String.prototype.trimRight) {\n\t\tObject.defineProperty(String.prototype, 'trimRight', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue() {\n\t\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError('String.prototype.trimRight called on null or undefined');\n\t\t\t\t}\n\n\t\t\t\treturn _trimString(this, 'end');\n\t\t\t}\n\t\t});\n\t}\n})();\n\n\n/*\n\tJavaScript Extensions.\n*/\n(() => {\n\t'use strict';\n\n\tconst _nativeMathRandom = Math.random;\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a pseudo-random whole number (integer) within the given bounds.\n\t*/\n\tfunction _random(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('_random called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = arguments[0];\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = arguments[0];\n\t\t\tmax = arguments[1];\n\t\t\tbreak;\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn Math.floor(_nativeMathRandom() * (max - min + 1)) + min;\n\t}\n\n\t/*\n\t\tReturns a randomly selected index within the given length and bounds.\n\t\tBounds may be negative.\n\t*/\n\tfunction _randomIndex(length, boundsArgs) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (boundsArgs.length) {\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = length - 1;\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tmin = 0;\n\t\t\tmax = Math.trunc(boundsArgs[1]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Math.trunc(boundsArgs[1]);\n\t\t\tmax = Math.trunc(boundsArgs[2]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (Number.isNaN(min)) {\n\t\t\tmin = 0;\n\t\t}\n\t\telse if (!Number.isFinite(min) || min >= length) {\n\t\t\tmin = length - 1;\n\t\t}\n\t\telse if (min < 0) {\n\t\t\tmin = length + min;\n\n\t\t\tif (min < 0) {\n\t\t\t\tmin = 0;\n\t\t\t}\n\t\t}\n\n\t\tif (Number.isNaN(max)) {\n\t\t\tmax = 0;\n\t\t}\n\t\telse if (!Number.isFinite(max) || max >= length) {\n\t\t\tmax = length - 1;\n\t\t}\n\t\telse if (max < 0) {\n\t\t\tmax = length + max;\n\n\t\t\tif (max < 0) {\n\t\t\t\tmax = length - 1;\n\t\t\t}\n\t\t}\n\n\t\treturn _random(min, max);\n\t}\n\n\t/*\n\t\tReturns an object (`{ char, start, end }`) containing the Unicode character at\n\t\tposition `pos`, its starting position, and its ending position—surrogate pairs\n\t\tare properly handled.  If `pos` is out-of-bounds, returns an object containing\n\t\tthe empty string and start/end positions of `-1`.\n\n\t\tThis function is necessary because JavaScript strings are sequences of UTF-16\n\t\tcode units, so surrogate pairs are exposed and thus must be handled.  While the\n\t\tES6/2015 standard does improve the situation somewhat, it does not alleviate\n\t\tthe need for this function.\n\n\t\tNOTE: Will throw exceptions on invalid surrogate pairs.\n\n\t\tIDEA: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt\n\t*/\n\tfunction _getCodePointStartAndEnd(str, pos) {\n\t\tconst code = str.charCodeAt(pos);\n\n\t\t// Given position was out-of-bounds.\n\t\tif (Number.isNaN(code)) {\n\t\t\treturn { char : '', start : -1, end : -1 };\n\t\t}\n\n\t\t// Code unit is not a UTF-16 surrogate.\n\t\tif (code < 0xD800 || code > 0xDFFF) {\n\t\t\treturn {\n\t\t\t\tchar  : str.charAt(pos),\n\t\t\t\tstart : pos,\n\t\t\t\tend   : pos\n\t\t\t};\n\t\t}\n\n\t\t// Code unit is a high surrogate (D800–DBFF).\n\t\tif (code >= 0xD800 && code <= 0xDBFF) {\n\t\t\tconst nextPos = pos + 1;\n\n\t\t\t// End of string.\n\t\t\tif (nextPos >= str.length) {\n\t\t\t\tthrow new Error('high surrogate without trailing low surrogate');\n\t\t\t}\n\n\t\t\tconst nextCode = str.charCodeAt(nextPos);\n\n\t\t\t// Next code unit is not a low surrogate (DC00–DFFF).\n\t\t\tif (nextCode < 0xDC00 || nextCode > 0xDFFF) {\n\t\t\t\tthrow new Error('high surrogate without trailing low surrogate');\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tchar  : str.charAt(pos) + str.charAt(nextPos),\n\t\t\t\tstart : pos,\n\t\t\t\tend   : nextPos\n\t\t\t};\n\t\t}\n\n\t\t// Code unit is a low surrogate (DC00–DFFF) in the first position.\n\t\tif (pos === 0) {\n\t\t\tthrow new Error('low surrogate without leading high surrogate');\n\t\t}\n\n\t\tconst prevPos  = pos - 1;\n\t\tconst prevCode = str.charCodeAt(prevPos);\n\n\t\t// Previous code unit is not a high surrogate (D800–DBFF).\n\t\tif (prevCode < 0xD800 || prevCode > 0xDBFF) {\n\t\t\tthrow new Error('low surrogate without leading high surrogate');\n\t\t}\n\n\t\treturn {\n\t\t\tchar  : str.charAt(prevPos) + str.charAt(pos),\n\t\t\tstart : prevPos,\n\t\t\tend   : pos\n\t\t};\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, General.\n\t*******************************************************************************************************************/\n\t/*\n\t\tRandomly selects an element from the given array, or array-like object, and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array, 'random', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(array /* DEPRECATED: [, [min ,] max] */) {\n\t\t\tif (\n\t\t\t\t   typeof array !== 'object'\n\t\t\t\t|| array === null\n\t\t\t\t|| !Object.prototype.hasOwnProperty.call(array, 'length')\n\t\t\t) {\n\t\t\t\tthrow new TypeError('Array.random array parameter must be an array or array-lke object');\n\t\t\t}\n\n\t\t\tconst length = array.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, Array.prototype.slice.call(arguments, 1));\n\n\t\t\treturn array[index];\n\t\t}\n\t});\n\n\t/*\n\t\tConcatenates one or more unique elements to the end of the base array\n\t\tand returns the result as a new array.  Elements which are arrays will\n\t\tbe merged—i.e. their elements will be concatenated, rather than the\n\t\tarray itself.\n\t*/\n\tObject.defineProperty(Array.prototype, 'concatUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.concatUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst result = Array.from(this);\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tconst items   = Array.prototype.reduce.call(arguments, (prev, cur) => prev.concat(cur), []);\n\t\t\tconst addSize = items.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst push    = Array.prototype.push;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = items[i];\n\n\t\t\t\tif (indexOf.call(result, value) === -1) {\n\t\t\t\t\tpush.call(result, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number of times the given element was found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'count', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex ] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.count called on null or undefined');\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst needle  = arguments[0];\n\t\t\tlet pos   = Number(arguments[1]) || 0;\n\t\t\tlet count = 0;\n\n\t\t\twhile ((pos = indexOf.call(this, needle, pos)) !== -1) {\n\t\t\t\t++count;\n\t\t\t\t++pos;\n\t\t\t}\n\n\t\t\treturn count;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the given elements from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'delete', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.delete called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst needles       = Array.prototype.concat.apply([], arguments);\n\t\t\tconst needlesLength = needles.length;\n\t\t\tconst indices       = [];\n\n\t\t\tfor (let i = 0; i < length; ++i) {\n\t\t\t\tconst value = this[i];\n\n\t\t\t\tfor (let j = 0; j < needlesLength; ++j) {\n\t\t\t\t\tconst needle = needles[j];\n\n\t\t\t\t\tif (value === needle || value !== value && needle !== needle) {\n\t\t\t\t\t\tindices.push(i);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst result = [];\n\n\t\t\t// Copy the elements (in original order).\n\t\t\tfor (let i = 0, iend = indices.length; i < iend; ++i) {\n\t\t\t\tresult[i] = this[indices[i]];\n\t\t\t}\n\n\t\t\tconst splice = Array.prototype.splice;\n\n\t\t\t// Delete the elements (in reverse order).\n\t\t\tfor (let i = indices.length - 1; i >= 0; --i) {\n\t\t\t\tsplice.call(this, indices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the elements at the given indices from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'deleteAt', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* indices */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.deleteAt called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst splice     = Array.prototype.splice;\n\t\t\tconst cpyIndices = [\n\t\t\t\t...(new Set(\n\t\t\t\t\tArray.prototype.concat.apply([], arguments)\n\t\t\t\t\t\t// Map negative indices to their positive counterparts,\n\t\t\t\t\t\t// so the Set can properly filter out duplicates.\n\t\t\t\t\t\t.map(x => x < 0 ? Math.max(0, length + x) : x)\n\t\t\t\t)).values()\n\t\t\t];\n\t\t\tconst delIndices = [...cpyIndices].sort((a, b) => b - a);\n\t\t\tconst result     = [];\n\n\t\t\t// Copy the elements (in originally specified order).\n\t\t\tfor (let i = 0, iend = cpyIndices.length; i < iend; ++i) {\n\t\t\t\tresult[i] = this[cpyIndices[i]];\n\t\t\t}\n\n\t\t\t// Delete the elements (in descending numeric order).\n\t\t\tfor (let i = 0, iend = delIndices.length; i < iend; ++i) {\n\t\t\t\tsplice.call(this, delIndices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRemoves and returns all of the elements that pass the test implemented\n\t\tby the given predicate function from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'deleteWith', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(predicate, thisArg) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.deleteWith called on null or undefined');\n\t\t\t}\n\t\t\tif (typeof predicate !== 'function') {\n\t\t\t\tthrow new Error('Array.prototype.deleteWith predicate parameter must be a function');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst splice  = Array.prototype.splice;\n\t\t\tconst indices = [];\n\t\t\tconst result  = [];\n\n\t\t\t// Copy the elements (in original order).\n\t\t\tfor (let i = 0; i < length; ++i) {\n\t\t\t\tif (predicate.call(thisArg, this[i], i, this)) {\n\t\t\t\t\tresult.push(this[i]);\n\t\t\t\t\tindices.push(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Delete the elements (in reverse order).\n\t\t\tfor (let i = indices.length - 1; i >= 0; --i) {\n\t\t\t\tsplice.call(this, indices[i], 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the first element from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'first', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.first called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn this[0];\n\t\t}\n\t});\n\n\t/*\n\t\tReturns whether all of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'includesAll', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.includesAll called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 1) {\n\t\t\t\tif (Array.isArray(arguments[0])) {\n\t\t\t\t\treturn Array.prototype.includesAll.apply(this, arguments[0]);\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = arguments.length; i < iend; ++i) {\n\t\t\t\tif (\n\t\t\t\t\t!Array.prototype.some.call(this, function (val) {\n\t\t\t\t\t\treturn val === this.val || val !== val && this.val !== this.val;\n\t\t\t\t\t}, { val : arguments[i] })\n\t\t\t\t) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns whether any of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'includesAny', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needles */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.includesAny called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length === 1) {\n\t\t\t\tif (Array.isArray(arguments[0])) {\n\t\t\t\t\treturn Array.prototype.includesAny.apply(this, arguments[0]);\n\t\t\t\t}\n\n\t\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = arguments.length; i < iend; ++i) {\n\t\t\t\tif (\n\t\t\t\t\tArray.prototype.some.call(this, function (val) {\n\t\t\t\t\t\treturn val === this.val || val !== val && this.val !== this.val;\n\t\t\t\t\t}, { val : arguments[i] })\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the last element from the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'last', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.last called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn this[length - 1];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly removes an element from the base array and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pluck', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* DEPRECATED: [min ,] max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pluck called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, [...arguments]);\n\n\t\t\treturn Array.prototype.splice.call(this, index, 1)[0];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly removes the given number of unique elements from the base array\n\t\tand returns the removed elements as a new array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pluckMany', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(wantSize) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pluckMany called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tlet want = Math.trunc(wantSize);\n\n\t\t\tif (!Number.isInteger(want)) {\n\t\t\t\tthrow new Error('Array.prototype.pluckMany want parameter must be an integer');\n\t\t\t}\n\n\t\t\tif (want < 1) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif (want > length) {\n\t\t\t\twant = length;\n\t\t\t}\n\n\t\t\tconst splice = Array.prototype.splice;\n\t\t\tconst result = [];\n\t\t\tlet max = length - 1;\n\n\t\t\tdo {\n\t\t\t\tresult.push(splice.call(this, _random(0, max--), 1)[0]);\n\t\t\t} while (result.length < want);\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tAppends one or more unique elements to the end of the base array and\n\t\treturns its new length.\n\t*/\n\tObject.defineProperty(Array.prototype, 'pushUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.pushUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst addSize = arguments.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn this.length >>> 0;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst push    = Array.prototype.push;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = arguments[i];\n\n\t\t\t\tif (indexOf.call(this, value) === -1) {\n\t\t\t\t\tpush.call(this, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.length >>> 0;\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly selects an element from the base array and returns it.\n\t\t[DEPRECATED] Optionally, from within the given bounds.\n\t*/\n\tObject.defineProperty(Array.prototype, 'random', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* DEPRECATED: [min ,] max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.random called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst index = arguments.length === 0\n\t\t\t\t? _random(0, length - 1)\n\t\t\t\t: _randomIndex(length, [...arguments]);\n\n\t\t\treturn this[index];\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly selects the given number of unique elements from the base array\n\t\tand returns the selected elements as a new array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'randomMany', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(wantSize) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.randomMany called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tlet want = Math.trunc(wantSize);\n\n\t\t\tif (!Number.isInteger(want)) {\n\t\t\t\tthrow new Error('Array.prototype.randomMany want parameter must be an integer');\n\t\t\t}\n\n\t\t\tif (want < 1) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tif (want > length) {\n\t\t\t\twant = length;\n\t\t\t}\n\n\t\t\tconst picked = new Map();\n\t\t\tconst result = [];\n\t\t\tconst max    = length - 1;\n\n\t\t\tdo {\n\t\t\t\tlet i;\n\t\t\t\tdo {\n\t\t\t\t\ti = _random(0, max);\n\t\t\t\t} while (picked.has(i));\n\t\t\t\tpicked.set(i, true);\n\t\t\t\tresult.push(this[i]);\n\t\t\t} while (result.length < want);\n\n\t\t\treturn result;\n\t\t}\n\t});\n\n\t/*\n\t\tRandomly shuffles the array and returns it.\n\t*/\n\tObject.defineProperty(Array.prototype, 'shuffle', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.shuffle called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tfor (let i = length - 1; i > 0; --i) {\n\t\t\t\tconst j = Math.floor(_nativeMathRandom() * (i + 1));\n\n\t\t\t\tif (i === j) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// [this[i], this[j]] = [this[j], this[i]];\n\t\t\t\tconst swap = this[i];\n\t\t\t\tthis[i] = this[j];\n\t\t\t\tthis[j] = swap;\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\t});\n\n\t/*\n\t\tPrepends one or more unique elements to the beginning of the base array\n\t\tand returns its new length.\n\t*/\n\tObject.defineProperty(Array.prototype, 'unshiftUnique', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.unshiftUnique called on null or undefined');\n\t\t\t}\n\n\t\t\tconst addSize = arguments.length;\n\n\t\t\tif (addSize === 0) {\n\t\t\t\treturn this.length >>> 0;\n\t\t\t}\n\n\t\t\tconst indexOf = Array.prototype.indexOf;\n\t\t\tconst unshift = Array.prototype.unshift;\n\n\t\t\tfor (let i = 0; i < addSize; ++i) {\n\t\t\t\tconst value = arguments[i];\n\n\t\t\t\tif (indexOf.call(this, value) === -1) {\n\t\t\t\t\tunshift.call(this, value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.length >>> 0;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a bound function that supplies the given arguments to the base\n\t\tfunction, followed by the arguments are supplied to the bound function,\n\t\twhenever it is called.\n\t*/\n\tObject.defineProperty(Function.prototype, 'partial', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* variadic */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Function.prototype.partial called on null or undefined');\n\t\t\t}\n\n\t\t\tconst slice = Array.prototype.slice;\n\t\t\tconst fn    = this;\n\t\t\tconst bound = slice.call(arguments, 0);\n\n\t\t\treturn function () {\n\t\t\t\tconst applied = [];\n\t\t\t\tlet argc = 0;\n\n\t\t\t\tfor (let i = 0; i < bound.length; ++i) {\n\t\t\t\t\tapplied.push(bound[i] === undefined ? arguments[argc++] : bound[i]);\n\t\t\t\t}\n\n\t\t\t\treturn fn.apply(this, applied.concat(slice.call(arguments, argc)));\n\t\t\t};\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the given numerical clamped to the specified bounds.\n\t*/\n\tObject.defineProperty(Math, 'clamp', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(num, min, max) {\n\t\t\tconst value = Number(num);\n\t\t\treturn Number.isNaN(value) ? NaN : value.clamp(min, max);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a decimal number eased from 0 to 1.\n\n\t\tNOTE: The magnitude of the returned value decreases if num < 0.5 or increases if num > 0.5.\n\t*/\n\tObject.defineProperty(Math, 'easeInOut', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(num) {\n\t\t\treturn 1 - (Math.cos(Number(num) * Math.PI) + 1) / 2;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number clamped to the specified bounds.\n\t*/\n\tObject.defineProperty(Number.prototype, 'clamp', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* min, max */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Number.prototype.clamp called on null or undefined');\n\t\t\t}\n\n\t\t\tif (arguments.length !== 2) {\n\t\t\t\tthrow new Error('Number.prototype.clamp called with an incorrect number of parameters');\n\t\t\t}\n\n\t\t\tlet min = Number(arguments[0]);\n\t\t\tlet max = Number(arguments[1]);\n\n\t\t\tif (min > max) {\n\t\t\t\t[min, max] = [max, min];\n\t\t\t}\n\n\t\t\treturn Math.min(Math.max(this, min), max);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the given string with all RegExp metacharacters escaped.\n\t*/\n\tif (!RegExp.escape) {\n\t\t(() => {\n\t\t\tconst _regExpMetaCharsRe    = /[\\\\^$*+?.()|[\\]{}]/g;\n\t\t\tconst _hasRegExpMetaCharsRe = new RegExp(_regExpMetaCharsRe.source); // to drop the global flag\n\n\t\t\tObject.defineProperty(RegExp, 'escape', {\n\t\t\t\tconfigurable : true,\n\t\t\t\twritable     : true,\n\n\t\t\t\tvalue(str) {\n\t\t\t\t\tconst val = String(str);\n\t\t\t\t\treturn val && _hasRegExpMetaCharsRe.test(val)\n\t\t\t\t\t\t? val.replace(_regExpMetaCharsRe, '\\\\$&')\n\t\t\t\t\t\t: val;\n\t\t\t\t}\n\t\t\t});\n\t\t})();\n\t}\n\n\t/*\n\t\tReturns a formatted string, after replacing each format item in the given\n\t\tformat string with the text equivalent of the corresponding argument's value.\n\t*/\n\t(() => {\n\t\tconst _formatRegExp    = /{(\\d+)(?:,([+-]?\\d+))?}/g;\n\t\tconst _hasFormatRegExp = new RegExp(_formatRegExp.source); // to drop the global flag\n\n\t\tObject.defineProperty(String, 'format', {\n\t\t\tconfigurable : true,\n\t\t\twritable     : true,\n\n\t\t\tvalue(format) {\n\t\t\t\tfunction padString(str, align, pad) {\n\t\t\t\t\tif (!align) {\n\t\t\t\t\t\treturn str;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst plen = Math.abs(align) - str.length;\n\n\t\t\t\t\tif (plen < 1) {\n\t\t\t\t\t\treturn str;\n\t\t\t\t\t}\n\n\t\t\t\t\t// const padding = Array(plen + 1).join(pad);\n\t\t\t\t\tconst padding = String(pad).repeat(plen);\n\t\t\t\t\treturn align < 0 ? str + padding : padding + str;\n\t\t\t\t}\n\n\t\t\t\tif (arguments.length < 2) {\n\t\t\t\t\treturn arguments.length === 0 ? '' : format;\n\t\t\t\t}\n\n\t\t\t\tconst args = arguments.length === 2 && Array.isArray(arguments[1])\n\t\t\t\t\t? [...arguments[1]]\n\t\t\t\t\t: Array.prototype.slice.call(arguments, 1);\n\n\t\t\t\tif (args.length === 0) {\n\t\t\t\t\treturn format;\n\t\t\t\t}\n\n\t\t\t\tif (!_hasFormatRegExp.test(format)) {\n\t\t\t\t\treturn format;\n\t\t\t\t}\n\n\t\t\t\t// Possibly required by some old buggy browsers.\n\t\t\t\t_formatRegExp.lastIndex = 0;\n\n\t\t\t\treturn format.replace(_formatRegExp, (match, index, align) => {\n\t\t\t\t\tlet retval = args[index];\n\n\t\t\t\t\tif (retval == null) { // lazy equality for null\n\t\t\t\t\t\treturn '';\n\t\t\t\t\t}\n\n\t\t\t\t\twhile (typeof retval === 'function') {\n\t\t\t\t\t\tretval = retval();\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (typeof retval) {\n\t\t\t\t\tcase 'string': /* no-op */ break;\n\t\t\t\t\tcase 'object': retval = JSON.stringify(retval); break;\n\t\t\t\t\tdefault:       retval = String(retval); break;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn padString(retval, !align ? 0 : Number.parseInt(align, 10), ' ');\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t})();\n\n\t/*\n\t\tReturns whether the given string was found within the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'contains', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.contains called on null or undefined');\n\t\t\t}\n\n\t\t\treturn String.prototype.indexOf.apply(this, arguments) !== -1;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the number of times the given substring was found within the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'count', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex ] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.count called on null or undefined');\n\t\t\t}\n\n\t\t\tconst needle = String(arguments[0] || '');\n\n\t\t\tif (needle === '') {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tconst indexOf = String.prototype.indexOf;\n\t\t\tconst step    = needle.length;\n\t\t\tlet pos     = Number(arguments[1]) || 0;\n\t\t\tlet count   = 0;\n\n\t\t\twhile ((pos = indexOf.call(this, needle, pos)) !== -1) {\n\t\t\t\t++count;\n\t\t\t\tpos += step;\n\t\t\t}\n\n\t\t\treturn count;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the first Unicode code point from the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'first', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.first called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn char;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns the last Unicode code point from the string.\n\t*/\n\tObject.defineProperty(String.prototype, 'last', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.last called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the last code point—may be one or two code units—and its end position.\n\t\t\tconst { char } = _getCodePointStartAndEnd(str, str.length - 1);\n\n\t\t\treturn char;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with `delCount` characters replaced with\n\t\t`replacement`, starting at `startAt`.\n\t*/\n\tObject.defineProperty(String.prototype, 'splice', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(startAt, delCount, replacement) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.splice called on null or undefined');\n\t\t\t}\n\n\t\t\tconst length = this.length >>> 0;\n\n\t\t\tif (length === 0) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tlet start = Number(startAt);\n\n\t\t\tif (!Number.isSafeInteger(start)) {\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t\telse if (start < 0) {\n\t\t\t\tstart += length;\n\n\t\t\t\tif (start < 0) {\n\t\t\t\t\tstart = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (start > length) {\n\t\t\t\tstart = length;\n\t\t\t}\n\n\t\t\tlet count = Number(delCount);\n\n\t\t\tif (!Number.isSafeInteger(count) || count < 0) {\n\t\t\t\tcount = 0;\n\t\t\t}\n\n\t\t\tlet res = this.slice(0, start);\n\n\t\t\tif (typeof replacement !== 'undefined') {\n\t\t\t\tres += replacement;\n\t\t\t}\n\n\t\t\tif (start + count < length) {\n\t\t\t\tres += this.slice(start + count);\n\t\t\t}\n\n\t\t\treturn res;\n\t\t}\n\t});\n\n\t/*\n\t\tReturns an array of strings, split from the string, or an empty array if the\n\t\tstring is empty.\n\t*/\n\tObject.defineProperty(String.prototype, 'splitOrEmpty', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* [ separator [, limit ]] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.splitOrEmpty called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tif (String(this) === '') {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\treturn String.prototype.split.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with the first Unicode code point uppercased,\n\t\taccording to any locale-specific rules.\n\t*/\n\tObject.defineProperty(String.prototype, 'toLocaleUpperFirst', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.toLocaleUpperFirst called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char, end } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn end === -1 ? '' : char.toLocaleUpperCase() + str.slice(end + 1);\n\t\t}\n\t});\n\n\t/*\n\t\tReturns a copy of the base string with the first Unicode code point uppercased.\n\t*/\n\tObject.defineProperty(String.prototype, 'toUpperFirst', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.toUpperFirst called on null or undefined');\n\t\t\t}\n\n\t\t\t// Required as `this` could be a `String` object or come from a `call()` or `apply()`.\n\t\t\tconst str = String(this);\n\n\t\t\t// Get the first code point—may be one or two code units—and its end position.\n\t\t\tconst { char, end } = _getCodePointStartAndEnd(str, 0);\n\n\t\t\treturn end === -1 ? '' : char.toUpperCase() + str.slice(end + 1);\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, JSON.\n\t*******************************************************************************************************************/\n\t/*\n\t\tDefine `toJSON()` methods on each prototype we wish to support.\n\t*/\n\tObject.defineProperty(Date.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:date)', this.toISOString()];\n\t\t}\n\t});\n\tObject.defineProperty(Function.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\t/*\n\t\t\t\tThe enclosing parenthesis here are necessary to force the function expression code\n\t\t\t\tstring, returned by `this.toString()`, to be evaluated as an expression during\n\t\t\t\trevival.  Without them, the function expression, which is likely nameless, will be\n\t\t\t\tevaluated as a function definition—which will throw a syntax error exception, since\n\t\t\t\tfunction definitions must have a name.\n\t\t\t*/\n\t\t\treturn ['(revive:eval)', `(${this.toString()})`];\n\t\t}\n\t});\n\tObject.defineProperty(Map.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:map)', [...this]];\n\t\t}\n\t});\n\tObject.defineProperty(RegExp.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:eval)', this.toString()];\n\t\t}\n\t});\n\tObject.defineProperty(Set.prototype, 'toJSON', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\treturn ['(revive:set)', [...this]];\n\t\t}\n\t});\n\n\t/*\n\t\tUtility method to allow users to easily wrap their code in the revive wrapper.\n\t*/\n\tObject.defineProperty(JSON, 'reviveWrapper', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(code, data) {\n\t\t\tif (typeof code !== 'string') {\n\t\t\t\tthrow new TypeError('JSON.reviveWrapper code parameter must be a string');\n\t\t\t}\n\n\t\t\treturn ['(revive:eval)', [code, data]];\n\t\t}\n\t});\n\n\t/*\n\t\tBackup the original `JSON.parse()` and replace it with a revive wrapper aware version.\n\t*/\n\tObject.defineProperty(JSON, '_real_parse', {\n\t\tvalue : JSON.parse\n\t});\n\tObject.defineProperty(JSON, 'parse', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(text, reviver) {\n\t\t\treturn JSON._real_parse(text, (key, val) => {\n\t\t\t\tlet value = val;\n\n\t\t\t\t/*\n\t\t\t\t\tAttempt to revive wrapped values.\n\t\t\t\t*/\n\t\t\t\tif (Array.isArray(value) && value.length === 2) {\n\t\t\t\t\tswitch (value[0]) {\n\t\t\t\t\tcase '(revive:set)':\n\t\t\t\t\t\tvalue = new Set(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:map)':\n\t\t\t\t\t\tvalue = new Map(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:date)':\n\t\t\t\t\t\tvalue = new Date(value[1]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '(revive:eval)':\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t/* eslint-disable no-eval */\n\t\t\t\t\t\t\t// For post-v2.9.0 `JSON.reviveWrapper()`.\n\t\t\t\t\t\t\tif (Array.isArray(value[1])) {\n\t\t\t\t\t\t\t\tconst $ReviveData$ = value[1][1]; // eslint-disable-line no-unused-vars\n\t\t\t\t\t\t\t\tvalue = eval(value[1][0]);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// For regular expressions, functions, and pre-v2.9.0 `JSON.reviveWrapper()`.\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tvalue = eval(value[1]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/* eslint-enable no-eval */\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* legacy */\n\t\t\t\telse if (typeof value === 'string' && value.slice(0, 10) === '@@revive@@') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvalue = eval(value.slice(10)); // eslint-disable-line no-eval\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t}\n\t\t\t\t/* /legacy */\n\n\t\t\t\t/*\n\t\t\t\t\tCall the custom reviver, if specified.\n\t\t\t\t*/\n\t\t\t\tif (typeof reviver === 'function') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvalue = reviver(key, value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) { /* no-op; although, perhaps, it would be better to throw an error here */ }\n\t\t\t\t}\n\n\t\t\t\treturn value;\n\t\t\t});\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tExtensions, Deprecated.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Returns whether the given element was found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'contains', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.contains called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includes.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns whether all of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'containsAll', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.containsAll called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includesAll.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns whether any of the given elements were found within the array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'containsAny', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue(/* needle [, fromIndex] */) {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.containsAny called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.includesAny.apply(this, arguments);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns a new array consisting of the flattened source array.\n\t*/\n\tObject.defineProperty(Array.prototype, 'flatten', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('Array.prototype.flatten called on null or undefined');\n\t\t\t}\n\n\t\t\treturn Array.prototype.flat.call(this, Infinity);\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] Returns an array of link titles, parsed from the string.\n\n\t\tNOTE: Unused in SugarCube, only included for compatibility.\n\t*/\n\tObject.defineProperty(String.prototype, 'readBracketedList', {\n\t\tconfigurable : true,\n\t\twritable     : true,\n\n\t\tvalue() {\n\t\t\tif (this == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('String.prototype.readBracketedList called on null or undefined');\n\t\t\t}\n\n\t\t\t// RegExp groups: Double-square-bracket quoted | Unquoted.\n\t\t\tconst re    = new RegExp('(?:\\\\[\\\\[((?:\\\\s|\\\\S)*?)\\\\]\\\\])|([^\"\\'\\\\s]\\\\S*)', 'gm');\n\t\t\tconst names = [];\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this)) !== null) {\n\t\t\t\tif (match[1]) { // double-square-bracket quoted\n\t\t\t\t\tnames.push(match[1]);\n\t\t\t\t}\n\t\t\t\telse if (match[2]) { // unquoted\n\t\t\t\t\tnames.push(match[2]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn names;\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/browser.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar Browser = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/* eslint-disable max-len */\n\tconst userAgent = navigator.userAgent.toLowerCase();\n\n\tconst winPhone = userAgent.includes('windows phone');\n\tconst isMobile = Object.freeze({\n\t\tAndroid    : !winPhone && userAgent.includes('android'),\n\t\tBlackBerry : /blackberry|bb10/.test(userAgent),\n\t\tiOS        : !winPhone && /ip(?:hone|ad|od)/.test(userAgent),\n\t\tOpera      : !winPhone && (typeof window.operamini === 'object' || userAgent.includes('opera mini')),\n\t\tWindows    : winPhone || /iemobile|wpdesktop/.test(userAgent),\n\n\t\tany() {\n\t\t\treturn isMobile.Android || isMobile.BlackBerry || isMobile.iOS || isMobile.Opera || isMobile.Windows;\n\t\t}\n\t});\n\n\tconst isGecko = !isMobile.Windows && !/khtml|trident|edge/.test(userAgent) && userAgent.includes('gecko');\n\n\tconst isIE      = !userAgent.includes('opera') && /msie|trident/.test(userAgent);\n\tconst ieVersion = isIE\n\t\t? (() => {\n\t\t\tconst ver = /(?:msie\\s+|rv:)(\\d+\\.\\d)/.exec(userAgent);\n\t\t\treturn ver ? Number(ver[1]) : 0;\n\t\t})()\n\t\t: null;\n\n\t// opera <= 12: \"opera/9.80 (windows nt 6.1; wow64) presto/2.12.388 version/12.16\"\n\t// opera >= 15: \"mozilla/5.0 (windows nt 6.1; wow64) applewebkit/537.36 (khtml, like gecko) chrome/28.0.1500.52 safari/537.36 opr/15.0.1147.130\"\n\tconst isOpera      = userAgent.includes('opera') || userAgent.includes(' opr/');\n\tconst operaVersion = isOpera\n\t\t? (() => {\n\t\t\tconst re  = new RegExp(`${/khtml|chrome/.test(userAgent) ? 'opr' : 'version'}\\\\/(\\\\d+\\\\.\\\\d+)`);\n\t\t\tconst ver = re.exec(userAgent);\n\t\t\treturn ver ? Number(ver[1]) : 0;\n\t\t})()\n\t\t: null;\n\n\tconst isVivaldi = userAgent.includes('vivaldi');\n\t/* eslint-enable max-len */\n\n\t// Module Exports.\n\treturn Object.freeze({\n\t\tuserAgent,\n\t\tisMobile,\n\t\tisGecko,\n\t\tisIE,\n\t\tieVersion,\n\t\tisOpera,\n\t\toperaVersion,\n\t\tisVivaldi\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/has.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser */\n\nvar Has = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tNOTE: The aggressive try/catch feature tests are necessitated by implementation\n\t\tbugs in various browsers.\n\t*/\n\n\t// Is the `HTMLAudioElement` API available?\n\tconst hasAudioElement = (() => {\n\t\ttry {\n\t\t\treturn typeof document.createElement('audio').canPlayType === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `File` API available?\n\tconst hasFile = (() => {\n\t\ttry {\n\t\t\treturn 'Blob' in window &&\n\t\t\t\t'File' in window &&\n\t\t\t\t'FileList' in window &&\n\t\t\t\t'FileReader' in window &&\n\t\t\t\t!Browser.isMobile.any() &&\n\t\t\t\t(!Browser.isOpera || Browser.operaVersion >= 15);\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `geolocation` API available?\n\tconst hasGeolocation = (() => {\n\t\ttry {\n\t\t\treturn 'geolocation' in navigator &&\n\t\t\t\ttypeof navigator.geolocation.getCurrentPosition === 'function' &&\n\t\t\t\ttypeof navigator.geolocation.watchPosition === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `MutationObserver` API available?\n\tconst hasMutationObserver = (() => {\n\t\ttry {\n\t\t\treturn 'MutationObserver' in window &&\n\t\t\t\ttypeof window.MutationObserver === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the `performance` API available?\n\tconst hasPerformance = (() => {\n\t\ttry {\n\t\t\treturn 'performance' in window &&\n\t\t\t\ttypeof window.performance.now === 'function';\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the platform a touch device?\n\tconst hasTouch = (() => {\n\t\ttry {\n\t\t\treturn 'ontouchstart' in window ||\n\t\t\t\t!!window.DocumentTouch &&\n\t\t\t\tdocument instanceof window.DocumentTouch ||\n\t\t\t\t!!navigator.maxTouchPoints ||\n\t\t\t\t!!navigator.msMaxTouchPoints;\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Is the transition end event available and by what name?\n\tconst hasTransitionEndEvent = (() => {\n\t\ttry {\n\t\t\tconst teMap = new Map([\n\t\t\t\t['transition',       'transitionend'],\n\t\t\t\t['MSTransition',     'msTransitionEnd'],\n\t\t\t\t['WebkitTransition', 'webkitTransitionEnd'],\n\t\t\t\t['MozTransition',    'transitionend']\n\t\t\t]);\n\t\t\tconst teKeys = [...teMap.keys()];\n\t\t\tconst el     = document.createElement('div');\n\n\t\t\tfor (let i = 0; i < teKeys.length; ++i) {\n\t\t\t\tif (el.style[teKeys[i]] !== undefined) {\n\t\t\t\t\treturn teMap.get(teKeys[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn false;\n\t})();\n\n\t// Module Exports.\n\treturn Object.freeze({\n\t\taudio              : hasAudioElement,\n\t\tfileAPI            : hasFile,\n\t\tgeolocation        : hasGeolocation,\n\t\tmutationObserver   : hasMutationObserver,\n\t\tperformance        : hasPerformance,\n\t\ttouch              : hasTouch,\n\t\ttransitionEndEvent : hasTransitionEndEvent\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/visibility.js\n\n\tCopyright © 2018–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar Visibility = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tThere are two versions of the Page Visibility API: First Edition and, the current,\n\t\tSecond Edition (i.e. \"Level 2\").  First Edition is mentioned here only because some\n\t\tolder browsers implement it, rather than the current specification.\n\n\t\tSEE:\n\t\t\tSecond Edition : https://www.w3.org/TR/page-visibility/\n\t\t\tFirst Edition  : https://www.w3.org/TR/2013/REC-page-visibility-20130514/\n\n\t\tNOTE: Generally, all supported browsers change the visibility state when either switching tabs\n\t\twithin the browser or minimizing the browser window.  Exceptions are noted below:\n\t\t\t* IE 9 doesn't support either version of the Page Visibility API.\n\t\t\t* Opera 12 (Presto) doesn't change the visibility state when the browser is minimized.\n\t*/\n\n\t// Vendor properties object.\n\tconst vendor = (() => {\n\t\ttry {\n\t\t\treturn Object.freeze([\n\t\t\t\t// Specification.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'hidden',          // boolean; historical in 2nd edition\n\t\t\t\t\tstateProperty  : 'visibilityState', // string, values: 'hidden', 'visible'; 1st edition had more values\n\t\t\t\t\tchangeEvent    : 'visibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `webkit` prefixed: old Blink & WebKit.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'webkitHidden',\n\t\t\t\t\tstateProperty  : 'webkitVisibilityState',\n\t\t\t\t\tchangeEvent    : 'webkitvisibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `moz` prefixed: old Gecko, maybe Seamonkey.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'mozHidden',\n\t\t\t\t\tstateProperty  : 'mozVisibilityState',\n\t\t\t\t\tchangeEvent    : 'mozvisibilitychange'\n\t\t\t\t},\n\n\t\t\t\t// `ms` prefixed: IE 10.\n\t\t\t\t{\n\t\t\t\t\thiddenProperty : 'msHidden',\n\t\t\t\t\tstateProperty  : 'msVisibilityState',\n\t\t\t\t\tchangeEvent    : 'msvisibilitychange'\n\t\t\t\t}\n\t\t\t].find(vnd => vnd.hiddenProperty in document));\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn undefined;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tAPI Functions.\n\t*******************************************************************************/\n\n\tfunction getVendor() {\n\t\treturn vendor;\n\t}\n\n\tfunction getVisibility() {\n\t\treturn vendor && document[vendor.stateProperty] || 'visible';\n\t}\n\n\tfunction isEnabled() {\n\t\treturn Boolean(vendor);\n\t}\n\n\tfunction isHidden() {\n\t\t// return Boolean(vendor && document[vendor.stateProperty] === 'hidden');\n\t\treturn Boolean(vendor && document[vendor.hiddenProperty]); // NOTE: Historical, but probably better for 1st edition.\n\t}\n\n\n\t/*******************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Functions.\n\t\tvendor    : { get : getVendor },\n\t\tstate     : { get : getVisibility },\n\t\tisEnabled : { value : isEnabled },\n\t\tisHidden  : { value : isHidden },\n\n\t\t// Properties.\n\t\thiddenProperty : { value : vendor && vendor.hiddenProperty },\n\t\tstateProperty  : { value : vendor && vendor.stateProperty },\n\t\tchangeEvent    : { value : vendor && vendor.changeEvent }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/fullscreen.js\n\n\tCopyright © 2018–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser */\n\nvar Fullscreen = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tSEE:\n\t\t\thttps://fullscreen.spec.whatwg.org\n\t\t\thttps://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API\n\t*/\n\n\t// Vendor properties object.\n\tconst vendor = (() => {\n\t\ttry {\n\t\t\treturn Object.freeze([\n\t\t\t\t// Specification.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'fullscreenEnabled',\n\t\t\t\t\telement     : 'fullscreenElement',\n\t\t\t\t\trequestFn   : 'requestFullscreen',\n\t\t\t\t\texitFn      : 'exitFullscreen',\n\t\t\t\t\tchangeEvent : 'fullscreenchange', // prop: onfullscreenchange\n\t\t\t\t\terrorEvent  : 'fullscreenerror'   // prop: onfullscreenerror\n\t\t\t\t},\n\n\t\t\t\t// `webkit` prefixed: old Blink, WebKit, & Edge.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'webkitFullscreenEnabled',\n\t\t\t\t\telement     : 'webkitFullscreenElement',\n\t\t\t\t\trequestFn   : 'webkitRequestFullscreen',\n\t\t\t\t\texitFn      : 'webkitExitFullscreen',\n\t\t\t\t\tchangeEvent : 'webkitfullscreenchange',\n\t\t\t\t\terrorEvent  : 'webkitfullscreenerror'\n\t\t\t\t},\n\n\t\t\t\t// `moz` prefixed: old Gecko, maybe Seamonkey.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'mozFullScreenEnabled',\n\t\t\t\t\telement     : 'mozFullScreenElement',\n\t\t\t\t\trequestFn   : 'mozRequestFullScreen',\n\t\t\t\t\texitFn      : 'mozCancelFullScreen',\n\t\t\t\t\tchangeEvent : 'mozfullscreenchange',\n\t\t\t\t\terrorEvent  : 'mozfullscreenerror'\n\t\t\t\t},\n\n\t\t\t\t// `ms` prefixed: IE 11.\n\t\t\t\t{\n\t\t\t\t\tisEnabled   : 'msFullscreenEnabled',\n\t\t\t\t\telement     : 'msFullscreenElement',\n\t\t\t\t\trequestFn   : 'msRequestFullscreen',\n\t\t\t\t\texitFn      : 'msExitFullscreen',\n\t\t\t\t\tchangeEvent : 'MSFullscreenChange',\n\t\t\t\t\terrorEvent  : 'MSFullscreenError'\n\t\t\t\t}\n\t\t\t].find(vnd => vnd.isEnabled in document));\n\t\t}\n\t\tcatch (ex) { /* no-op */ }\n\n\t\treturn undefined;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tFeature Detection Functions.\n\t*******************************************************************************/\n\n\t// Return whether the request and exit fullscreen methods return a `Promise`.\n\t//\n\t// NOTE: The initial result is cached for future calls.\n\tconst _returnsPromise = (function () {\n\t\t// Cache of whether the request and exit methods return a `Promise`.\n\t\tlet _hasPromise = null;\n\n\t\tfunction _returnsPromise() {\n\t\t\tif (_hasPromise !== null) {\n\t\t\t\treturn _hasPromise;\n\t\t\t}\n\n\t\t\t_hasPromise = false;\n\n\t\t\tif (vendor) {\n\t\t\t\ttry {\n\t\t\t\t\tconst value = document.exitFullscreen();\n\n\t\t\t\t\t// Silence \"Uncaught (in promise)\" console errors from Blink.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: Swallowing errors is generally bad, but in this case we know there's\n\t\t\t\t\t// going to be an error regardless, since we shouldn't be in fullscreen yet,\n\t\t\t\t\t// and we don't actually care about the error, since we just want the return\n\t\t\t\t\t// value, so we consign it to the bit bucket.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: We don't ensure that the return value is not `undefined` here because\n\t\t\t\t\t// having the attempted call to `<Promise>.catch()` on an `undefined` value throw\n\t\t\t\t\t// is acceptable, since it will be caught and `false` eventually returned.\n\t\t\t\t\tvalue.catch(() => { /* no-op */ });\n\n\t\t\t\t\t_hasPromise = value instanceof Promise;\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t}\n\n\t\t\treturn _hasPromise;\n\t\t}\n\n\t\treturn _returnsPromise;\n\t})();\n\n\n\t/*******************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************/\n\n\tfunction _selectElement(requestedEl) {\n\t\tlet selectedEl = requestedEl || document.documentElement;\n\n\t\t// Document element scrolling workaround for older browsers.\n\t\tif (\n\t\t\t   selectedEl === document.documentElement\n\t\t\t&& (\n\t\t\t\t   vendor.requestFn === 'msRequestFullscreen'   // IE 11\n\t\t\t\t|| Browser.isOpera && Browser.operaVersion < 15 // Opera 12 (Presto)\n\t\t\t)\n\t\t) {\n\t\t\tselectedEl = document.body;\n\t\t}\n\n\t\treturn selectedEl;\n\t}\n\n\n\t/*******************************************************************************\n\t\tAPI Functions.\n\t*******************************************************************************/\n\n\tfunction getVendor() {\n\t\treturn vendor;\n\t}\n\n\tfunction getElement() {\n\t\treturn (vendor || null) && document[vendor.element];\n\t}\n\n\tfunction isEnabled() {\n\t\treturn Boolean(vendor && document[vendor.isEnabled]);\n\t}\n\n\tfunction isFullscreen() {\n\t\treturn Boolean(vendor && document[vendor.element]);\n\t}\n\n\tfunction requestFullscreen(options, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn Promise.reject(new Error('fullscreen not supported'));\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (typeof element[vendor.requestFn] !== 'function') {\n\t\t\treturn Promise.reject(new Error('fullscreen not supported'));\n\t\t}\n\t\tif (isFullscreen()) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tif (_returnsPromise()) {\n\t\t\treturn element[vendor.requestFn](options);\n\t\t}\n\t\telse { // eslint-disable-line no-else-return\n\t\t\tconst namespace = '.Fullscreen_requestFullscreen';\n\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tjQuery(element)\n\t\t\t\t\t.off(namespace)\n\t\t\t\t\t.one(`${vendor.errorEvent}${namespace} ${vendor.changeEvent}${namespace}`, ev => {\n\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\tif (ev.type === vendor.errorEvent) {\n\t\t\t\t\t\t\treject(new Error('unknown fullscreen request error'));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\telement[vendor.requestFn](options);\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction exitFullscreen() {\n\t\tif (!vendor || typeof document[vendor.exitFn] !== 'function') {\n\t\t\treturn Promise.reject(new TypeError('fullscreen not supported'));\n\t\t}\n\t\tif (!isFullscreen()) {\n\t\t\treturn Promise.reject(new TypeError('fullscreen mode not active'));\n\t\t}\n\n\t\tif (_returnsPromise()) {\n\t\t\treturn document[vendor.exitFn]();\n\t\t}\n\t\telse { // eslint-disable-line no-else-return\n\t\t\tconst namespace = '.Fullscreen_exitFullscreen';\n\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tjQuery(document)\n\t\t\t\t\t.off(namespace)\n\t\t\t\t\t.one(`${vendor.errorEvent}${namespace} ${vendor.changeEvent}${namespace}`, ev => {\n\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\tif (ev.type === vendor.errorEvent) {\n\t\t\t\t\t\t\treject(new Error('unknown fullscreen exit error'));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tdocument[vendor.exitFn]();\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction toggleFullscreen(options, requestedEl) {\n\t\treturn isFullscreen() ? exitFullscreen() : requestFullscreen(options, requestedEl);\n\t}\n\n\tfunction onChange(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\t$(element).on(vendor.changeEvent, handlerFn);\n\t}\n\n\tfunction offChange(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (handlerFn) {\n\t\t\t$(element).off(vendor.changeEvent, handlerFn);\n\t\t}\n\t\telse {\n\t\t\t$(element).off(vendor.changeEvent);\n\t\t}\n\t}\n\n\tfunction onError(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\t$(element).on(vendor.errorEvent, handlerFn);\n\t}\n\n\tfunction offError(handlerFn, requestedEl) {\n\t\tif (!vendor) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = _selectElement(requestedEl);\n\n\t\tif (handlerFn) {\n\t\t\t$(element).off(vendor.errorEvent, handlerFn);\n\t\t}\n\t\telse {\n\t\t\t$(element).off(vendor.errorEvent);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tvendor       : { get : getVendor },\n\t\telement      : { get : getElement },\n\t\tisEnabled    : { value : isEnabled },\n\t\tisFullscreen : { value : isFullscreen },\n\t\trequest      : { value : requestFullscreen },\n\t\texit         : { value : exitFullscreen },\n\t\ttoggle       : { value : toggleFullscreen },\n\t\tonChange     : { value : onChange },\n\t\toffChange    : { value : offChange },\n\t\tonError      : { value : onError },\n\t\toffError     : { value : offError }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/helpers.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, L10n, State, Story, Util, Wikifier */\n\nvar { // eslint-disable-line no-var\n\t/* eslint-disable no-unused-vars */\n\tclone,\n\tconvertBreaks,\n\tsafeActiveElement,\n\tsetDisplayTitle,\n\tsetPageElement,\n\tthrowError,\n\ttoStringOrDefault\n\t/* eslint-enable no-unused-vars */\n} = (() => {\n\t'use strict';\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _getTextContent(source) {\n\t\tconst copy = source.cloneNode(true);\n\t\tconst frag = document.createDocumentFragment();\n\t\tlet node;\n\n\t\twhile ((node = copy.firstChild) !== null) {\n\t\t\t// Insert spaces before various elements.\n\t\t\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tswitch (node.nodeName.toUpperCase()) {\n\t\t\t\tcase 'BR':\n\t\t\t\tcase 'DIV':\n\t\t\t\tcase 'P':\n\t\t\t\t\tfrag.appendChild(document.createTextNode(' '));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfrag.appendChild(node);\n\t\t}\n\n\t\treturn frag.textContent;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tHelper Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a deep copy of the given object.\n\n\t\tNOTE:\n\t\t\t1. `clone()` does not clone functions, however, since function definitions\n\t\t\t   are immutable, the only issues are with expando properties and scope.\n\t\t\t   The former really should not be done.  The latter is problematic either\n\t\t\t   way—damned if you do, damned if you don't.\n\t\t\t2. `clone()` does not maintain referential relationships—e.g. multiple\n\t\t\t   references to the same object will, post-cloning, refer to different\n\t\t\t   equivalent objects; i.e. each reference will receive its own clone\n\t\t\t   of the original object.\n\t*/\n\tfunction clone(orig) {\n\t\t/*\n\t\t\tImmediately return the primitives and functions.\n\t\t*/\n\t\tif (typeof orig !== 'object' || orig === null) {\n\t\t\treturn orig;\n\t\t}\n\n\t\t/*\n\t\t\tUnbox instances of the primitive exemplar objects.\n\t\t*/\n\t\tif (orig instanceof String) {\n\t\t\treturn String(orig);\n\t\t}\n\t\tif (orig instanceof Number) {\n\t\t\treturn Number(orig);\n\t\t}\n\t\tif (orig instanceof Boolean) {\n\t\t\treturn Boolean(orig);\n\t\t}\n\n\t\t/*\n\t\t\tHonor native clone methods.\n\t\t*/\n\t\tif (typeof orig.clone === 'function') {\n\t\t\treturn orig.clone(true);\n\t\t}\n\t\tif (orig.nodeType && typeof orig.cloneNode === 'function') {\n\t\t\treturn orig.cloneNode(true);\n\t\t}\n\n\t\t/*\n\t\t\tCreate a copy of the original object.\n\n\t\t\tNOTE: Each non-generic object that we wish to support must be\n\t\t\texplicitly handled below.\n\t\t*/\n\t\tlet copy;\n\n\t\t// Handle instances of the core supported object types.\n\t\tif (orig instanceof Array) {\n\t\t\tcopy = new Array(orig.length);\n\t\t}\n\t\telse if (orig instanceof Date) {\n\t\t\tcopy = new Date(orig.getTime());\n\t\t}\n\t\telse if (orig instanceof Map) {\n\t\t\tcopy = new Map();\n\t\t\torig.forEach((val, key) => copy.set(key, clone(val)));\n\t\t}\n\t\telse if (orig instanceof RegExp) {\n\t\t\tcopy = new RegExp(orig);\n\t\t}\n\t\telse if (orig instanceof Set) {\n\t\t\tcopy = new Set();\n\t\t\torig.forEach(val => copy.add(clone(val)));\n\t\t}\n\n\t\t// Handle instances of unknown or generic objects.\n\t\telse {\n\t\t\t// We try to ensure that the returned copy has the same prototype as\n\t\t\t// the original, but this will probably produce less than satisfactory\n\t\t\t// results on non-generics.\n\t\t\tcopy = Object.create(Object.getPrototypeOf(orig));\n\t\t}\n\n\t\t/*\n\t\t\tDuplicate the original object's own enumerable properties, which will\n\t\t\tinclude expando properties on non-generic objects.\n\n\t\t\tNOTE: This preserves neither symbol properties nor ES5 property attributes.\n\t\t\tNeither does the delta coding or serialization code, however, so it's not\n\t\t\treally an issue at the moment.\n\t\t*/\n\t\tObject.keys(orig).forEach(name => copy[name] = clone(orig[name]));\n\n\t\treturn copy;\n\t}\n\n\t/*\n\t\tConverts <br> elements to <p> elements within the given node tree.\n\t*/\n\tfunction convertBreaks(source) {\n\t\tconst output = document.createDocumentFragment();\n\t\tlet para = document.createElement('p');\n\t\tlet node;\n\n\t\twhile ((node = source.firstChild) !== null) {\n\t\t\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tconst tagName = node.nodeName.toUpperCase();\n\n\t\t\t\tswitch (tagName) {\n\t\t\t\tcase 'BR':\n\t\t\t\t\tif (\n\t\t\t\t\t\t   node.nextSibling !== null\n\t\t\t\t\t\t&& node.nextSibling.nodeType === Node.ELEMENT_NODE\n\t\t\t\t\t\t&& node.nextSibling.nodeName.toUpperCase() === 'BR'\n\t\t\t\t\t) {\n\t\t\t\t\t\tsource.removeChild(node.nextSibling);\n\t\t\t\t\t\tsource.removeChild(node);\n\t\t\t\t\t\toutput.appendChild(para);\n\t\t\t\t\t\tpara = document.createElement('p');\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\telse if (!para.hasChildNodes()) {\n\t\t\t\t\t\tsource.removeChild(node);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'ADDRESS':\n\t\t\t\tcase 'ARTICLE':\n\t\t\t\tcase 'ASIDE':\n\t\t\t\tcase 'BLOCKQUOTE':\n\t\t\t\tcase 'CENTER':\n\t\t\t\tcase 'DIV':\n\t\t\t\tcase 'DL':\n\t\t\t\tcase 'FIGURE':\n\t\t\t\tcase 'FOOTER':\n\t\t\t\tcase 'FORM':\n\t\t\t\tcase 'H1':\n\t\t\t\tcase 'H2':\n\t\t\t\tcase 'H3':\n\t\t\t\tcase 'H4':\n\t\t\t\tcase 'H5':\n\t\t\t\tcase 'H6':\n\t\t\t\tcase 'HEADER':\n\t\t\t\tcase 'HR':\n\t\t\t\tcase 'MAIN':\n\t\t\t\tcase 'NAV':\n\t\t\t\tcase 'OL':\n\t\t\t\tcase 'P':\n\t\t\t\tcase 'PRE':\n\t\t\t\tcase 'SECTION':\n\t\t\t\tcase 'TABLE':\n\t\t\t\tcase 'UL':\n\t\t\t\t\tif (para.hasChildNodes()) {\n\t\t\t\t\t\toutput.appendChild(para);\n\t\t\t\t\t\tpara = document.createElement('p');\n\t\t\t\t\t}\n\n\t\t\t\t\toutput.appendChild(node);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpara.appendChild(node);\n\t\t}\n\n\t\tif (para.hasChildNodes()) {\n\t\t\toutput.appendChild(para);\n\t\t}\n\n\t\tsource.appendChild(output);\n\t}\n\n\t/*\n\t\tReturns `document.activeElement` or `null`.\n\t*/\n\tfunction safeActiveElement() {\n\t\t/*\n\t\t\tIE9 contains a bug where trying to access the active element of an iframe's\n\t\t\tparent document (i.e. `window.parent.document.activeElement`) will throw an\n\t\t\texception, so we must allow for an exception to be thrown.\n\n\t\t\tWe could simply return `undefined` here, but since the API's default behavior\n\t\t\tshould be to return `document.body` or `null` when there is no selection, we\n\t\t\tchoose to return `null` in all non-element cases (i.e. whether it returns\n\t\t\t`null` or throws an exception).  Just a bit of normalization.\n\t\t*/\n\t\ttry {\n\t\t\treturn document.activeElement || null;\n\t\t}\n\t\tcatch (ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/*\n\t\tSets the display title.\n\t*/\n\tfunction setDisplayTitle(title) {\n\t\tif (typeof title !== 'string') {\n\t\t\tthrow new TypeError(`story display title must be a string (received: ${Util.getType(title)})`);\n\t\t}\n\n\t\tconst render = document.createDocumentFragment();\n\t\tnew Wikifier(render, title);\n\n\t\tconst text = _getTextContent(render).trim();\n\n\t\t// if (text === '') {\n\t\t// \tthrow new Error('story display title must not render to an empty string or consist solely of whitespace');\n\t\t// }\n\n\t\tdocument.title = Config.passages.displayTitles && State.passage !== '' && State.passage !== Config.passages.start\n\t\t\t? `${State.passage} | ${text}`\n\t\t\t: text;\n\n\t\tconst storyTitle = document.getElementById('story-title');\n\n\t\tif (storyTitle !== null) {\n\t\t\tjQuery(storyTitle).empty().append(render);\n\t\t}\n\t}\n\n\t/*\n\t\tWikifies a passage into a DOM element corresponding to the passed ID and returns the element.\n\t*/\n\tfunction setPageElement(idOrElement, titles, defaultText) {\n\t\tconst el = typeof idOrElement === 'object'\n\t\t\t? idOrElement\n\t\t\t: document.getElementById(idOrElement);\n\n\t\tif (el == null) { // lazy equality for null\n\t\t\treturn null;\n\t\t}\n\n\t\tconst ids = Array.isArray(titles) ? titles : [titles];\n\n\t\tjQuery(el).empty();\n\n\t\tfor (let i = 0, iend = ids.length; i < iend; ++i) {\n\t\t\tif (Story.has(ids[i])) {\n\t\t\t\tnew Wikifier(el, Story.get(ids[i]).processText().trim());\n\t\t\t\treturn el;\n\t\t\t}\n\t\t}\n\n\t\tif (defaultText != null) { // lazy equality for null\n\t\t\tconst text = String(defaultText).trim();\n\n\t\t\tif (text !== '') {\n\t\t\t\tnew Wikifier(el, text);\n\t\t\t}\n\t\t}\n\n\t\treturn el;\n\t}\n\n\t/*\n\t\tAppends an error view to the passed DOM element.\n\t*/\n\tfunction throwError(place, message, source, stack) {\n\t\tconst $wrapper = jQuery(document.createElement('div'));\n\t\tconst $toggle  = jQuery(document.createElement('button'));\n\t\tconst $source  = jQuery(document.createElement('pre'));\n\t\tconst mesg     = `${L10n.get('errorTitle')}: ${message || 'unknown error'}`;\n\n\t\t$toggle\n\t\t\t.addClass('error-toggle')\n\t\t\t.ariaClick({\n\t\t\t\tlabel : L10n.get('errorToggle')\n\t\t\t}, () => {\n\t\t\t\tif ($toggle.hasClass('enabled')) {\n\t\t\t\t\t$toggle.removeClass('enabled');\n\t\t\t\t\t$source.attr({\n\t\t\t\t\t\t'aria-hidden' : true,\n\t\t\t\t\t\thidden        : 'hidden'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$toggle.addClass('enabled');\n\t\t\t\t\t$source.removeAttr('aria-hidden hidden');\n\t\t\t\t}\n\t\t\t})\n\t\t\t.appendTo($wrapper);\n\t\tjQuery(document.createElement('span'))\n\t\t\t.addClass('error')\n\t\t\t.text(mesg)\n\t\t\t.appendTo($wrapper);\n\t\tjQuery(document.createElement('code'))\n\t\t\t.text(source)\n\t\t\t.appendTo($source);\n\t\t$source\n\t\t\t.addClass('error-source')\n\t\t\t.attr({\n\t\t\t\t'aria-hidden' : true,\n\t\t\t\thidden        : 'hidden'\n\t\t\t})\n\t\t\t.appendTo($wrapper);\n\t\tif (stack) {\n\t\t\tconst lines = stack.split('\\n');\n\t\t\tfor (const ll of lines) {\n\t\t\t\tconst div = document.createElement('div');\n\t\t\t\tdiv.append(ll.replace(/file:.*\\//, '<path>/'));\n\t\t\t\t$source.append(div);\n\t\t\t}\n\t\t}\n\t\t$wrapper\n\t\t\t.addClass('error-view')\n\t\t\t.appendTo(place);\n\n\t\tconsole.warn(`${mesg}\\n\\t${source.replace(/\\n/g, '\\n\\t')}`);\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tReturns the simple string representation of the passed value or, if there is none,\n\t\tthe passed default value.\n\t*/\n\tfunction toStringOrDefault(value, defValue) {\n\t\tconst tSOD = toStringOrDefault;\n\n\t\tswitch (typeof value) {\n\t\tcase 'number':\n\t\t\t// TODO: Perhaps NaN should be printed instead?\n\t\t\tif (Number.isNaN(value)) {\n\t\t\t\treturn defValue;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\tif (value === null) {\n\t\t\t\treturn defValue;\n\t\t\t}\n\t\t\telse if (Array.isArray(value)) {\n\t\t\t\treturn value.map(val => tSOD(val, defValue)).join(', ');\n\t\t\t}\n\t\t\telse if (value instanceof Set) {\n\t\t\t\treturn [...value].map(val => tSOD(val, defValue)).join(', ');\n\t\t\t}\n\t\t\telse if (value instanceof Map) {\n\t\t\t\tconst result = [...value].map(([key, val]) => `${tSOD(key, defValue)} \\u2192 ${tSOD(val, defValue)}`);\n\t\t\t\treturn `{\\u202F${result.join(', ')}\\u202F}`;\n\t\t\t}\n\t\t\telse if (value instanceof Date) {\n\t\t\t\treturn value.toLocaleString();\n\t\t\t}\n\t\t\telse if (typeof value.toString === 'function') {\n\t\t\t\treturn value.toString();\n\t\t\t}\n\t\t\treturn Object.prototype.toString.call(value);\n\n\t\tcase 'function':\n\t\tcase 'undefined':\n\t\t\treturn defValue;\n\t\t}\n\n\t\treturn String(value);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tclone             : { value : clone },\n\t\tconvertBreaks     : { value : convertBreaks },\n\t\tsafeActiveElement : { value : safeActiveElement },\n\t\tsetDisplayTitle   : { value : setDisplayTitle },\n\t\tsetPageElement    : { value : setPageElement },\n\t\tthrowError        : { value : throwError },\n\t\ttoStringOrDefault : { value : toStringOrDefault }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/jquery-plugins.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Wikifier, errorPrologRegExp, safeActiveElement */\n\n/*\n\tWAI-ARIA methods plugin.\n\n\t`<jQuery>.ariaClick([options,] handler)`\n\t    Makes the target element(s) WAI-ARIA compatible clickables.\n\n\t`<jQuery>.ariaDisabled(state)`\n\t    Changes the disabled state of the target WAI-ARIA-compatible clickable element(s).\n\n\t`<jQuery>.ariaIsDisabled()`\n\t    Checks the disabled status of the target WAI-ARIA-compatible clickable element(s).\n*/\n(() => {\n\t'use strict';\n\n\t/*\n\t\tEvent handler & utility functions.\n\n\t\tNOTE: Do not replace the anonymous functions herein with arrow functions.\n\t*/\n\tfunction onKeypressFn(ev) {\n\t\t// 13 is Enter/Return, 32 is Space.\n\t\tif (ev.which === 13 || ev.which === 32) {\n\t\t\tev.preventDefault();\n\n\t\t\t// To allow delegation, attempt to trigger the event on `document.activeElement`,\n\t\t\t// if possible, elsewise on `this`.\n\t\t\tjQuery(safeActiveElement() || this).trigger('click');\n\t\t}\n\t}\n\n\tfunction onClickFnWrapper(fn) {\n\t\treturn function () {\n\t\t\tconst $this = jQuery(this);\n\n\t\t\tconst dataPassage = $this.attr('data-passage');\n\t\t\tconst initialDataPassage = window && window.SugarCube && window.SugarCube.State && window.SugarCube.State.passage;\n\t\t\tconst savedYOffset = window.pageYOffset;\n\n\t\t\t// Toggle \"aria-pressed\" status, if the attribute exists.\n\t\t\tif ($this.is('[aria-pressed]')) {\n\t\t\t\t$this.attr('aria-pressed', $this.attr('aria-pressed') === 'true' ? 'false' : 'true');\n\t\t\t}\n\n\t\t\t// Call the true handler.\n\t\t\tfn.apply(this, arguments);\n\n\t\t\tconst doJump = function(){ window.scrollTo(0, savedYOffset); }\n\t\t\tif ( dataPassage && (window.lastDataPassageLink === dataPassage || initialDataPassage === dataPassage))\n\t\t\t\tdoJump();\n\t\t\twindow.lastDataPassageLink = dataPassage;\n\t\t};\n\t}\n\n\tfunction oneClickFnWrapper(fn) {\n\t\treturn onClickFnWrapper(function () {\n\t\t\t// Remove both event handlers (keypress & click) and the other components.\n\t\t\tjQuery(this)\n\t\t\t\t.off('.aria-clickable')\n\t\t\t\t.removeAttr('tabindex aria-controls aria-pressed')\n\t\t\t\t.not('a,button')\n\t\t\t\t.removeAttr('role')\n\t\t\t\t.end()\n\t\t\t\t.filter('button')\n\t\t\t\t.prop('disabled', true);\n\n\t\t\t// Call the true handler.\n\t\t\tfn.apply(this, arguments);\n\t\t});\n\t}\n\n\tjQuery.fn.extend({\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaClick()` method.\n\t\t*/\n\t\tariaClick(options, handler) {\n\t\t\t// Bail out if there are no target element(s) or parameters.\n\t\t\tif (this.length === 0 || arguments.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tlet opts = options;\n\t\t\tlet fn   = handler;\n\n\t\t\tif (fn == null) { // lazy equality for null\n\t\t\t\tfn   = opts;\n\t\t\t\topts = undefined;\n\t\t\t}\n\n\t\t\topts = jQuery.extend({\n\t\t\t\tnamespace : undefined,\n\t\t\t\tone       : false,\n\t\t\t\tselector  : undefined,\n\t\t\t\tdata      : undefined,\n\t\t\t\tcontrols  : undefined,\n\t\t\t\tpressed   : undefined,\n\t\t\t\tlabel     : undefined\n\t\t\t}, opts);\n\n\t\t\tif (typeof opts.namespace !== 'string') {\n\t\t\t\topts.namespace = '';\n\t\t\t}\n\t\t\telse if (opts.namespace[0] !== '.') {\n\t\t\t\topts.namespace = `.${opts.namespace}`;\n\t\t\t}\n\n\t\t\tif (typeof opts.pressed === 'boolean') {\n\t\t\t\topts.pressed = opts.pressed ? 'true' : 'false';\n\t\t\t}\n\n\t\t\t// Set `type` to `button` to suppress \"submit\" semantics, for <button> elements.\n\t\t\tthis.filter('button').prop('type', 'button');\n\n\t\t\t// Set `role` to `button`, for non-<a>/-<button> elements.\n\t\t\tthis.not('a,button').attr('role', 'button');\n\n\t\t\t// Set `tabindex` to `0` to make them focusable (unnecessary on <button> elements, but it doesn't hurt).\n\t\t\tthis.attr('tabindex', 0);\n\n\t\t\t// Set `aria-controls`.\n\t\t\tif (opts.controls != null) { // lazy equality for null\n\t\t\t\tthis.attr('aria-controls', opts.controls);\n\t\t\t}\n\n\t\t\t// Set `aria-pressed`.\n\t\t\tif (opts.pressed != null) { // lazy equality for null\n\t\t\t\tthis.attr('aria-pressed', opts.pressed);\n\t\t\t}\n\n\t\t\t// Set `aria-label` and `title`.\n\t\t\tif (opts.label != null) { // lazy equality for null\n\t\t\t\tthis.attr({\n\t\t\t\t\t'aria-label' : opts.label,\n\t\t\t\t\ttitle        : opts.label\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Set the keypress handlers, for non-<button> elements.\n\t\t\t// NOTE: For the single-use case, the click handler will also remove this handler.\n\t\t\tthis.not('button').on(\n\t\t\t\t`keypress.aria-clickable${opts.namespace}`,\n\t\t\t\topts.selector,\n\t\t\t\tonKeypressFn\n\t\t\t);\n\n\t\t\t// Set the click handlers.\n\t\t\t// NOTE: To ensure both handlers are properly removed, `one()` must not be used here.\n\t\t\tthis.on(\n\t\t\t\t`click.aria-clickable${opts.namespace}`,\n\t\t\t\topts.selector,\n\t\t\t\topts.data,\n\t\t\t\topts.one ? oneClickFnWrapper(fn) : onClickFnWrapper(fn)\n\t\t\t);\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaDisabled()` method.\n\t\t*/\n\t\tariaDisabled(disable) {\n\t\t\t// Bail out if there are no target element(s) or parameters.\n\t\t\tif (this.length === 0 || arguments.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tNOTE: We use `<jQuery>.each()` callbacks to invoke the `<Element>.setAttribute()`\n\t\t\t\tmethods in the following because the `<jQuery>.attr()` method does not allow you\n\t\t\t\tto set a content attribute without a value, which is recommended for boolean\n\t\t\t\tcontent attributes by the HTML specification.\n\t\t\t*/\n\n\t\t\tconst $nonDisableable = this.not('button,fieldset,input,menuitem,optgroup,option,select,textarea');\n\t\t\tconst $disableable    = this.filter('button,fieldset,input,menuitem,optgroup,option,select,textarea');\n\n\t\t\tif (disable) {\n\t\t\t\t// Add boolean content attribute `disabled` and set non-boolean content attribute\n\t\t\t\t// `aria-disabled` to `'true'`, for non-disableable elements.\n\t\t\t\t$nonDisableable.each(function () {\n\t\t\t\t\tthis.setAttribute('disabled', '');\n\t\t\t\t\tthis.setAttribute('aria-disabled', 'true');\n\t\t\t\t});\n\n\t\t\t\t// Set IDL attribute `disabled` to `true` and set non-boolean content attribute\n\t\t\t\t// `aria-disabled` to `'true'`, for disableable elements.\n\t\t\t\t$disableable.each(function () {\n\t\t\t\t\tthis.disabled = true;\n\t\t\t\t\tthis.setAttribute('aria-disabled', 'true');\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Remove content attributes `disabled` and `aria-disabled`, for non-disableable elements.\n\t\t\t\t$nonDisableable.each(function () {\n\t\t\t\t\tthis.removeAttribute('disabled');\n\t\t\t\t\tthis.removeAttribute('aria-disabled');\n\t\t\t\t});\n\n\t\t\t\t// Set IDL attribute `disabled` to `false` and remove content attribute `aria-disabled`,\n\t\t\t\t// for disableable elements.\n\t\t\t\t$disableable.each(function () {\n\t\t\t\t\tthis.disabled = false;\n\t\t\t\t\tthis.removeAttribute('aria-disabled');\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with an `ariaIsDisabled()` method.\n\t\t*/\n\t\tariaIsDisabled() {\n\t\t\t// Check content attribute `disabled`.\n\t\t\t//\n\t\t\t// NOTE: We simply check the `disabled` content attribute for all elements\n\t\t\t// since we have to check it for non-disableable elements and it may also\n\t\t\t// be used for disableable elements since their `disabled` IDL attribute\n\t\t\t// is required to reflect the status of their `disabled` content attribute,\n\t\t\t// and vice versa, by the HTML specification.\n\t\t\t// return this.toArray().some(el => el.hasAttribute('disabled'));\n\t\t\treturn this.is('[disabled]');\n\t\t}\n\t});\n})();\n\n/*\n\tWikifier methods plugin.\n\n\t`jQuery.wikiWithOptions(options, sources…)`\n\t    Wikifies the given content source(s), as directed by the given options.\n\n\t`jQuery.wiki(sources…)`\n\t    Wikifies the given content source(s).\n\n\t`<jQuery>.wikiWithOptions(options, sources…)`\n\t    Wikifies the given content source(s) and appends the result to the target\n\t    element(s), as directed by the given options.\n\n\t`<jQuery>.wiki(sources…)`\n\t    Wikifies the given content source(s) and appends the result to the target\n\t    element(s).\n*/\n(() => {\n\t'use strict';\n\n\tjQuery.extend({\n\t\t/*\n\t\t\tExtend jQuery's static methods with a `wikiWithOptions()` method.\n\t\t*/\n\t\twikiWithOptions(options, ...sources) {\n\t\t\t// Bail out, if there are no content sources.\n\t\t\tif (sources.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Wikify the content sources into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tsources.forEach(content => new Wikifier(frag, content, options));\n\n\t\t\t// Gather the text of any error elements within the fragment…\n\t\t\tconst errors = [...frag.querySelectorAll('.error')]\n\t\t\t\t.map(errEl => errEl.textContent.replace(errorPrologRegExp, ''));\n\n\t\t\t// …and throw an exception, if there were any errors.\n\t\t\tif (errors.length > 0) {\n\t\t\t\tthrow new Error(errors.join('; '));\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's static methods with a `wiki()` method.\n\t\t*/\n\t\twiki(...sources) {\n\t\t\tthis.wikiWithOptions(undefined, ...sources);\n\t\t}\n\t});\n\n\tjQuery.fn.extend({\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with a `wikiWithOptions()` method.\n\t\t*/\n\t\twikiWithOptions(options, ...sources) {\n\t\t\t// Bail out if there are no target element(s) or content sources.\n\t\t\tif (this.length === 0 || sources.length === 0) {\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\t// Wikify the content sources into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tsources.forEach(content => new Wikifier(frag, content, options));\n\n\t\t\t// Append the fragment to the target element(s).\n\t\t\tthis.append(frag);\n\n\t\t\t// Return `this` for further chaining.\n\t\t\treturn this;\n\t\t},\n\n\t\t/*\n\t\t\tExtend jQuery's chainable methods with a `wiki()` method.\n\t\t*/\n\t\twiki(...sources) {\n\t\t\treturn this.wikiWithOptions(undefined, ...sources);\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tlib/util.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Has, Scripting */\n\nvar Util = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tType Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the value yielded by `typeof` (for primitives), the `@@toStringTag`\n\t\tinternal property (for objects), and `'null'` for `null`.\n\n\t\tNOTE: In ≤ES5, returns the value of the `[[Class]]` internal slot for objects.\n\t*/\n\tfunction utilGetType(obj) {\n\t\tif (obj === null) { return 'null'; }\n\n\t\tconst baseType = typeof obj;\n\t\treturn baseType === 'object'\n\t\t\t? Object.prototype.toString.call(obj).slice(8, -1)\n\t\t\t: baseType;\n\t}\n\n\t/*\n\t\tReturns whether the passed value is a boolean or one of the strings \"true\"\n\t\tor \"false\".\n\t*/\n\tfunction utilIsBoolean(obj) {\n\t\treturn typeof obj === 'boolean' || typeof obj === 'string' && (obj === 'true' || obj === 'false');\n\t}\n\n\t/*\n\t\tReturns whether the passed value is iterable.\n\t*/\n\tfunction utilIsIterable(obj) {\n\t\treturn obj != null && typeof obj[Symbol.iterator] === 'function'; // lazy equality for null\n\t}\n\n\t/*\n\t\tReturns whether the passed value is a finite number or a numeric string which\n\t\tyields a finite number when parsed.\n\t*/\n\tfunction utilIsNumeric(obj) {\n\t\tlet num;\n\n\t\tswitch (typeof obj) {\n\t\tcase 'number':\n\t\t\tnum = obj;\n\t\t\tbreak;\n\n\t\tcase 'string':\n\t\t\tnum = Number(obj);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !Number.isNaN(num) && Number.isFinite(num);\n\t}\n\n\t/*\n\t\tReturns whether the passed values pass a SameValueZero comparison.\n\n\t\tSEE: http://ecma-international.org/ecma-262/8.0/#sec-samevaluezero\n\t*/\n\tfunction utilSameValueZero(a, b) {\n\t\t/*\n\t\t\tNOTE: This comparison could also be implemented thus:\n\n\t\t\t\t```\n\t\t\t\ta === b ||\n\t\t\t\ttypeof a === 'number' && typeof b === 'number' &&\n\t\t\t\tNumber.isNaN(a) && Number.isNaN(b)\n\t\t\t\t```\n\n\t\t\tThat's needlessly verbose, however, as `NaN` is the only value in\n\t\t\tthe language which is not reflexive.\n\t\t*/\n\t\treturn a === b || a !== a && b !== b;\n\t}\n\n\t/*\n\t\tReturns a pseudo-enumeration created from the given Array, Map, Set, or generic object.\n\t*/\n\tfunction utilToEnum(obj) {\n\t\tconst pEnum = Object.create(null);\n\n\t\tif (obj instanceof Array) {\n\t\t\tobj.forEach((val, i) => pEnum[String(val)] = i);\n\t\t}\n\t\telse if (obj instanceof Set) {\n\t\t\t// NOTE: Use `<Array>.forEach()` here rather than `<Set>.forEach()`\n\t\t\t// as the latter does not provide the indices we require.\n\t\t\tArray.from(obj).forEach((val, i) => pEnum[String(val)] = i);\n\t\t}\n\t\telse if (obj instanceof Map) {\n\t\t\tobj.forEach((val, key) => pEnum[String(key)] = val);\n\t\t}\n\t\telse if (\n\t\t\t   typeof obj === 'object'\n\t\t\t&& obj !== null\n\t\t\t&& Object.getPrototypeOf(obj) === Object.prototype\n\t\t) {\n\t\t\tObject.assign(pEnum, obj);\n\t\t}\n\t\telse {\n\t\t\tthrow new TypeError('Util.toEnum obj parameter must be an Array, Map, Set, or generic object');\n\t\t}\n\n\t\treturn Object.freeze(pEnum);\n\t}\n\n\t/*\n\t\tReturns the value of the `@@toStringTag` property of the given object.\n\n\t\tNOTE: In ≤ES5, returns the value of the `[[Class]]` internal slot.\n\t*/\n\tfunction utilToStringTag(obj) {\n\t\treturn Object.prototype.toString.call(obj).slice(8, -1);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tString Encoding Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a trimmed and encoded slug of the passed string that should be safe\n\t\tfor use as a DOM ID or class name.\n\n\t\tNOTE: The range of illegal characters consists of: C0 controls, space, exclamation,\n\t\tdouble quote, number, dollar, percent, ampersand, single quote, left paren, right\n\t\tparen, asterisk, plus, comma, hyphen, period, forward slash, colon, semi-colon,\n\t\tless-than, equals, greater-than, question, at, left bracket, backslash, right\n\t\tbracket, caret, backquote/grave, left brace, pipe/vertical-bar, right brace, tilde,\n\t\tdelete, C1 controls.\n\t*/\n\tconst _illegalSlugCharsRe = /[\\x00-\\x20!-/:-@[-^`{-\\x9f]+/g; // eslint-disable-line no-control-regex\n\t/* legacy */\n\tconst _isInvalidSlugRe = /^-*$/; // Matches the empty string or one comprised solely of hyphens.\n\t/* /legacy */\n\n\tfunction utilSlugify(str) {\n\t\tconst base = String(str).trim();\n\n\t\t/* legacy */\n\t\tconst _legacy = base\n\t\t\t.replace(/[^\\w\\s\\u2013\\u2014-]+/g, '')\n\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-')\n\t\t\t.toLocaleLowerCase();\n\n\t\tif (!_isInvalidSlugRe.test(_legacy)) {\n\t\t\treturn _legacy;\n\t\t}\n\t\t/* /legacy */\n\n\t\treturn base\n\t\t\t.replace(_illegalSlugCharsRe, '')\n\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-');\n\n\t\t// For v3.\n\t\t// return base.replace(_illegalSlugCharsRe, '-');\n\t}\n\n\t/*\n\t\tReturns an entity encoded version of the passed string.\n\n\t\tNOTE: Only escapes the five primary special characters and the backquote.\n\t*/\n\tconst _htmlCharsRe    = /[&<>\"'`]/g;\n\tconst _hasHtmlCharsRe = new RegExp(_htmlCharsRe.source); // to drop the global flag\n\tconst _htmlCharsMap   = Object.freeze({\n\t\t'&' : '&amp;',\n\t\t'<' : '&lt;',\n\t\t'>' : '&gt;',\n\t\t'\"' : '&quot;',\n\t\t\"'\" : '&#39;',\n\t\t'`' : '&#96;'\n\t});\n\n\tfunction utilEscape(str) {\n\t\tif (str == null) { // lazy equality for null\n\t\t\treturn '';\n\t\t}\n\n\t\tconst val = String(str);\n\t\treturn val && _hasHtmlCharsRe.test(val)\n\t\t\t? val.replace(_htmlCharsRe, ch => _htmlCharsMap[ch])\n\t\t\t: val;\n\t}\n\n\t/*\n\t\tReturns a decoded version of the passed entity encoded string.\n\n\t\tNOTE: The extended replacement set here, in contrast to `utilEscape()`,\n\t\tis required due to observed stupidity from various sources.\n\t*/\n\tconst _escapedHtmlRe    = /&(?:amp|#38|#x26|lt|#60|#x3c|gt|#62|#x3e|quot|#34|#x22|apos|#39|#x27|#96|#x60);/gi;\n\tconst _hasEscapedHtmlRe = new RegExp(_escapedHtmlRe.source, 'i'); // to drop the global flag\n\tconst _escapedHtmlMap   = Object.freeze({\n\t\t'&amp;'  : '&', // ampersand (HTML character entity, XML predefined entity)\n\t\t'&#38;'  : '&', // ampersand (decimal numeric character reference)\n\t\t'&#x26;' : '&', // ampersand (hexadecimal numeric character reference)\n\t\t'&lt;'   : '<', // less-than (HTML character entity, XML predefined entity)\n\t\t'&#60;'  : '<', // less-than (decimal numeric character reference)\n\t\t'&#x3c;' : '<', // less-than (hexadecimal numeric character reference)\n\t\t'&gt;'   : '>', // greater-than (HTML character entity, XML predefined entity)\n\t\t'&#62;'  : '>', // greater-than (decimal numeric character reference)\n\t\t'&#x3e;' : '>', // greater-than (hexadecimal numeric character reference)\n\t\t'&quot;' : '\"', // double quote (HTML character entity, XML predefined entity)\n\t\t'&#34;'  : '\"', // double quote (decimal numeric character reference)\n\t\t'&#x22;' : '\"', // double quote (hexadecimal numeric character reference)\n\t\t'&apos;' : \"'\", // apostrophe (XML predefined entity)\n\t\t'&#39;'  : \"'\", // apostrophe (decimal numeric character reference)\n\t\t'&#x27;' : \"'\", // apostrophe (hexadecimal numeric character reference)\n\t\t'&#96;'  : '`', // backquote (decimal numeric character reference)\n\t\t'&#x60;' : '`'  // backquote (hexadecimal numeric character reference)\n\t});\n\n\tfunction utilUnescape(str) {\n\t\tif (str == null) { // lazy equality for null\n\t\t\treturn '';\n\t\t}\n\n\t\tconst val = String(str);\n\t\treturn val && _hasEscapedHtmlRe.test(val)\n\t\t\t? val.replace(_escapedHtmlRe, entity => _escapedHtmlMap[entity.toLowerCase()])\n\t\t\t: val;\n\t}\n\n\t/*\n\t\tReturns an object (`{ char, start, end }`) containing the Unicode character at\n\t\tposition `pos`, its starting position, and its ending position—surrogate pairs\n\t\tare properly handled.  If `pos` is out-of-bounds, returns an object containing\n\t\tthe empty string and start/end positions of `-1`.\n\n\t\tThis function is necessary because JavaScript strings are sequences of UTF-16\n\t\tcode units, so surrogate pairs are exposed and thus must be handled.  While the\n\t\tES6/2015 standard does improve the situation somewhat, it does not alleviate\n\t\tthe need for this function.\n\n\t\tNOTE: Returns the individual code units of invalid surrogate pairs as-is.\n\n\t\tIDEA: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt\n\t*/\n\tfunction utilCharAndPosAt(text, position) {\n\t\tconst str  = String(text);\n\t\tconst pos  = Math.trunc(position);\n\t\tconst code = str.charCodeAt(pos);\n\n\t\t// Given position was out-of-bounds.\n\t\tif (Number.isNaN(code)) {\n\t\t\treturn { char : '', start : -1, end : -1 };\n\t\t}\n\n\t\tconst retval = {\n\t\t\tchar  : str.charAt(pos),\n\t\t\tstart : pos,\n\t\t\tend   : pos\n\t\t};\n\n\t\t// Code unit is not a UTF-16 surrogate.\n\t\tif (code < 0xD800 || code > 0xDFFF) {\n\t\t\treturn retval;\n\t\t}\n\n\t\t// Code unit is a high surrogate (D800–DBFF).\n\t\tif (code >= 0xD800 && code <= 0xDBFF) {\n\t\t\tconst nextPos = pos + 1;\n\n\t\t\t// End of string.\n\t\t\tif (nextPos >= str.length) {\n\t\t\t\treturn retval;\n\t\t\t}\n\n\t\t\tconst nextCode = str.charCodeAt(nextPos);\n\n\t\t\t// Next code unit is not a low surrogate (DC00–DFFF).\n\t\t\tif (nextCode < 0xDC00 || nextCode > 0xDFFF) {\n\t\t\t\treturn retval;\n\t\t\t}\n\n\t\t\tretval.char = retval.char + str.charAt(nextPos);\n\t\t\tretval.end = nextPos;\n\t\t\treturn retval;\n\t\t}\n\n\t\t// Code unit is a low surrogate (DC00–DFFF) in the first position.\n\t\tif (pos === 0) {\n\t\t\treturn retval;\n\t\t}\n\n\t\tconst prevPos  = pos - 1;\n\t\tconst prevCode = str.charCodeAt(prevPos);\n\n\t\t// Previous code unit is not a high surrogate (D800–DBFF).\n\t\tif (prevCode < 0xD800 || prevCode > 0xDBFF) {\n\t\t\treturn retval;\n\t\t}\n\n\t\tretval.char = str.charAt(prevPos) + retval.char;\n\t\tretval.start = prevPos;\n\t\treturn retval;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTime Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the number of milliseconds elapsed since a reference epoch.\n\n\t\tNOTE: Use the Performance API, if available, elsewise use Date as a\n\t\tfailover.  The Performance API is preferred for its monotonic clock—\n\t\tmeaning, it's not subject to the vagaries of timezone changes and leap\n\t\tperiods, as is Date.\n\t*/\n\tconst _nowSource = Has.performance ? performance : Date;\n\n\tfunction utilNow() {\n\t\treturn _nowSource.now();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tConversion Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the number of miliseconds represented by the passed CSS time string.\n\t*/\n\tconst _cssTimeRe = /^([+-]?(?:\\d*\\.)?\\d+)([Mm]?[Ss])$/;\n\n\tfunction utilFromCssTime(cssTime) {\n\t\tconst match = _cssTimeRe.exec(String(cssTime));\n\n\t\tif (match === null) {\n\t\t\tthrow new SyntaxError(`invalid time value syntax: \"${cssTime}\"`);\n\t\t}\n\n\t\tlet msec = Number(match[1]);\n\n\t\tif (match[2].length === 1) {\n\t\t\tmsec *= 1000;\n\t\t}\n\n\t\tif (Number.isNaN(msec) || !Number.isFinite(msec)) {\n\t\t\tthrow new RangeError(`invalid time value: \"${cssTime}\"`);\n\t\t}\n\n\t\treturn msec;\n\t}\n\n\t/*\n\t\tReturns the CSS time string represented by the passed number of milliseconds.\n\t*/\n\tfunction utilToCssTime(msec) {\n\t\tif (typeof msec !== 'number' || Number.isNaN(msec) || !Number.isFinite(msec)) {\n\t\t\tlet what;\n\n\t\t\tswitch (typeof msec) {\n\t\t\tcase 'string':\n\t\t\t\twhat = `\"${msec}\"`;\n\t\t\t\tbreak;\n\n\t\t\tcase 'number':\n\t\t\t\twhat = String(msec);\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\twhat = utilToStringTag(msec);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tthrow new Error(`invalid milliseconds: ${what}`);\n\t\t}\n\n\t\treturn `${msec}ms`;\n\t}\n\n\t/*\n\t\tReturns the DOM property name represented by the passed CSS property name.\n\t*/\n\tfunction utilFromCssProperty(cssName) {\n\t\tif (!cssName.includes('-')) {\n\t\t\tswitch (cssName) {\n\t\t\tcase 'bgcolor': return 'backgroundColor';\n\t\t\tcase 'float':   return 'cssFloat';\n\t\t\tdefault:        return cssName;\n\t\t\t}\n\t\t}\n\n\t\t// Strip the leading hyphen from the `-ms-` vendor prefix, so it stays lowercased.\n\t\tconst normalized = cssName.slice(0, 4) === '-ms-' ? cssName.slice(1) : cssName;\n\n\t\treturn normalized\n\t\t\t.split('-')\n\t\t\t.map((part, i) => i === 0 ? part : part.toUpperFirst())\n\t\t\t.join('');\n\t}\n\n\t/*\n\t\tReturns an object containing the component properties parsed from the passed URL.\n\t*/\n\tfunction utilParseUrl(url) {\n\t\tconst el       = document.createElement('a');\n\t\tconst queryObj = Object.create(null);\n\n\t\t// Let the `<a>` element parse the URL.\n\t\tel.href = url;\n\n\t\t// Populate the `queryObj` object with the query string attributes.\n\t\tif (el.search) {\n\t\t\tel.search\n\t\t\t\t.replace(/^\\?/, '')\n\t\t\t\t.splitOrEmpty(/(?:&(?:amp;)?|;)/)\n\t\t\t\t.forEach(query => {\n\t\t\t\t\tconst [key, value] = query.split('=');\n\t\t\t\t\tqueryObj[key] = value;\n\t\t\t\t});\n\t\t}\n\n\t\t/*\n\t\t\tCaveats by browser:\n\t\t\t\tEdge and Internet Explorer (≥8) do not support authentication\n\t\t\t\tinformation within a URL at all and will throw a security exception\n\t\t\t\ton *any* property access if it's included.\n\n\t\t\t\tInternet Explorer does not include the leading forward slash on\n\t\t\t\t`pathname` when required.\n\n\t\t\t\tOpera (Presto) strips the authentication information from `href`\n\t\t\t\tand does not supply `username` or `password`.\n\n\t\t\t\tSafari (ca. v5.1.x) does not supply `username` or `password` and\n\t\t\t\tpeforms URI decoding on `pathname`.\n\t\t*/\n\n\t\t// Patch for IE not including the leading slash on `pathname` when required.\n\t\tconst pathname = el.host && el.pathname[0] !== '/' ? `/${el.pathname}` : el.pathname;\n\n\t\treturn {\n\t\t\t// The full URL that was originally parsed.\n\t\t\thref : el.href,\n\n\t\t\t// The request protocol, lowercased.\n\t\t\tprotocol : el.protocol,\n\n\t\t\t// // The full authentication information.\n\t\t\t// auth : el.username || el.password // eslint-disable-line no-nested-ternary\n\t\t\t// \t? `${el.username}:${el.password}`\n\t\t\t// \t: typeof el.username === 'string' ? '' : undefined,\n\t\t\t//\n\t\t\t// // The username portion of the auth info.\n\t\t\t// username : el.username,\n\t\t\t//\n\t\t\t// // The password portion of the auth info.\n\t\t\t// password : el.password,\n\n\t\t\t// The full host information, including port number, lowercased.\n\t\t\thost : el.host,\n\n\t\t\t// The hostname portion of the host info, lowercased.\n\t\t\thostname : el.hostname,\n\n\t\t\t// The port number portion of the host info.\n\t\t\tport : el.port,\n\n\t\t\t// The full path information, including query info.\n\t\t\tpath : `${pathname}${el.search}`,\n\n\t\t\t// The pathname portion of the path info.\n\t\t\tpathname,\n\n\t\t\t// The query string portion of the path info, including the leading question mark.\n\t\t\tquery  : el.search,\n\t\t\tsearch : el.search,\n\n\t\t\t// The attributes portion of the query string, parsed into an object.\n\t\t\tqueries  : queryObj,\n\t\t\tsearches : queryObj,\n\n\t\t\t// The fragment string, including the leading hash/pound sign.\n\t\t\thash : el.hash\n\t\t};\n\t}\n\n\t/*\n\t\tReturns a new exception based on the given exception.\n\n\t\tNOTE: Mostly useful for making a standard JavaScript exception type copy\n\t\tof a host exception type—e.g. `DOMException` → `Error`.\n\t*/\n\tfunction utilNewExceptionFrom(original, exceptionType, override) {\n\t\tif (typeof original !== 'object' || original === null) {\n\t\t\tthrow new Error('Util.newExceptionFrom original parameter must be an object');\n\t\t}\n\t\tif (typeof exceptionType !== 'function') {\n\t\t\tthrow new Error('Util.newExceptionFrom exceptionType parameter must be an error type constructor');\n\t\t}\n\n\t\tconst ex = new exceptionType(original.message); // eslint-disable-line new-cap\n\n\t\tif (typeof original.name !== 'undefined') {\n\t\t\tex.name = original.name;\n\t\t}\n\t\tif (typeof original.code !== 'undefined') {\n\t\t\tex.code = original.code;\n\t\t}\n\t\tif (typeof original.columnNumber !== 'undefined') {\n\t\t\tex.columnNumber = original.columnNumber;\n\t\t}\n\t\tif (typeof original.description !== 'undefined') {\n\t\t\tex.description = original.description;\n\t\t}\n\t\tif (typeof original.fileName !== 'undefined') {\n\t\t\tex.fileName = original.fileName;\n\t\t}\n\t\tif (typeof original.lineNumber !== 'undefined') {\n\t\t\tex.lineNumber = original.lineNumber;\n\t\t}\n\t\tif (typeof original.number !== 'undefined') {\n\t\t\tex.number = original.number;\n\t\t}\n\t\tif (typeof original.stack !== 'undefined') {\n\t\t\tex.stack = original.stack;\n\t\t}\n\n\t\tconst overrideType = typeof override;\n\n\t\tif (overrideType !== 'undefined') {\n\t\t\tif (overrideType === 'object' && override !== null) {\n\t\t\t\tObject.assign(ex, override);\n\t\t\t}\n\t\t\telse if (overrideType === 'string') {\n\t\t\t\tex.message = override;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('Util.newExceptionFrom override parameter must be an object or string');\n\t\t\t}\n\t\t}\n\n\t\treturn ex;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tType Functions.\n\t\t*/\n\t\tgetType       : { value : utilGetType },\n\t\tisBoolean     : { value : utilIsBoolean },\n\t\tisIterable    : { value : utilIsIterable },\n\t\tisNumeric     : { value : utilIsNumeric },\n\t\tsameValueZero : { value : utilSameValueZero },\n\t\ttoEnum        : { value : utilToEnum },\n\t\ttoStringTag   : { value : utilToStringTag },\n\n\t\t/*\n\t\t\tString Encoding Functions.\n\t\t*/\n\t\tslugify      : { value : utilSlugify },\n\t\tescape       : { value : utilEscape },\n\t\tunescape     : { value : utilUnescape },\n\t\tcharAndPosAt : { value : utilCharAndPosAt },\n\n\t\t/*\n\t\t\tConversion Functions.\n\t\t*/\n\t\tfromCssTime      : { value : utilFromCssTime },\n\t\ttoCssTime        : { value : utilToCssTime },\n\t\tfromCssProperty  : { value : utilFromCssProperty },\n\t\tparseUrl         : { value : utilParseUrl },\n\t\tnewExceptionFrom : { value : utilNewExceptionFrom },\n\n\t\t/*\n\t\t\tTime Functions.\n\t\t*/\n\t\tnow : { value : utilNow },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\trandom         : { value : Math.random },\n\t\tentityEncode   : { value : utilEscape },\n\t\tentityDecode   : { value : utilUnescape },\n\t\tevalExpression : { value : (...args) => Scripting.evalJavaScript(...args) }, // SEE: `markup/scripting.js`.\n\t\tevalStatements : { value : (...args) => Scripting.evalJavaScript(...args) }  // SEE: `markup/scripting.js`.\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/simplestore.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar SimpleStore = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// In-order list of database adapters.\n\tconst _adapters = [];\n\n\t// The initialized adapter.\n\tlet _initialized = null;\n\n\n\t/*******************************************************************************************************************\n\t\tSimpleStore Functions.\n\t*******************************************************************************************************************/\n\tfunction storeCreate(storageId, persistent) {\n\t\tif (_initialized) {\n\t\t\treturn _initialized.create(storageId, persistent);\n\t\t}\n\n\t\t// Return the first adapter which successfully initializes, elsewise throw an exception.\n\t\tfor (let i = 0; i < _adapters.length; ++i) {\n\t\t\tif (_adapters[i].init(storageId, persistent)) {\n\t\t\t\t_initialized = _adapters[i];\n\t\t\t\treturn _initialized.create(storageId, persistent);\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error('no valid storage adapters found');\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tAdapters List.\n\n\t\t\tTODO: This should probably have a getter, rather than being exported directly.\n\t\t*/\n\t\tadapters : { value : _adapters },\n\n\t\t/*\n\t\t\tCore Functions.\n\t\t*/\n\t\tcreate : { value : storeCreate }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/FCHost.Storage.js\n\n\tCopyright © 2013–2019 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_FCHostStorageAdapter Class.\n        Note that FCHost is only intended for a single document, so we ignore both prefixing and storageID\n\t*******************************************************************************************************************/\n\tclass _FCHostStorageAdapter {\n\t\tconstructor(persistent) {\n\t\t\tlet engine = null;\n\t\t\tlet name   = null;\n\n\t\t\tif (persistent) {\n\t\t\t\tengine = window.FCHostPersistent;\n\t\t\t\tname   = 'FCHostPersistent';\n\t\t\t}\n\t\t\telse {\n\t\t\t    engine = window.FCHostSession;\n\t\t\t\tname   = 'FCHostSession';\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_engine : {\n\t\t\t\t\tvalue : engine\n\t\t\t\t},\n                \n\t\t\t\tname : {\n\t\t\t\t\tvalue : name\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\treturn this._engine.size();\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\treturn this._engine.size();\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\treturn this._engine.keys();\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn this._engine.has(key);\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = this._engine.get(key);\n\n\t\t\treturn value == null ? null : _FCHostStorageAdapter._deserialize(value); // lazy equality for null\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.set(key, _FCHostStorageAdapter._serialize(value));\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.remove(key);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tthis._engine.clear();\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn JSON.stringify(obj);\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse(str);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit() {\n\t\t// FCHost feature test.\n\t\tfunction hasFCHostStorage() {\n\t\t\ttry {\n\t\t\t    if (typeof window.FCHostPersistent !== 'undefined')\n\t\t\t        return true;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn false;\n\t\t}\n\n\t\t_ok = hasFCHostStorage();\n\t\t\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _FCHostStorageAdapter(persistent);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/webstorage.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_WebStorageAdapter Class.\n\t*******************************************************************************************************************/\n\tclass _WebStorageAdapter {\n\t\tconstructor(storageId, persistent) {\n\t\t\tconst prefix = `${storageId}.`;\n\t\t\tlet engine = null;\n\t\t\tlet name   = null;\n\n\t\t\tif (persistent) {\n\t\t\t\tengine = window.localStorage;\n\t\t\t\tname   = 'localStorage';\n\t\t\t}\n\t\t\telse {\n\t\t\t\tengine = window.sessionStorage;\n\t\t\t\tname   = 'sessionStorage';\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_engine : {\n\t\t\t\t\tvalue : engine\n\t\t\t\t},\n\n\t\t\t\t_prefix : {\n\t\t\t\t\tvalue : prefix\n\t\t\t\t},\n\n\t\t\t\t_prefixRe : {\n\t\t\t\t\tvalue : new RegExp(`^${RegExp.escape(prefix)}`)\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : name\n\t\t\t\t},\n\n\t\t\t\tid : {\n\t\t\t\t\tvalue : storageId\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\t/*\n\t\t\t\tNOTE: DO NOT do something like `return this._engine.length;` here,\n\t\t\t\tas that will return the length of the entire store, rather than\n\t\t\t\tjust our prefixed keys.\n\t\t\t*/\n\t\t\treturn this.keys().length;\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\t/*\n\t\t\t\tNOTE: DO NOT do something like `return this._engine.length;` here,\n\t\t\t\tas that will return the length of the entire store, rather than\n\t\t\t\tjust our prefixed keys.\n\t\t\t*/\n\t\t\treturn this.keys().length;\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\tconst keys = [];\n\n\t\t\tfor (let i = 0; i < this._engine.length; ++i) {\n\t\t\t\tconst key = this._engine.key(i);\n\n\t\t\t\tif (this._prefixRe.test(key)) {\n\t\t\t\t\tkeys.push(key.replace(this._prefixRe, ''));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn keys;\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// // FIXME: This method should probably check for the key, rather than comparing its value.\n\t\t\t// return this._engine.getItem(this._prefix + key) != null; // lazy equality for null\n\n\t\t\treturn this._engine.hasOwnProperty(this._prefix + key);\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = this._engine.getItem(this._prefix + key);\n\n\t\t\treturn value == null ? null : _WebStorageAdapter._deserialize(value); // lazy equality for null\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tthis._engine.setItem(this._prefix + key, _WebStorageAdapter._serialize(value));\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t/*\n\t\t\t\t\tIf the exception is a quota exceeded error, massage it into something\n\t\t\t\t\ta bit nicer for the player.\n\n\t\t\t\t\tNOTE: Ideally, we could simply do something like checking `ex.code`, but\n\t\t\t\t\tit's a non-standard property and not supported in all browsers.  Thus,\n\t\t\t\t\twe have to resort to pattern matching the name and message—the latter being\n\t\t\t\t\trequired by Opera (Presto).  I hate the parties responsible for this snafu\n\t\t\t\t\tso much.\n\t\t\t\t*/\n\t\t\t\tif (/quota.?(?:exceeded|reached)/i.test(ex.name + ex.message)) {\n\t\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `${this.name} quota exceeded`);\n\t\t\t\t}\n\n\t\t\t\tthrow ex;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._engine.removeItem(this._prefix + key);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tconst keys = this.keys();\n\n\t\t\tfor (let i = 0, iend = keys.length; i < iend; ++i) {\n\t\t\t\tif (DEBUG) { console.log('\\tdeleting key:', keys[i]); }\n\n\t\t\t\tthis.delete(keys[i]);\n\t\t\t}\n\n\t\t\t// return this.keys().forEach(key => {\n\t\t\t// \tif (DEBUG) { console.log('\\tdeleting key:', key); }\n\t\t\t//\n\t\t\t// \tthis.delete(key);\n\t\t\t// });\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn JSON.stringify(obj);\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse((!str || str[0] == \"{\") ? str : LZString.decompressFromUTF16(str));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit() {\n\t\t// Web Storage feature test.\n\t\tfunction hasWebStorage(storeId) {\n\t\t\ttry {\n\t\t\t\tconst store = window[storeId];\n\t\t\t\tconst tid   = `_sc_${String(Date.now())}`;\n\t\t\t\tstore.setItem(tid, tid);\n\t\t\t\tconst result = store.getItem(tid) === tid;\n\t\t\t\tstore.removeItem(tid);\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn false;\n\t\t}\n\n\t\t/*\n\t\t\tJust to be safe, we feature test for both `localStorage` and `sessionStorage`,\n\t\t\tas you never know what browser implementation bugs you're going to run into.\n\t\t*/\n\t\t_ok = hasWebStorage('localStorage') && hasWebStorage('sessionStorage');\n\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _WebStorageAdapter(storageId, persistent);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/simplestore/adapters/cookie.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global SimpleStore, Util */\n\nSimpleStore.adapters.push((() => {\n\t'use strict';\n\n\t// Expiry constants.\n\tconst _MAX_EXPIRY = 'Tue, 19 Jan 2038 03:14:07 GMT'; // (new Date((Math.pow(2, 31) - 1) * 1000)).toUTCString()\n\tconst _MIN_EXPIRY = 'Thu, 01 Jan 1970 00:00:00 GMT'; // (new Date(0)).toUTCString()\n\n\t// Adapter readiness state.\n\tlet _ok = false;\n\n\n\t/*******************************************************************************************************************\n\t\t_CookieAdapter Class.\n\t*******************************************************************************************************************/\n\tclass _CookieAdapter {\n\t\tconstructor(storageId, persistent) {\n\t\t\tconst prefix = `${storageId}${persistent ? '!' : '*'}.`;\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t_prefix : {\n\t\t\t\t\tvalue : prefix\n\t\t\t\t},\n\n\t\t\t\t_prefixRe : {\n\t\t\t\t\tvalue : new RegExp(`^${RegExp.escape(prefix)}`)\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : 'cookie'\n\t\t\t\t},\n\n\t\t\t\tid : {\n\t\t\t\t\tvalue : storageId\n\t\t\t\t},\n\n\t\t\t\tpersistent : {\n\t\t\t\t\tvalue : !!persistent\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* legacy */\n\t\tget length() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.length : Number]`); }\n\n\t\t\treturn this.keys().length;\n\t\t}\n\t\t/* /legacy */\n\n\t\tsize() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.size() : Number]`); }\n\n\t\t\treturn this.keys().length;\n\t\t}\n\n\t\tkeys() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.keys() : String Array]`); }\n\n\t\t\tif (document.cookie === '') {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tconst cookies = document.cookie.split(/;\\s*/);\n\t\t\tconst keys    = [];\n\n\t\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\t\tif (this._prefixRe.test(key)) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\t\tnot a serialized empty string, so we should omit such pairs.\n\t\t\t\t\t*/\n\t\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\t\tif (value !== '') {\n\t\t\t\t\t\tkeys.push(key.replace(this._prefixRe, ''));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn keys;\n\t\t}\n\n\t\thas(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.has(key: \"${key}\") : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn _CookieAdapter._getCookie(this._prefix + key) !== null;\n\t\t}\n\n\t\tget(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.get(key: \"${key}\") : Any]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst value = _CookieAdapter._getCookie(this._prefix + key);\n\n\t\t\treturn value === null ? null : _CookieAdapter._deserialize(value);\n\t\t}\n\n\t\tset(key, value) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.set(key: \"${key}\", value: \\u2026) : Boolean]`); }\n\n\t\t\tif (typeof key !== 'string' || !key) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\tthis._prefix + key,\n\t\t\t\t\t_CookieAdapter._serialize(value),\n\n\t\t\t\t\t// An undefined expiry denotes a session cookie.\n\t\t\t\t\tthis.persistent ? _MAX_EXPIRY : undefined\n\t\t\t\t);\n\n\t\t\t\tif (!this.has(key)) {\n\t\t\t\t\tthrow new Error('unknown validation error during set');\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t// Massage the cookie exception into something a bit nicer for the player.\n\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `cookie error: ${ex.message}`);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tdelete(key) {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.delete(key: \"${key}\") : Boolean]`); }\n\n\t\t\t/*\n\t\t\t\tAttempting to delete a cookie implies setting it, so we test for its existence\n\t\t\t\tbeforehand, to avoid creating it in the event that it does not already exist.\n\t\t\t*/\n\t\t\tif (typeof key !== 'string' || !key || !this.has(key)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\tthis._prefix + key,\n\n\t\t\t\t\t// Use `undefined` as the value.\n\t\t\t\t\tundefined,\n\n\t\t\t\t\t// Use the epoch as the expiry.\n\t\t\t\t\t_MIN_EXPIRY\n\t\t\t\t);\n\n\t\t\t\tif (this.has(key)) {\n\t\t\t\t\tthrow new Error('unknown validation error during delete');\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\t// Massage the cookie exception into something a bit nicer for the player.\n\t\t\t\tthrow Util.newExceptionFrom(ex, Error, `cookie error: ${ex.message}`);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tclear() {\n\t\t\tif (DEBUG) { console.log(`[<SimpleStore:${this.name}>.clear() : Boolean]`); }\n\n\t\t\tconst keys = this.keys();\n\n\t\t\tfor (let i = 0, iend = keys.length; i < iend; ++i) {\n\t\t\t\tif (DEBUG) { console.log('\\tdeleting key:', keys[i]); }\n\n\t\t\t\tthis.delete(keys[i]);\n\t\t\t}\n\n\t\t\t// this.keys().forEach(key => {\n\t\t\t// \tif (DEBUG) { console.log('\\tdeleting key:', key); }\n\t\t\t//\n\t\t\t// \tthis.delete(key);\n\t\t\t// });\n\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic _getCookie(prefixedKey) {\n\t\t\tif (!prefixedKey || document.cookie === '') {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst cookies = document.cookie.split(/;\\s*/);\n\n\t\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\t\tif (prefixedKey === key) {\n\t\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\t\tnot a serialized empty string, so we should yield `null` for such pairs.\n\t\t\t\t\t*/\n\t\t\t\t\treturn value || null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tstatic _setCookie(prefixedKey, value, expiry) {\n\t\t\tif (!prefixedKey) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet payload = `${encodeURIComponent(prefixedKey)}=`;\n\n\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\tpayload += encodeURIComponent(value);\n\t\t\t}\n\n\t\t\tif (expiry != null) { // lazy equality for null\n\t\t\t\tpayload += `; expires=${expiry}`;\n\t\t\t}\n\n\t\t\tpayload += '; path=/';\n\t\t\tdocument.cookie = payload;\n\t\t}\n\n\t\tstatic _serialize(obj) {\n\t\t\treturn LZString.compressToBase64(JSON.stringify(obj));\n\t\t}\n\n\t\tstatic _deserialize(str) {\n\t\t\treturn JSON.parse(LZString.decompressFromBase64(str));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAdapter Utility Functions.\n\t*******************************************************************************************************************/\n\tfunction adapterInit(\n\t\t// Only used for stores updates.\n\t\tstorageId\n\t) {\n\t\t// Cookie feature test.\n\t\ttry {\n\t\t\tconst tid = `_sc_${String(Date.now())}`;\n\n\t\t\t// We only test a session cookie as that should suffice.\n\t\t\t_CookieAdapter._setCookie(tid, _CookieAdapter._serialize(tid), undefined);\n\t\t\t_ok = _CookieAdapter._deserialize(_CookieAdapter._getCookie(tid)) === tid;\n\t\t\t_CookieAdapter._setCookie(tid, undefined, _MIN_EXPIRY);\n\t\t}\n\t\tcatch (ex) {\n\t\t\t_ok = false;\n\t\t}\n\n\t\t/* legacy */\n\t\t// Attempt to update the cookie stores, if necessary.  This should happen only during initialization.\n\t\tif (_ok) {\n\t\t\t_updateCookieStores(storageId);\n\t\t}\n\t\t/* /legacy */\n\n\t\treturn _ok;\n\t}\n\n\tfunction adapterCreate(storageId, persistent) {\n\t\tif (!_ok) {\n\t\t\tthrow new Error('adapter not initialized');\n\t\t}\n\n\t\treturn new _CookieAdapter(storageId, persistent);\n\t}\n\n\t/* legacy */\n\t// Updates old non-segmented cookie stores into segmented stores.\n\tfunction _updateCookieStores(storageId) {\n\t\tif (document.cookie === '') {\n\t\t\treturn;\n\t\t}\n\n\t\tconst oldPrefix     = `${storageId}.`;\n\t\tconst oldPrefixRe   = new RegExp(`^${RegExp.escape(oldPrefix)}`);\n\t\tconst persistPrefix = `${storageId}!.`;\n\t\tconst sessionPrefix = `${storageId}*.`;\n\t\tconst sessionTestRe = /\\.(?:state|rcWarn)$/;\n\t\tconst cookies       = document.cookie.split(/;\\s*/);\n\n\t\tfor (let i = 0; i < cookies.length; ++i) {\n\t\t\tconst kvPair = cookies[i].split('=');\n\t\t\tconst key    = decodeURIComponent(kvPair[0]);\n\n\t\t\tif (oldPrefixRe.test(key)) {\n\t\t\t\t/*\n\t\t\t\t\tAll stored values are serialized and an empty string serializes to a non-empty\n\t\t\t\t\tstring.  Therefore, receiving an empty string here signifies a deleted value,\n\t\t\t\t\tnot a serialized empty string, so we should skip processing such pairs.\n\t\t\t\t*/\n\t\t\t\tconst value = decodeURIComponent(kvPair[1]);\n\n\t\t\t\tif (value !== '') {\n\t\t\t\t\tconst persist = !sessionTestRe.test(key);\n\n\t\t\t\t\t// Delete the old k/v pair.\n\t\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t_MIN_EXPIRY\n\t\t\t\t\t);\n\n\t\t\t\t\t// Set the new k/v pair.\n\t\t\t\t\t_CookieAdapter._setCookie(\n\t\t\t\t\t\tkey.replace(oldPrefixRe, () => persist ? persistPrefix : sessionPrefix),\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tpersist ? _MAX_EXPIRY : undefined\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t/* /legacy */\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : adapterInit },\n\t\tcreate : { value : adapterCreate }\n\t}));\n})());\n\n/***********************************************************************************************************************\n\n\tlib/debugview.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\tTODO: Make this use jQuery throughout.\n*/\nvar DebugView = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tDebugView Class.\n\t*******************************************************************************************************************/\n\tclass DebugView {\n\t\tconstructor(parent, type, name, title) {\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tparent : {\n\t\t\t\t\tvalue : parent\n\t\t\t\t},\n\n\t\t\t\tview : {\n\t\t\t\t\tvalue : document.createElement('span')\n\t\t\t\t},\n\n\t\t\t\tbreak : {\n\t\t\t\t\tvalue : document.createElement('wbr')\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Set up the wrapper (`<span>`) element.\n\t\t\tjQuery(this.view)\n\t\t\t\t.attr({\n\t\t\t\t\ttitle,\n\t\t\t\t\t'aria-label' : title,\n\t\t\t\t\t'data-type'  : type != null ? type : '', // lazy equality for null\n\t\t\t\t\t'data-name'  : name != null ? name : ''  // lazy equality for null\n\t\t\t\t})\n\t\t\t\t.addClass('debug');\n\n\t\t\t// Set up the word break (`<wbr>`) element.\n\t\t\tjQuery(this.break).addClass('debug hidden');\n\n\t\t\t// Add the wrapper (`<span>`) and word break (`<wbr>`) elements to the `parent` element.\n\t\t\tthis.parent.appendChild(this.view);\n\t\t\tthis.parent.appendChild(this.break);\n\t\t}\n\n\t\tget output() {\n\t\t\treturn this.view;\n\t\t}\n\n\t\tget type() {\n\t\t\treturn this.view.getAttribute('data-type');\n\t\t}\n\t\tset type(type) {\n\t\t\tthis.view.setAttribute('data-type', type != null ? type : ''); // lazy equality for null\n\t\t}\n\n\t\tget name() {\n\t\t\treturn this.view.getAttribute('data-name');\n\t\t}\n\t\tset name(name) {\n\t\t\tthis.view.setAttribute('data-name', name != null ? name : ''); // lazy equality for null\n\t\t}\n\n\t\tget title() {\n\t\t\treturn this.view.title;\n\t\t}\n\t\tset title(title) {\n\t\t\tthis.view.title = title;\n\t\t}\n\n\t\tappend(el) {\n\t\t\tjQuery(this.view).append(el);\n\t\t\treturn this;\n\t\t}\n\n\t\tmodes(options) {\n\t\t\tif (options == null) { // lazy equality for null\n\t\t\t\tconst current = {};\n\n\t\t\t\tthis.view.className.splitOrEmpty(/\\s+/).forEach(name => {\n\t\t\t\t\tif (name !== 'debug') {\n\t\t\t\t\t\tcurrent[name] = true;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\treturn current;\n\t\t\t}\n\t\t\telse if (typeof options === 'object') {\n\t\t\t\tObject.keys(options).forEach(function (name) {\n\t\t\t\t\tthis[options[name] ? 'addClass' : 'removeClass'](name);\n\t\t\t\t}, jQuery(this.view));\n\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tthrow new Error('DebugView.prototype.modes options parameter must be an object or null/undefined');\n\t\t}\n\n\t\tremove() {\n\t\t\tconst $view = jQuery(this.view);\n\n\t\t\tif (this.view.hasChildNodes()) {\n\t\t\t\t$view.contents().appendTo(this.parent);\n\t\t\t}\n\n\t\t\t$view.remove();\n\t\t\tjQuery(this.break).remove();\n\t\t}\n\n\t\tstatic isEnabled() {\n\t\t\treturn jQuery(document.documentElement).attr('data-debug-view') === 'enabled';\n\t\t}\n\n\t\tstatic enable() {\n\t\t\tjQuery(document.documentElement).attr('data-debug-view', 'enabled');\n\t\t\tjQuery.event.trigger(':debugviewupdate');\n\t\t}\n\n\t\tstatic disable() {\n\t\t\tjQuery(document.documentElement).removeAttr('data-debug-view');\n\t\t\tjQuery.event.trigger(':debugviewupdate');\n\t\t}\n\n\t\tstatic toggle() {\n\t\t\tif (jQuery(document.documentElement).attr('data-debug-view') === 'enabled') {\n\t\t\t\tDebugView.disable();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tDebugView.enable();\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn DebugView;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/prngwrapper.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar PRNGWrapper = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tPRNGWrapper Class.\n\t*******************************************************************************************************************/\n\tclass PRNGWrapper {\n\t\tconstructor(seed, useEntropy) {\n\t\t\t/* eslint-disable new-cap */\n\t\t\tObject.defineProperties(this, new Math.seedrandom(seed, useEntropy, (prng, seed) => ({\n\t\t\t\t_prng : {\n\t\t\t\t\tvalue : prng\n\t\t\t\t},\n\n\t\t\t\tseed : {\n\t\t\t\t\t/*\n\t\t\t\t\t\tTODO: Make this non-writable.\n\t\t\t\t\t*/\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : seed\n\t\t\t\t},\n\n\t\t\t\tpull : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\trandom : {\n\t\t\t\t\tvalue() {\n\t\t\t\t\t\t++this.pull;\n\t\t\t\t\t\treturn this._prng();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})));\n\t\t\t/* eslint-enable new-cap */\n\t\t}\n\n\t\tstatic marshal(prng) {\n\t\t\tif (!prng || !prng.hasOwnProperty('seed') || !prng.hasOwnProperty('pull')) {\n\t\t\t\tthrow new Error('PRNG is missing required data');\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tseed : prng.seed,\n\t\t\t\tpull : prng.pull\n\t\t\t};\n\t\t}\n\n\t\tstatic unmarshal(prngObj) {\n\t\t\tif (!prngObj || !prngObj.hasOwnProperty('seed') || !prngObj.hasOwnProperty('pull')) {\n\t\t\t\tthrow new Error('PRNG object is missing required data');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tCreate a new PRNG using the original seed and pull values from it until it\n\t\t\t\thas reached the original pull count.\n\t\t\t*/\n\t\t\tconst prng = new PRNGWrapper(prngObj.seed, false);\n\n\t\t\tfor (let i = prngObj.pull; i > 0; --i) {\n\t\t\t\tprng.random();\n\t\t\t}\n\n\t\t\treturn prng;\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn PRNGWrapper;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/stylewrapper.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns, Story, Wikifier */\n\nvar StyleWrapper = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tconst _imageMarkupRe    = new RegExp(Patterns.cssImage, 'g');\n\tconst _hasImageMarkupRe = new RegExp(Patterns.cssImage);\n\n\n\t/*******************************************************************************************************************\n\t\tStyleWrapper Class.\n\t*******************************************************************************************************************/\n\tclass StyleWrapper {\n\t\tconstructor(style) {\n\t\t\tif (style == null) { // lazy equality for null\n\t\t\t\tthrow new TypeError('StyleWrapper style parameter must be an HTMLStyleElement object');\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tstyle : {\n\t\t\t\t\tvalue : style\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tisEmpty() {\n\t\t\t// This should work in all supported browsers.\n\t\t\treturn this.style.cssRules.length === 0;\n\t\t}\n\n\t\tset(rawCss) {\n\t\t\tthis.clear();\n\t\t\tthis.add(rawCss);\n\t\t}\n\n\t\tadd(rawCss) {\n\t\t\tlet css = rawCss;\n\n\t\t\t// Check for wiki image transclusion.\n\t\t\tif (_hasImageMarkupRe.test(css)) {\n\t\t\t\t/*\n\t\t\t\t\tThe JavaScript specifications, since at least ES3, say that `<String>.replace()`\n\t\t\t\t\tshould reset a global-flagged regular expression's `lastIndex` property to `0`\n\t\t\t\t\tupon invocation.  Buggy browser versions exist, however, which do not reset\n\t\t\t\t\t`lastIndex`, so we should do so manually to support those browsers.\n\n\t\t\t\t\tNOTE: I do not think this is actually necessary, since `_imageMarkupRe` is\n\t\t\t\t\tscoped to this module—meaning users should not be able to access it.  That\n\t\t\t\t\tbeing the case, and since we search to exhaustion which should also cause\n\t\t\t\t\t`lastIndex` to be reset, there should never be an instance where we invoke\n\t\t\t\t\t`css.replace()` and `_imageMarkupRe.lastIndex` is not already `0`.  Still,\n\t\t\t\t\tconsidering the other bug, better safe than sorry.\n\t\t\t\t*/\n\t\t\t\t_imageMarkupRe.lastIndex = 0;\n\n\t\t\t\tcss = css.replace(_imageMarkupRe, wikiImage => {\n\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\tsource     : wikiImage,\n\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t});\n\n\t\t\t\t\tif (markup.hasOwnProperty('error') || markup.pos < wikiImage.length) {\n\t\t\t\t\t\treturn wikiImage;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet source = markup.source;\n\n\t\t\t\t\t// Handle image passage transclusion.\n\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\tsource = passage.text.trim();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tThe source may be URI- or Base64-encoded, so we cannot use `encodeURIComponent()`\n\t\t\t\t\t\there.  Instead, we simply encode any double quotes, since the URI will be\n\t\t\t\t\t\tdelimited by them.\n\t\t\t\t\t*/\n\t\t\t\t\treturn `url(\"${source.replace(/\"/g, '%22')}\")`;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// For IE ≤ 10.\n\t\t\tif (this.style.styleSheet) {\n\t\t\t\tthis.style.styleSheet.cssText += css;\n\t\t\t}\n\n\t\t\t// For all other browsers (incl. IE ≥ 11).\n\t\t\telse {\n\t\t\t\tthis.style.appendChild(document.createTextNode(css));\n\t\t\t}\n\t\t}\n\n\t\tclear() {\n\t\t\t// For IE ≤10.\n\t\t\tif (this.style.styleSheet) {\n\t\t\t\tthis.style.styleSheet.cssText = '';\n\t\t\t}\n\n\t\t\t// For all other browsers (incl. IE ≥11).\n\t\t\telse {\n\t\t\t\tjQuery(this.style).empty();\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn StyleWrapper;\n})();\n\n/***********************************************************************************************************************\n\n\tlib/diff.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util, clone */\n\nvar Diff = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tDiff Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tDiff operations object (pseudo-enumeration).\n\t*/\n\tconst Op = Util.toEnum({\n\t\tDelete      : 0,\n\t\tSpliceArray : 1,\n\t\tCopy        : 2,\n\t\tCopyDate    : 3\n\t});\n\n\t/*\n\t\tReturns a difference object generated from comparing the the orig and dest objects.\n\t*/\n\tfunction diff(orig, dest) /* diff object */ {\n\t\tconst objToString = Object.prototype.toString;\n\t\tconst origIsArray = orig instanceof Array;\n\t\tconst keys        = []\n\t\t\t.concat(Object.keys(orig), Object.keys(dest))\n\t\t\t.sort()\n\t\t\t.filter((val, i, arr) => i === 0 || arr[i - 1] !== val);\n\t\tconst diffed      = {};\n\t\tlet aOpRef;\n\n\t\tconst keyIsAOpRef = key => key === aOpRef;\n\n\t\t/* eslint-disable max-depth */\n\t\tfor (let i = 0, klen = keys.length; i < klen; ++i) {\n\t\t\tconst key   = keys[i];\n\t\t\tconst origP = orig[key];\n\t\t\tconst destP = dest[key];\n\n\t\t\tif (orig.hasOwnProperty(key)) {\n\t\t\t\t// Key exists in both.\n\t\t\t\tif (dest.hasOwnProperty(key)) {\n\t\t\t\t\t// Values are exactly the same, so do nothing.\n\t\t\t\t\tif (origP === destP) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Values are of the same basic type.\n\t\t\t\t\tif (typeof origP === typeof destP) { // eslint-disable-line valid-typeof\n\t\t\t\t\t\t// Values are functions.\n\t\t\t\t\t\tif (typeof origP === 'function') {\n\t\t\t\t\t\t\t/* diffed[key] = [Op.Copy, destP]; */\n\t\t\t\t\t\t\tif (origP.toString() !== destP.toString()) {\n\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, destP];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Values are primitives.\n\t\t\t\t\t\telse if (typeof origP !== 'object' || origP === null) {\n\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, destP];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Values are objects.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst origPType = objToString.call(origP);\n\t\t\t\t\t\t\tconst destPType = objToString.call(destP);\n\n\t\t\t\t\t\t\t// Values are objects of the same reported type.\n\t\t\t\t\t\t\tif (origPType === destPType) {\n\t\t\t\t\t\t\t\t// Various special cases to handle supported non-generic objects.\n\t\t\t\t\t\t\t\tif (origP instanceof Date) {\n\t\t\t\t\t\t\t\t\tif (Number(origP) !== Number(destP)) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof Map) {\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof RegExp) {\n\t\t\t\t\t\t\t\t\tif (origP.toString() !== destP.toString()) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (origP instanceof Set) {\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Unknown non-generic objects (custom or unsupported natives).\n\t\t\t\t\t\t\t\telse if (origPType !== '[object Object]') {\n\t\t\t\t\t\t\t\t\t// We cannot know how to process these objects,\n\t\t\t\t\t\t\t\t\t// so we simply accept them as-is.\n\t\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Generic objects.\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tconst recurse = diff(origP, destP);\n\n\t\t\t\t\t\t\t\t\tif (recurse !== null) {\n\t\t\t\t\t\t\t\t\t\tdiffed[key] = recurse;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Values are objects of different reported types.\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tdiffed[key] = [Op.Copy, clone(destP)];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Values are of different types.\n\t\t\t\t\telse {\n\t\t\t\t\t\tdiffed[key] = [\n\t\t\t\t\t\t\tOp.Copy,\n\t\t\t\t\t\t\ttypeof destP !== 'object' || destP === null ? destP : clone(destP)\n\t\t\t\t\t\t];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Key only exists in orig.\n\t\t\t\telse {\n\t\t\t\t\tif (origIsArray && Util.isNumeric(key)) {\n\t\t\t\t\t\tconst nKey = Number(key);\n\n\t\t\t\t\t\tif (!aOpRef) {\n\t\t\t\t\t\t\taOpRef = '';\n\n\t\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\t\taOpRef += '~';\n\t\t\t\t\t\t\t} while (keys.some(keyIsAOpRef));\n\n\t\t\t\t\t\t\tdiffed[aOpRef] = [Op.SpliceArray, nKey, nKey];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (nKey < diffed[aOpRef][1]) {\n\t\t\t\t\t\t\tdiffed[aOpRef][1] = nKey;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (nKey > diffed[aOpRef][2]) {\n\t\t\t\t\t\t\tdiffed[aOpRef][2] = nKey;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdiffed[key] = Op.Delete;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Key only exists in dest.\n\t\t\telse {\n\t\t\t\tdiffed[key] = [\n\t\t\t\t\tOp.Copy,\n\t\t\t\t\ttypeof destP !== 'object' || destP === null ? destP : clone(destP)\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\t\t/* eslint-enable max-depth */\n\n\t\treturn Object.keys(diffed).length > 0 ? diffed : null;\n\t}\n\n\t/*\n\t\tReturns the object resulting from updating the orig object with the diffed object.\n\t*/\n\tfunction patch(orig, diffed) /* patched object */ {\n\t\tconst keys    = Object.keys(diffed || {});\n\t\tconst patched = clone(orig);\n\n\t\tfor (let i = 0, klen = keys.length; i < klen; ++i) {\n\t\t\tconst key     = keys[i];\n\t\t\tconst diffedP = diffed[key];\n\n\t\t\tif (diffedP === Op.Delete) {\n\t\t\t\tdelete patched[key];\n\t\t\t}\n\t\t\telse if (diffedP instanceof Array) {\n\t\t\t\tswitch (diffedP[0]) {\n\t\t\t\tcase Op.SpliceArray:\n\t\t\t\t\tpatched.splice(diffedP[1], 1 + (diffedP[2] - diffedP[1]));\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase Op.Copy:\n\t\t\t\t\tpatched[key] = clone(diffedP[1]);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase Op.CopyDate:\n\t\t\t\t\tpatched[key] = new Date(diffedP[1]);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tpatched[key] = patch(patched[key], diffedP);\n\t\t\t}\n\t\t}\n\n\t\treturn patched;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tOp    : { value : Op },\n\t\tdiff  : { value : diff },\n\t\tpatch : { value : patch }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tl10n/l10n.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global l10nStrings, strings */\n\nvar L10n = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Replacement pattern regular expressions.\n\tconst _patternRe    = /\\{\\w+\\}/g;\n\tconst _hasPatternRe = new RegExp(_patternRe.source); // to drop the global flag\n\n\n\t/*******************************************************************************************************************\n\t\tLocalization Functions.\n\t*******************************************************************************************************************/\n\tfunction l10nInit() {\n\t\t/* legacy */\n\t\t_mapStringsToL10nStrings();\n\t\t/* /legacy */\n\t}\n\n\t/*******************************************************************************************************************\n\t\tLocalized String Functions.\n\t*******************************************************************************************************************/\n\tfunction l10nGet(ids, overrides) {\n\t\tif (!ids) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst id = (idList => {\n\t\t\tlet selectedId;\n\t\t\tidList.some(id => {\n\t\t\t\tif (l10nStrings.hasOwnProperty(id)) {\n\t\t\t\t\tselectedId = id;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\treturn selectedId;\n\t\t})(Array.isArray(ids) ? ids : [ids]);\n\n\t\tif (!id) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst maxIterations = 50;\n\t\tlet processed = l10nStrings[id];\n\t\tlet iteration = 0;\n\n\t\twhile (_hasPatternRe.test(processed)) {\n\t\t\tif (++iteration > maxIterations) {\n\t\t\t\tthrow new Error('L10n.get exceeded maximum replacement iterations, probable infinite loop');\n\t\t\t}\n\n\t\t\t// Possibly required by some old buggy browsers.\n\t\t\t_patternRe.lastIndex = 0;\n\n\t\t\tprocessed = processed.replace(_patternRe, pat => {\n\t\t\t\tconst subId = pat.slice(1, -1);\n\n\t\t\t\tif (overrides && overrides.hasOwnProperty(subId)) {\n\t\t\t\t\treturn overrides[subId];\n\t\t\t\t}\n\t\t\t\telse if (l10nStrings.hasOwnProperty(subId)) {\n\t\t\t\t\treturn l10nStrings[subId];\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treturn processed;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tLegacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tAttempt to map legacy `strings` object properties to the `l10nStrings` object.\n\t*/\n\tfunction _mapStringsToL10nStrings() {\n\t\tif (strings && Object.keys(strings).length > 0) {\n\t\t\tObject.keys(l10nStrings).forEach(id => {\n\t\t\t\ttry {\n\t\t\t\t\tlet value;\n\n\t\t\t\t\tswitch (id) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tGeneral.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'identity': value = strings.identity; break;\n\t\t\t\t\tcase 'aborting': value = strings.aborting; break;\n\t\t\t\t\tcase 'cancel':   value = strings.cancel; break;\n\t\t\t\t\tcase 'close':    value = strings.close; break;\n\t\t\t\t\tcase 'ok':       value = strings.ok; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tErrors.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'errorTitle':              value = strings.errors.title; break;\n\t\t\t\t\tcase 'errorNonexistentPassage': value = strings.errors.nonexistentPassage; break;\n\t\t\t\t\tcase 'errorSaveMissingData':    value = strings.errors.saveMissingData; break;\n\t\t\t\t\tcase 'errorSaveIdMismatch':     value = strings.errors.saveIdMismatch; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tWarnings.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'warningDegraded': value = strings.warnings.degraded; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tDebug View.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'debugViewTitle':  value = strings.debugView.title; break;\n\t\t\t\t\tcase 'debugViewToggle': value = strings.debugView.toggle; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tUI bar.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'uiBarToggle':   value = strings.uiBar.toggle; break;\n\t\t\t\t\tcase 'uiBarBackward': value = strings.uiBar.backward; break;\n\t\t\t\t\tcase 'uiBarForward':  value = strings.uiBar.forward; break;\n\t\t\t\t\tcase 'uiBarJumpto':   value = strings.uiBar.jumpto; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tJump To.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'jumptoTitle':       value = strings.jumpto.title; break;\n\t\t\t\t\tcase 'jumptoTurn':        value = strings.jumpto.turn; break;\n\t\t\t\t\tcase 'jumptoUnavailable': value = strings.jumpto.unavailable; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tSaves.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'savesTitle':       value = strings.saves.title; break;\n\t\t\t\t\tcase 'savesDisallowed':  value = strings.saves.disallowed; break;\n\t\t\t\t\tcase 'savesIncapable':   value = strings.saves.incapable; break;\n\t\t\t\t\tcase 'savesLabelAuto':   value = strings.saves.labelAuto; break;\n\t\t\t\t\tcase 'savesLabelDelete': value = strings.saves.labelDelete; break;\n\t\t\t\t\tcase 'savesLabelExport': value = strings.saves.labelExport; break;\n\t\t\t\t\tcase 'savesLabelImport': value = strings.saves.labelImport; break;\n\t\t\t\t\tcase 'savesLabelLoad':   value = strings.saves.labelLoad; break;\n\t\t\t\t\tcase 'savesLabelClear':  value = strings.saves.labelClear; break;\n\t\t\t\t\tcase 'savesLabelSave':   value = strings.saves.labelSave; break;\n\t\t\t\t\tcase 'savesLabelSlot':   value = strings.saves.labelSlot; break;\n\t\t\t\t\tcase 'savesUnavailable': value = strings.saves.unavailable; break;\n\t\t\t\t\tcase 'savesUnknownDate': value = strings.saves.unknownDate; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tSettings.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'settingsTitle': value = strings.settings.title; break;\n\t\t\t\t\tcase 'settingsOff':   value = strings.settings.off; break;\n\t\t\t\t\tcase 'settingsOn':    value = strings.settings.on; break;\n\t\t\t\t\tcase 'settingsReset': value = strings.settings.reset; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tRestart.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'restartTitle':  value = strings.restart.title; break;\n\t\t\t\t\tcase 'restartPrompt': value = strings.restart.prompt; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tShare.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'shareTitle': value = strings.share.title; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAlert.\n\t\t\t\t\t*/\n\t\t\t\t\t/* none */\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAutoload.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'autoloadTitle':  value = strings.autoload.title; break;\n\t\t\t\t\tcase 'autoloadCancel': value = strings.autoload.cancel; break;\n\t\t\t\t\tcase 'autoloadOk':     value = strings.autoload.ok; break;\n\t\t\t\t\tcase 'autoloadPrompt': value = strings.autoload.prompt; break;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tMacros.\n\t\t\t\t\t*/\n\t\t\t\t\tcase 'macroBackText':   value = strings.macros.back.text; break;\n\t\t\t\t\tcase 'macroReturnText': value = strings.macros.return.text; break;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (value) {\n\t\t\t\t\t\tl10nStrings[id] = value.replace(/%\\w+%/g, pat => `{${pat.slice(1, -1)}}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t});\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tLocalization Functions.\n\t\t*/\n\t\tinit : { value : l10nInit },\n\n\t\t/*\n\t\t\tLocalized String Functions.\n\t\t*/\n\t\tget : { value : l10nGet }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tl10n/legacy.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\n/*\n\t[DEPRECATED] The `strings` object is deprecated and should no longer be used.\n\tAll new or updated translations should be based upon the `l10nStrings` object\n\t(see: `l10n/strings.js`).\n\n\tLegacy/existing uses of the `strings` object will be mapped to the `l10nStrings`\n\tobject after user script evaluation.\n*/\nvar strings = { // eslint-disable-line no-unused-vars, no-var\n\terrors    : {},\n\twarnings  : {},\n\tdebugView : {},\n\tuiBar     : {},\n\tjumpto    : {},\n\tsaves     : {},\n\tsettings  : {},\n\trestart   : {},\n\tshare     : {},\n\tautoload  : {},\n\tmacros    : {\n\t\tback   : {},\n\t\treturn : {}\n\t}\n};\n\n/***********************************************************************************************************************\n\n\tl10n/strings.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* eslint-disable max-len, prefer-template */\n\n/*\n\tATTENTION TRANSLATORS\n\n\tPlease use the `locale/l10n-template.js` file, from the root of the repository,\n\tas the template for your translation rather than this file.\n\n\tSEE: https://github.com/tmedwards/sugarcube-2/tree/develop/locale\n*/\nvar l10nStrings = { // eslint-disable-line no-unused-vars, no-var\n\t/*\n\t\tGeneral.\n\t*/\n\tidentity : 'game',\n\taborting : 'Aborting',\n\tcancel   : 'Cancel',\n\tclose    : 'Close',\n\tok       : 'OK',\n\n\t/*\n\t\tErrors.\n\t*/\n\terrorTitle              : 'Error',\n\terrorToggle             : 'Toggle the error view',\n\terrorNonexistentPassage : 'the passage \"{passage}\" does not exist', // NOTE: `passage` is supplied locally\n\terrorSaveMissingData    : 'save is missing required data. Either the loaded file is not a save or the save has become corrupted',\n\terrorSaveIdMismatch     : 'save is from the wrong {identity}',\n\n\t/*\n\t\tWarnings.\n\t*/\n\t_warningIntroLacking  : 'Your browser either lacks or has disabled',\n\t_warningOutroDegraded : ', so this {identity} is running in a degraded mode. You may be able to continue, however, some parts may not work properly.',\n\twarningNoWebStorage   : '{_warningIntroLacking} the Web Storage API{_warningOutroDegraded}',\n\twarningDegraded       : '{_warningIntroLacking} some of the capabilities required by this {identity}{_warningOutroDegraded}',\n\n\t/*\n\t\tDebug bar.\n\t*/\n\tdebugBarToggle      : 'Toggle the debug bar',\n\tdebugBarNoWatches   : '\\u2014 no watches set \\u2014',\n\tdebugBarAddWatch    : 'Add watch',\n\tdebugBarDeleteWatch : 'Delete watch',\n\tdebugBarWatchAll    : 'Watch all',\n\tdebugBarWatchNone   : 'Delete all',\n\tdebugBarLabelAdd    : 'Add',\n\tdebugBarLabelWatch  : 'Watch',\n\tdebugBarLabelTurn   : 'Turn', // (noun) chance to act (in a game), moment, period\n\tdebugBarLabelViews  : 'Views',\n\tdebugBarViewsToggle : 'Toggle the debug views',\n\tdebugBarWatchToggle : 'Toggle the watch panel',\n\n\t/*\n\t\tUI bar.\n\t*/\n\tuiBarToggle   : 'Toggle the UI bar',\n\tuiBarBackward : 'Go backward within the {identity} history',\n\tuiBarForward  : 'Go forward within the {identity} history',\n\tuiBarJumpto   : 'Jump to a specific point within the {identity} history',\n\n\t/*\n\t\tJump To.\n\t*/\n\tjumptoTitle       : 'Jump To',\n\tjumptoTurn        : 'Turn', // (noun) chance to act (in a game), moment, period\n\tjumptoUnavailable : 'No jump points currently available\\u2026',\n\n\t/*\n\t\tSaves.\n\t*/\n\tsavesTitle       : 'Saves',\n\tsavesDisallowed  : 'Saving has been disallowed on this passage.',\n\tsavesIncapable   : '{_warningIntroLacking} the capabilities required to support saves, so saves have been disabled for this session.',\n\tsavesLabelAuto   : 'Autosave',\n\tsavesLabelDelete : 'Delete',\n\tsavesLabelExport : 'Save to Disk\\u2026',\n\tsavesLabelImport : 'Load from Disk\\u2026',\n\tsavesLabelLoad   : 'Load',\n\tsavesLabelClear  : 'Delete All',\n\tsavesLabelSave   : 'Save',\n\tsavesLabelSlot   : 'Slot',\n\tsavesUnavailable : 'No save slots found\\u2026',\n\tsavesUnknownDate : 'unknown',\n\n\t/*\n\t\tSettings.\n\t*/\n\tsettingsTitle : 'Settings',\n\tsettingsOff   : 'Off',\n\tsettingsOn    : 'On',\n\tsettingsReset : 'Reset to Defaults',\n\n\t/*\n\t\tRestart.\n\t*/\n\trestartTitle  : 'Restart',\n\trestartPrompt : 'Are you sure that you want to restart? Unsaved progress will be lost.',\n\n\t/*\n\t\tShare.\n\t*/\n\tshareTitle : 'Share',\n\n\t/*\n\t\tAlert.\n\t*/\n\t/* none */\n\n\t/*\n\t\tAutoload.\n\t*/\n\tautoloadTitle  : 'Autoload',\n\tautoloadCancel : 'Go to start',\n\tautoloadOk     : 'Load autosave',\n\tautoloadPrompt : 'An autosave exists. Load it now or go to the start?',\n\n\t/*\n\t\tMacros.\n\t*/\n\tmacroBackText   : 'Back',  // (verb) rewind, revert\n\tmacroReturnText : 'Return' // (verb) go/send back\n};\n\n/***********************************************************************************************************************\n\n\tconfig.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util */\n\nvar Config = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// General settings.\n\tlet _debug                 = false;\n\tlet _addVisitedLinkClass   = false;\n\tlet _cleanupWikifierOutput = false;\n\tlet _loadDelay             = 0;\n\n\t// Audio settings.\n\tlet _audioPauseOnFadeToZero = true;\n\tlet _audioPreloadMetadata   = true;\n\n\t// State history settings.\n\tlet _historyControls  = true;\n\tlet _historyMaxStates = 100;\n\n\t// Macros settings.\n\tlet _macrosIfAssignmentError = true;\n\tlet _macrosMaxLoopIterations = 1000;\n\n\t// Navigation settings.\n\tlet _navigationOverride;\n\n\t// Passages settings.\n\tlet _passagesDescriptions;\n\tlet _passagesDisplayTitles = false;\n\tlet _passagesNobr          = false;\n\tlet _passagesStart; // set by `Story.load()`\n\tlet _passagesOnProcess;\n\tlet _passagesTransitionOut;\n\n\t// Saves settings.\n\tlet _savesAutoload;\n\tlet _savesAutosave;\n\tlet _savesId        = 'untitled-story';\n\tlet _savesIsAllowed;\n\tlet _savesOnLoad;\n\tlet _savesOnSave;\n\tlet _savesSlots     = 8;\n\tlet _savesVersion;\n\n\t// UI settings.\n\tlet _uiStowBarInitially    = 800;\n\tlet _uiUpdateStoryElements = true;\n\n\n\t/*******************************************************************************\n\t\tError Constants.\n\t*******************************************************************************/\n\n\tconst _errHistoryModeDeprecated     = 'Config.history.mode has been deprecated and is no longer used by SugarCube, please remove it from your code';\n\tconst _errHistoryTrackingDeprecated = 'Config.history.tracking has been deprecated, use Config.history.maxStates instead';\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze({\n\t\t/*\n\t\t\tGeneral settings.\n\t\t*/\n\t\tget debug() { return _debug; },\n\t\tset debug(value) { _debug = Boolean(value); },\n\n\t\tget addVisitedLinkClass() { return _addVisitedLinkClass; },\n\t\tset addVisitedLinkClass(value) { _addVisitedLinkClass = Boolean(value); },\n\n\t\tget cleanupWikifierOutput() { return _cleanupWikifierOutput; },\n\t\tset cleanupWikifierOutput(value) { _cleanupWikifierOutput = Boolean(value); },\n\n\t\tget loadDelay() { return _loadDelay; },\n\t\tset loadDelay(value) {\n\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\tthrow new RangeError('Config.loadDelay must be a non-negative integer');\n\t\t\t}\n\n\t\t\t_loadDelay = value;\n\t\t},\n\n\t\t/*\n\t\t\tAudio settings.\n\t\t*/\n\t\taudio : Object.freeze({\n\t\t\tget pauseOnFadeToZero() { return _audioPauseOnFadeToZero; },\n\t\t\tset pauseOnFadeToZero(value) { _audioPauseOnFadeToZero = Boolean(value); },\n\n\t\t\tget preloadMetadata() { return _audioPreloadMetadata; },\n\t\t\tset preloadMetadata(value) { _audioPreloadMetadata = Boolean(value); }\n\t\t}),\n\n\t\t/*\n\t\t\tState history settings.\n\t\t*/\n\t\thistory : Object.freeze({\n\t\t\t// TODO: (v3) This should be under UI settings → `Config.ui.historyControls`.\n\t\t\tget controls() { return _historyControls; },\n\t\t\tset controls(value) {\n\t\t\t\tconst controls = Boolean(value);\n\n\t\t\t\tif (_historyMaxStates === 1 && controls) {\n\t\t\t\t\tthrow new Error('Config.history.controls must be false when Config.history.maxStates is 1');\n\t\t\t\t}\n\n\t\t\t\t_historyControls = controls;\n\t\t\t},\n\n\t\t\tget maxStates() { return _historyMaxStates; },\n\t\t\tset maxStates(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new RangeError('Config.history.maxStates must be a non-negative integer');\n\t\t\t\t}\n\n\t\t\t\t_historyMaxStates = value;\n\n\t\t\t\t// Force `Config.history.controls` to `false`, when limited to `1` moment.\n\t\t\t\tif (_historyControls && value === 1) {\n\t\t\t\t\t_historyControls = false;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// legacy\n\t\t\t// Die if deprecated state history settings are accessed.\n\t\t\tget mode()  { throw new Error(_errHistoryModeDeprecated); },\n\t\t\tset mode(_) { throw new Error(_errHistoryModeDeprecated); },\n\t\t\tget tracking()  { throw new Error(_errHistoryTrackingDeprecated); },\n\t\t\tset tracking(_) { throw new Error(_errHistoryTrackingDeprecated); }\n\t\t\t// /legacy\n\t\t}),\n\n\t\t/*\n\t\t\tMacros settings.\n\t\t*/\n\t\tmacros : Object.freeze({\n\t\t\tget ifAssignmentError() { return _macrosIfAssignmentError; },\n\t\t\tset ifAssignmentError(value) { _macrosIfAssignmentError = Boolean(value); },\n\n\t\t\tget maxLoopIterations() { return _macrosMaxLoopIterations; },\n\t\t\tset maxLoopIterations(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new RangeError('Config.macros.maxLoopIterations must be a non-negative integer');\n\t\t\t\t}\n\n\t\t\t\t_macrosMaxLoopIterations = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tNavigation settings.\n\t\t*/\n\t\tnavigation : Object.freeze({\n\t\t\tget override() { return _navigationOverride; },\n\t\t\tset override(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.navigation.override must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_navigationOverride = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tPassages settings.\n\t\t*/\n\t\tpassages : Object.freeze({\n\t\t\tget descriptions() { return _passagesDescriptions; },\n\t\t\tset descriptions(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'boolean' && valueType !== 'Object' && valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.descriptions must be a boolean, object, function, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesDescriptions = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.updateTitle`.\n\t\t\tget displayTitles() { return _passagesDisplayTitles; },\n\t\t\tset displayTitles(value) { _passagesDisplayTitles = Boolean(value); },\n\n\t\t\tget nobr() { return _passagesNobr; },\n\t\t\tset nobr(value) { _passagesNobr = Boolean(value); },\n\n\t\t\tget onProcess() { return _passagesOnProcess; },\n\t\t\tset onProcess(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.onProcess must be a function or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesOnProcess = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.(start|startingPassage)`.\n\t\t\tget start() { return _passagesStart; },\n\t\t\tset start(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'string') {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.start must be a string or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesStart = value;\n\t\t\t},\n\n\t\t\t// TODO: (v3) This should be under Navigation settings → `Config.navigation.transitionOut`.\n\t\t\tget transitionOut() { return _passagesTransitionOut; },\n\t\t\tset transitionOut(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t   valueType !== 'string'\n\t\t\t\t\t\t&& (valueType !== 'number' || !Number.isSafeInteger(value) || value < 0)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new TypeError(`Config.passages.transitionOut must be a string, non-negative integer, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_passagesTransitionOut = value;\n\t\t\t}\n\t\t}),\n\n\t\t/*\n\t\t\tSaves settings.\n\t\t*/\n\t\tsaves : Object.freeze({\n\t\t\tget autoload() { return _savesAutoload; },\n\t\t\tset autoload(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\tif (valueType !== 'boolean' && valueType !== 'string' && valueType !== 'function') {\n\t\t\t\t\t\tthrow new TypeError(`Config.saves.autoload must be a boolean, string, function, or null/undefined (received: ${valueType})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_savesAutoload = value;\n\t\t\t},\n\n\t\t\tget autosave() { return _savesAutosave; },\n\t\t\tset autosave(value) {\n\t\t\t\tif (value != null) { // lazy equality for null\n\t\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\t\t// legacy\n\t\t\t\t\t// Convert a string value to an Array of string.\n\t\t\t\t\tif (valueType === 'string') {\n\t\t\t\t\t\t_savesAutosave = [value];\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// /legacy\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t   valueType !== 'boolean'\n\t\t\t\t\t\t&& (valueType !== 'Array' || !value.every(item => typeof item === 'string'))\n\t\t\t\t\t\t&& valueType !== 'function'\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new TypeError(`Config.saves.autosave must be a boolean, Array of strings, function, or null/undefined (received: ${valueType}${valueType === 'Array' ? ' of mixed' : ''})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_savesAutosave = value;\n\t\t\t},\n\n\t\t\tget id() { return _savesId; },\n\t\t\tset id(value) {\n\t\t\t\tif (typeof value !== 'string' || value === '') {\n\t\t\t\t\tthrow new TypeError(`Config.saves.id must be a non-empty string (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesId = value;\n\t\t\t},\n\n\t\t\tget isAllowed() { return _savesIsAllowed; },\n\t\t\tset isAllowed(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.isAllowed must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesIsAllowed = value;\n\t\t\t},\n\n\t\t\tget onLoad() { return _savesOnLoad; },\n\t\t\tset onLoad(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.onLoad must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesOnLoad = value;\n\t\t\t},\n\n\t\t\tget onSave() { return _savesOnSave; },\n\t\t\tset onSave(value) {\n\t\t\t\tif (!(value == null || value instanceof Function)) { // lazy equality for null\n\t\t\t\t\tthrow new TypeError(`Config.saves.onSave must be a function or null/undefined (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesOnSave = value;\n\t\t\t},\n\n\t\t\tget slots() { return _savesSlots; },\n\t\t\tset slots(value) {\n\t\t\t\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\t\t\t\tthrow new TypeError(`Config.saves.slots must be a non-negative integer (received: ${Util.getType(value)})`);\n\t\t\t\t}\n\n\t\t\t\t_savesSlots = value;\n\t\t\t},\n\n\t\t\tget version() { return _savesVersion; },\n\t\t\tset version(value) { _savesVersion = value; }\n\t\t}),\n\n\t\t/*\n\t\t\tUI settings.\n\t\t*/\n\t\tui : Object.freeze({\n\t\t\tget stowBarInitially() { return _uiStowBarInitially; },\n\t\t\tset stowBarInitially(value) {\n\t\t\t\tconst valueType = Util.getType(value);\n\n\t\t\t\tif (\n\t\t\t\t\t   valueType !== 'boolean'\n\t\t\t\t\t&& (valueType !== 'number' || !Number.isSafeInteger(value) || value < 0)\n\t\t\t\t) {\n\t\t\t\t\tthrow new TypeError(`Config.ui.stowBarInitially must be a boolean or non-negative integer (received: ${valueType})`);\n\t\t\t\t}\n\n\t\t\t\t_uiStowBarInitially = value;\n\t\t\t},\n\n\t\t\tget updateStoryElements() { return _uiUpdateStoryElements; },\n\t\t\tset updateStoryElements(value) { _uiUpdateStoryElements = Boolean(value); }\n\t\t})\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tsimpleaudio.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Browser, Config, Has, LoadScreen, Story, Util, Visibility, clone */\n\nvar SimpleAudio = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*\n\t\tEvents that count as user activation—i.e. \"user gestures\", \"activation behavior\".\n\n\t\tNOTE (ca. Dec, 2018): This not an exhaustive list and varies significantly by browser.\n\t\tProposals for a specification/standard are still very much in flux at this point.\n\n\t\tTODO (ca. Dec, 2018): Revisit this topic.\n\n\t\tSEE: (too many to list)\n\t\t\thttps://github.com/whatwg/html/issues/3849\n\t\t\thttps://github.com/whatwg/html/issues/1903\n\t\t\thttps://html.spec.whatwg.org/#activation\n\t\t\thttps://docs.google.com/spreadsheets/d/1DGXjhQ6D3yZXIePOMo0dsd2agz0t5W7rYH1NwJ-QGJo/edit#gid=0\n\t*/\n\tconst _gestureEventNames = Object.freeze(['click', 'contextmenu', 'dblclick', 'keyup', 'mouseup', 'pointerup', 'touchend']);\n\n\t// Special group IDs.\n\tconst _specialIds = Object.freeze([':not', ':all', ':looped', ':muted', ':paused', ':playing']);\n\n\t// Format specifier regular expression.\n\tconst _formatSpecRe = /^([\\w-]+)\\s*\\|\\s*(\\S.*)$/; // e.g. 'mp3|https://audiohost.tld/id'\n\n\t// ID verification regular expressions.\n\tconst _badIdRe = /[:\\s]/;\n\n\t// Tracks collection.\n\tconst _tracks = new Map();\n\n\t// Groups collection.\n\tconst _groups = new Map();\n\n\t// Playlists collection.\n\tconst _lists = new Map();\n\n\t// Subscriber collection.\n\tconst _subscribers = new Map();\n\n\t// Master playback rate.\n\tlet _masterRate = 1;\n\n\t// Master playback volume.\n\tlet _masterVolume = 1;\n\n\t// Master mute state.\n\tlet _masterMute = false;\n\n\t// Master mute on tab/window visibility state.\n\tlet _masterMuteOnHidden = false;\n\n\n\t/*******************************************************************************************************************\n\t\tFeature Detection Functions.\n\t*******************************************************************************************************************/\n\t// Return whether the `<HTMLAudioElement>.play()` method returns a `Promise`.\n\t//\n\t// NOTE: The initial result is cached for future calls.\n\tconst _playReturnsPromise = (function () {\n\t\t// Cache of whether `<HTMLAudioElement>.play()` returns a `Promise`.\n\t\tlet _hasPromise = null;\n\n\t\tfunction _playReturnsPromise() {\n\t\t\tif (_hasPromise !== null) {\n\t\t\t\treturn _hasPromise;\n\t\t\t}\n\n\t\t\t_hasPromise = false;\n\n\t\t\tif (Has.audio) {\n\t\t\t\ttry {\n\t\t\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t\t\t// NOTE (ca. Jan 01, 2020): Firefox will still log an \"Autoplay is only allowed\n\t\t\t\t\t// when […] media is muted.\" message to the console when attempting the test\n\t\t\t\t\t// below, even though the audio has been muted.  Stay classy, Firefox.\n\t\t\t\t\t//\n\t\t\t\t\t// QUESTION (ca. Jan 01, 2020): Keep this?  It's only here to appease Firefox,\n\t\t\t\t\t// but doesn't seem to work as Firefox seems to ignore mute in violation of the\n\t\t\t\t\t// `HTMLAudioElement` specification—willfully or simply a bug, I can't say.\n\t\t\t\t\taudio.muted = true;\n\n\t\t\t\t\tconst value = audio.play();\n\n\t\t\t\t\t// Silence \"Uncaught (in promise)\" console errors from Blink.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: Swallowing errors is generally bad, but in this case we know there's\n\t\t\t\t\t// going to be an error regardless, since there's no source, and we don't actually\n\t\t\t\t\t// care about the error, since we just want the return value, so we consign it\n\t\t\t\t\t// to the bit bucket.\n\t\t\t\t\t//\n\t\t\t\t\t// NOTE: We don't ensure that the return value is not `undefined` here because\n\t\t\t\t\t// having the attempted call to `<Promise>.catch()` on an `undefined` value throw\n\t\t\t\t\t// is acceptable, since it will be caught and `false` eventually returned.\n\t\t\t\t\tvalue.catch(() => { /* no-op */ });\n\n\t\t\t\t\t_hasPromise = value instanceof Promise;\n\t\t\t\t}\n\t\t\t\tcatch (ex) { /* no-op */ }\n\t\t\t}\n\n\t\t\treturn _hasPromise;\n\t\t}\n\n\t\treturn _playReturnsPromise;\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tAudioTrack Class.\n\t*******************************************************************************************************************/\n\tclass AudioTrack {\n\t\tconstructor(obj) {\n\t\t\t// Process the given array of sources or AudioTrack object.\n\t\t\tif (obj instanceof Array) {\n\t\t\t\tthis._create(obj);\n\t\t\t}\n\t\t\telse if (obj instanceof AudioTrack) {\n\t\t\t\tthis._copy(obj);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('sources parameter must be either an array, of URIs or source objects, or an AudioTrack instance');\n\t\t\t}\n\t\t}\n\n\t\t_create(sourceList) {\n\t\t\tconst dataUriRe   = /^data:\\s*audio\\/([^;,]+)\\s*[;,]/i;\n\t\t\tconst extRe       = /\\.([^./\\\\]+)$/;\n\t\t\tconst getType     = AudioTrack.getType;\n\t\t\tconst usedSources = [];\n\t\t\t/*\n\t\t\t\tHTMLAudioElement: DOM factory method vs. constructor\n\n\t\t\t\tUse of the DOM factory method, `document.createElement('audio')`, should be\n\t\t\t\tpreferred over use of the constructor, `new Audio()`.  The reason being that\n\t\t\t\tobjects created by the latter are, erroneously, treated differently, often\n\t\t\t\tunfavorably, by certain browser engines—e.g. within some versions of the iOS\n\t\t\t\tbrowser core.\n\n\t\t\t\tNotably, the only difference between the two, per the specification, is that\n\t\t\t\tobjects created via the constructor should have their `preload` property\n\t\t\t\tautomatically set to 'auto'.  Thus, there's no technical reason to prefer\n\t\t\t\tusage of the constructor, even discounting buggy browser implementations.\n\t\t\t*/\n\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t// Initially set the `preload` attribute to `'none'`.\n\t\t\taudio.preload = 'none';\n\n\t\t\t// Process the array of sources, adding any valid sources to the `usedSources`\n\t\t\t// array and to the audio element as source elements.\n\t\t\tsourceList.forEach(src => {\n\t\t\t\tlet srcObj = null;\n\n\t\t\t\tswitch (typeof src) {\n\t\t\t\tcase 'string':\n\t\t\t\t\t{\n\t\t\t\t\t\tlet match;\n\n\t\t\t\t\t\tif (src.slice(0, 5) === 'data:') {\n\t\t\t\t\t\t\tmatch = dataUriRe.exec(src);\n\n\t\t\t\t\t\t\tif (match === null) {\n\t\t\t\t\t\t\t\tthrow new Error('source data URI missing media type');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tmatch = extRe.exec(Util.parseUrl(src).pathname);\n\n\t\t\t\t\t\t\tif (match === null) {\n\t\t\t\t\t\t\t\tthrow new Error('source URL missing file extension');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst type = getType(match[1]);\n\n\t\t\t\t\t\tif (type !== null) {\n\t\t\t\t\t\t\tsrcObj = { src, type };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\t{\n\t\t\t\t\t\tif (src === null) {\n\t\t\t\t\t\t\tthrow new Error('source object cannot be null');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (!src.hasOwnProperty('src')) {\n\t\t\t\t\t\t\tthrow new Error('source object missing required \"src\" property');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (!src.hasOwnProperty('format')) {\n\t\t\t\t\t\t\tthrow new Error('source object missing required \"format\" property');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst type = getType(src.format);\n\n\t\t\t\t\t\tif (type !== null) {\n\t\t\t\t\t\t\tsrcObj = { src : src.src, type };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`invalid source value (type: ${typeof src})`);\n\t\t\t\t}\n\n\t\t\t\tif (srcObj !== null) {\n\t\t\t\t\t/*\n\t\t\t\t\t\tOpera (Blink; ca. Jul 2017) fails to play audio from some sources\n\t\t\t\t\t\twith MIME-types containing a `codecs` parameter, despite the fact\n\t\t\t\t\t\tthat `canPlayType()` blessed the full MIME-type including `codecs`.\n\n\t\t\t\t\t\tBizarrely, this only affects some MIME-types—e.g. MP3s are affected,\n\t\t\t\t\t\twhile WAVEs are not.\n\t\t\t\t\t\t\tFails: 'audio/mpeg; codecs=\"mp3\"'\n\t\t\t\t\t\t\tPlays: 'audio/mpeg'\n\t\t\t\t\t\t\tPlays: 'audio/wav; codecs=\"1\"'\n\n\t\t\t\t\t\tTo workaround this we remove all parameters from the MIME-type in\n\t\t\t\t\t\tOpera.\n\t\t\t\t\t*/\n\t\t\t\t\tif (Browser.isOpera) {\n\t\t\t\t\t\tsrcObj.type =  srcObj.type.replace(/;.*$/, '');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst source = document.createElement('source');\n\t\t\t\t\tsource.src  = srcObj.src;\n\t\t\t\t\tsource.type = srcObj.type;\n\t\t\t\t\taudio.appendChild(source);\n\t\t\t\t\tusedSources.push(srcObj);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (audio.hasChildNodes()) {\n\t\t\t\t// Set the `preload` attribute to `'metadata'`, unless preloading has been disabled.\n\t\t\t\tif (Config.audio.preloadMetadata) {\n\t\t\t\t\taudio.preload = 'metadata';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._finalize(audio, usedSources, clone(sourceList));\n\t\t}\n\n\t\t_copy(obj) {\n\t\t\tthis._finalize(\n\t\t\t\tobj.audio.cloneNode(true), // deep clone of the audio element & its children\n\t\t\t\tclone(obj.sources),\n\t\t\t\tclone(obj.originals)\n\t\t\t);\n\t\t}\n\n\t\t_finalize(audio, sources, originals) {\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\taudio : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : audio\n\t\t\t\t},\n\n\t\t\t\tsources : {\n\t\t\t\t\tvalue : Object.freeze(sources)\n\t\t\t\t},\n\n\t\t\t\toriginals : {\n\t\t\t\t\tvalue : Object.freeze(originals)\n\t\t\t\t},\n\n\t\t\t\t_error : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_faderId : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_mute : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_rate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_volume : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Set up event handlers on the audio and source elements.\n\t\t\tjQuery(this.audio)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving a `loadstart` event on the audio element, set `_error` to\n\t\t\t\t\t`false`.\n\t\t\t\t*/\n\t\t\t\t.on('loadstart.AudioTrack', () => this._error = false)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving an `error` event on the audio element, set `_error` to\n\t\t\t\t\t`true`.\n\n\t\t\t\t\tCaveats by browser:\n\t\t\t\t\t\tEdge violates the specification by triggering `error` events from source\n\t\t\t\t\t\telements on their parent media element, rather than the source element.\n\t\t\t\t\t\tTo enable error handling in all browsers, we set the error handler on the\n\t\t\t\t\t\taudio element and have the final source element forward its `error` event.\n\n\t\t\t\t\t\tIE does not trigger, at least some, `error` events from source elements at\n\t\t\t\t\t\tall, not on the source element or its parent media element.  AFAIK, nothing\n\t\t\t\t\t\tcan be done about this lossage.\n\t\t\t\t*/\n\t\t\t\t.on('error.AudioTrack', () => this._error = true)\n\t\t\t\t/*\n\t\t\t\t\tUpon receiving an `error` event on the final source element (if any), trigger\n\t\t\t\t\tan `error` event on the audio element—that being necessary because the source\n\t\t\t\t\t`error` event does not bubble.\n\t\t\t\t*/\n\t\t\t\t.find('source:last-of-type')\n\t\t\t\t.on('error.AudioTrack', () => this._trigger('error'));\n\n\t\t\t// Subscribe to command messages.\n\t\t\tsubscribe(this, mesg => {\n\t\t\t\tif (!this.audio) {\n\t\t\t\t\tunsubscribe(this);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch (mesg) {\n\t\t\t\tcase 'loadwithscreen':\n\t\t\t\t\tif (this.hasSource()) {\n\t\t\t\t\t\tconst lockId = LoadScreen.lock();\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t// NOTE: Do not use an arrow function here.\n\t\t\t\t\t\t\t.one(\n\t\t\t\t\t\t\t\t'canplaythrough.AudioTrack_loadwithscreen error.AudioTrack_loadwithscreen',\n\t\t\t\t\t\t\t\tfunction () {\n\t\t\t\t\t\t\t\t\tjQuery(this).off('.AudioTrack_loadwithscreen');\n\t\t\t\t\t\t\t\t\tLoadScreen.unlock(lockId);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.load();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'load':   this.load();               break;\n\t\t\t\tcase 'mute':   this._updateAudioMute();   break;\n\t\t\t\tcase 'rate':   this._updateAudioRate();   break;\n\t\t\t\tcase 'stop':   this.stop();               break;\n\t\t\t\tcase 'volume': this._updateAudioVolume(); break;\n\t\t\t\tcase 'unload': this.unload();             break;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Synchronize with the current master audio settings.\n\t\t\tthis._updateAudioMute();\n\t\t\tthis._updateAudioRate();\n\t\t\tthis._updateAudioVolume();\n\t\t}\n\n\t\t_trigger(eventName) {\n\t\t\t// Do not use `trigger()` here as we do not want these events to bubble.\n\t\t\tjQuery(this.audio).triggerHandler(eventName);\n\t\t}\n\n\t\t_destroy() {\n\t\t\t/*\n\t\t\t\tStrictly speaking, self-destruction is not necessary as this object will,\n\t\t\t\teventually, be garbage collected.  That said, since the audio element contains\n\t\t\t\tdata buffers for the selected audio source, which may be quite large, manually\n\t\t\t\tpurging them as soon as we know that they're no longer needed is not a bad idea.\n\t\t\t*/\n\t\t\tunsubscribe(this);\n\n\t\t\tif (!this.audio) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tjQuery(this.audio).off();\n\t\t\tthis.unload();\n\t\t\tthis._error = true;\n\n\t\t\t// Delete the audio element property.\n\t\t\tdelete this.audio;\n\t\t}\n\n\t\tclone() {\n\t\t\treturn new AudioTrack(this);\n\t\t}\n\n\t\tload() {\n\t\t\tthis.fadeStop();\n\t\t\tthis.audio.pause();\n\n\t\t\tif (!this.audio.hasChildNodes()) {\n\t\t\t\tif (this.sources.length === 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.sources.forEach(srcObj => {\n\t\t\t\t\tconst source = document.createElement('source');\n\t\t\t\t\tsource.src  = srcObj.src;\n\t\t\t\t\tsource.type = srcObj.type;\n\t\t\t\t\tthis.audio.appendChild(source);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (this.audio.preload !== 'auto') {\n\t\t\t\tthis.audio.preload = 'auto';\n\t\t\t}\n\n\t\t\tif (!this.isLoading()) {\n\t\t\t\tthis.audio.load();\n\t\t\t}\n\t\t}\n\n\t\tunload() {\n\t\t\tthis.fadeStop();\n\t\t\tthis.stop();\n\n\t\t\tconst audio = this.audio;\n\t\t\taudio.preload = 'none';\n\n\t\t\t// Remove all source elements.\n\t\t\twhile (audio.hasChildNodes()) {\n\t\t\t\taudio.removeChild(audio.firstChild);\n\t\t\t}\n\n\t\t\t// Force the audio element to drop any existing data buffers.\n\t\t\taudio.load();\n\t\t}\n\n\t\tplay() {\n\t\t\tif (!this.hasSource()) {\n\t\t\t\treturn Promise.reject(new Error('none of the candidate sources were acceptable'));\n\t\t\t}\n\n\t\t\tif (this.isUnloaded()) {\n\t\t\t\treturn Promise.reject(new Error('no sources are loaded'));\n\t\t\t}\n\n\t\t\tif (this.isFailed()) {\n\t\t\t\treturn Promise.reject(new Error('failed to load any of the sources'));\n\t\t\t}\n\n\t\t\tif (this.audio.preload !== 'auto') {\n\t\t\t\tthis.audio.preload = 'auto';\n\t\t\t}\n\n\t\t\tconst namespace = '.AudioTrack_play';\n\n\t\t\treturn _playReturnsPromise()\n\t\t\t\t? this.audio.play()\n\t\t\t\t: new Promise((resolve, reject) => {\n\t\t\t\t\tif (this.isPlaying()) {\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tjQuery(this.audio)\n\t\t\t\t\t\t\t.off(namespace)\n\t\t\t\t\t\t\t.one(`error${namespace} playing${namespace} timeupdate${namespace}`, ev => {\n\t\t\t\t\t\t\t\tjQuery(this).off(namespace);\n\n\t\t\t\t\t\t\t\tif (ev.type === 'error') {\n\t\t\t\t\t\t\t\t\treject(new Error('unknown audio play error'));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.audio.play();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tthis.play().catch(() => {\n\t\t\t\tconst gestures = _gestureEventNames.map(name => `${name}.AudioTrack_playWhenAllowed`).join(' ');\n\t\t\t\tjQuery(document).one(gestures, () => {\n\t\t\t\t\tjQuery(document).off('.AudioTrack_playWhenAllowed');\n\t\t\t\t\tthis.audio.play();\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tpause() {\n\t\t\tthis.audio.pause();\n\t\t}\n\n\t\tstop() {\n\t\t\tthis.audio.pause();\n\t\t\tthis.time(0);\n\t\t\tthis._trigger(':stopped');\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (typeof duration !== 'number') {\n\t\t\t\tthrow new TypeError('duration parameter must be a number');\n\t\t\t}\n\t\t\tif (typeof toVol !== 'number') {\n\t\t\t\tthrow new TypeError('toVolume parameter must be a number');\n\t\t\t}\n\t\t\tif (fromVol != null && typeof fromVol !== 'number') { // lazy equality for null\n\t\t\t\tthrow new TypeError('fromVolume parameter must be a number');\n\t\t\t}\n\n\t\t\tif (!this.hasSource()) {\n\t\t\t\treturn Promise.reject(new Error('none of the candidate sources were acceptable'));\n\t\t\t}\n\n\t\t\tif (this.isUnloaded()) {\n\t\t\t\treturn Promise.reject(new Error('no sources are loaded'));\n\t\t\t}\n\n\t\t\tif (this.isFailed()) {\n\t\t\t\treturn Promise.reject(new Error('failed to load any of the sources'));\n\t\t\t}\n\n\t\t\tthis.fadeStop();\n\n\t\t\tconst from = Math.clamp(fromVol == null ? this.volume() : fromVol, 0, 1); // lazy equality for null\n\t\t\tconst to   = Math.clamp(toVol, 0, 1);\n\n\t\t\tif (from === to) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.volume(from);\n\n\t\t\t/*\n\t\t\t\tWe listen for the `timeupdate` event here, rather than `playing`, because\n\t\t\t\tvarious browsers (notably, mobile browsers) are poor at firing media events\n\t\t\t\tin a timely fashion, so we use `timeupdate` to ensure that we don't start\n\t\t\t\tthe fade until the track is actually progressing.\n\t\t\t*/\n\t\t\tjQuery(this.audio)\n\t\t\t\t.off('timeupdate.AudioTrack_fade')\n\t\t\t\t.one('timeupdate.AudioTrack_fade', () => {\n\t\t\t\t\tlet min;\n\t\t\t\t\tlet max;\n\n\t\t\t\t\t// Fade in.\n\t\t\t\t\tif (from < to) {\n\t\t\t\t\t\tmin = from;\n\t\t\t\t\t\tmax = to;\n\t\t\t\t\t}\n\t\t\t\t\t// Fade out.\n\t\t\t\t\telse {\n\t\t\t\t\t\tmin = to;\n\t\t\t\t\t\tmax = from;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst time     = Math.max(duration, 1);\n\t\t\t\t\tconst interval = 25; // in milliseconds\n\t\t\t\t\tconst delta    = (to - from) / (time / (interval / 1000));\n\n\t\t\t\t\tthis._trigger(':fading');\n\t\t\t\t\tthis._faderId = setInterval(() => {\n\t\t\t\t\t\tif (!this.isPlaying()) {\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tWhile it may seem like a good idea to also set the track volume\n\t\t\t\t\t\t\t\tto the `to` value here, we should not do so.  We cannot know why\n\t\t\t\t\t\t\t\tthe track is no longer playing, nor if the volume has been modified\n\t\t\t\t\t\t\t\tin the interim, so doing so now may clobber an end-user set volume.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tthis.fadeStop();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthis.volume(Math.clamp(this.volume() + delta, min, max));\n\n\t\t\t\t\t\tif (Config.audio.pauseOnFadeToZero && this.volume() === 0) {\n\t\t\t\t\t\t\tthis.pause();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.volume() === to) {\n\t\t\t\t\t\t\tthis.fadeStop();\n\t\t\t\t\t\t\tthis._trigger(':faded');\n\t\t\t\t\t\t}\n\t\t\t\t\t}, interval);\n\t\t\t\t});\n\n\t\t\treturn this.play();\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\treturn this.fade(duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\treturn this.fade(duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tif (this._faderId !== null) {\n\t\t\t\tclearInterval(this._faderId);\n\t\t\t\tthis._faderId = null;\n\t\t\t}\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\treturn this.audio.loop;\n\t\t\t}\n\n\t\t\tthis.audio.loop = !!loop;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\treturn this._mute;\n\t\t\t}\n\n\t\t\tthis._mute = !!mute;\n\t\t\tthis._updateAudioMute();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioMute() {\n\t\t\tthis.audio.muted = this._mute || _masterMute;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\treturn this._rate;\n\t\t\t}\n\n\t\t\tif (typeof rate !== 'number') {\n\t\t\t\tthrow new TypeError('rate parameter must be a number');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tClamp the playback rate to sane values—some browsers also do this to varying degrees.\n\n\t\t\t\tNOTE (ca. Aug 2016): The specification allows negative values for reverse playback,\n\t\t\t\thowever, most browsers either completely ignore negative values or clamp them to\n\t\t\t\tsome positive value.  In some (notably, IE & Edge), setting a negative playback\n\t\t\t\trate breaks the associated controls, if displayed.\n\t\t\t*/\n\t\t\t/*\n\t\t\tthis._rate = rate < 0\n\t\t\t\t? Math.clamp(rate, -0.2, -5) // clamp to 5× slower & faster, backward\n\t\t\t\t: Math.clamp(rate, 0.2, 5);  // clamp to 5× slower & faster, forward\n\t\t\t*/\n\t\t\tthis._rate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\t\t\tthis._updateAudioRate();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioRate() {\n\t\t\t/*\n\t\t\tconst rate = this._rate * _masterRate;\n\t\t\tthis.audio.playbackRate = rate < 0\n\t\t\t\t? Math.clamp(rate, -0.2, -5) // clamp to 5× slower & faster, backward\n\t\t\t\t: Math.clamp(rate, 0.2, 5);  // clamp to 5× slower & faster, forward\n\t\t\t*/\n\t\t\tthis.audio.playbackRate = Math.clamp(this._rate * _masterRate, 0.2, 5); // clamp to 5× slower & faster\n\t\t}\n\n\t\ttime(time) {\n\t\t\tif (time == null) { // lazy equality for null\n\t\t\t\treturn this.audio.currentTime;\n\t\t\t}\n\n\t\t\tif (typeof time !== 'number') {\n\t\t\t\tthrow new TypeError('time parameter must be a number');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tNOTE (historic): If we try to modify the audio clip's `.currentTime` property\n\t\t\t\tbefore its metadata has been loaded, it will throw an `InvalidStateError`\n\t\t\t\t(since it doesn't know its duration, allowing `.currentTime` to be set would\n\t\t\t\tbe undefined behavior), so in case an exception is thrown we provide a fallback\n\t\t\t\tusing the `loadedmetadata` event.\n\n\t\t\t\tNOTE (ca. 2016): This workaround should no longer be necessary in most browsers.\n\t\t\t\tThat said, it will still be required for some time to service legacy browsers.\n\n\t\t\t\tNOTE (ca. Dec 09, 2018): Firefox will still log an `InvalidStateError` to the\n\t\t\t\tconsole when attempting to modify the clip's `.currentTime` property before its\n\t\t\t\tmetadata has been loaded, even though it handles the situation properly—by waiting\n\t\t\t\tfor the metadata, as all browsers do now.  To prevent this spurious logging, we\n\t\t\t\tmust now manually check for the existence of the metadata and always failover to\n\t\t\t\tan event regardless of if the browser needs it or not—because I don't want to\n\t\t\t\tintroduce a browser check here.  Stay classy, Firefox.\n\t\t\t*/\n\t\t\tif (this.hasMetadata()) {\n\t\t\t\tthis.audio.currentTime = time;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery(this.audio)\n\t\t\t\t\t.off('loadedmetadata.AudioTrack_time')\n\t\t\t\t\t.one('loadedmetadata.AudioTrack_time', () => this.audio.currentTime = time);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\treturn this._volume;\n\t\t\t}\n\n\t\t\tif (typeof volume !== 'number') {\n\t\t\t\tthrow new TypeError('volume parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._volume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\t\t\tthis._updateAudioVolume();\n\n\t\t\treturn this;\n\t\t}\n\t\t_updateAudioVolume() {\n\t\t\tthis.audio.volume = Math.clamp(this._volume * _masterVolume, 0, 1);\n\t\t}\n\n\t\tduration() {\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.audio.duration;\n\t\t}\n\n\t\tremaining() {\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.audio.duration - this.audio.currentTime;\n\t\t}\n\n\t\tisFailed() {\n\t\t\treturn this._error;\n\t\t}\n\n\t\tisLoading() {\n\t\t\treturn this.audio.networkState === HTMLMediaElement.NETWORK_LOADING;\n\t\t}\n\n\t\tisUnloaded() {\n\t\t\treturn !this.audio.hasChildNodes();\n\t\t}\n\n\t\tisUnavailable() {\n\t\t\treturn !this.hasSource() || this.isUnloaded() || this.isFailed();\n\t\t}\n\n\t\tisPlaying() {\n\t\t\t// NOTE: The `this.hasSomeData()` check is probably no longer necessary.\n\t\t\treturn !this.audio.paused && this.hasSomeData();\n\t\t}\n\n\t\tisPaused() {\n\t\t\t/*\n\t\t\t\tIf the selected audio resource is a stream, `currentTime` may return a non-zero\n\t\t\t\tvalue even at the earliest available position within the stream as the browser\n\t\t\t\tmay have dropped the earliest chunks of buffered data or the stream may have a\n\t\t\t\ttimeline which does not start at zero.\n\n\t\t\t\tIn an attempt to guard against these possiblities, as best as we can, we test\n\t\t\t\t`duration` against `Infinity` first, which should yield true for actual streams.\n\t\t\t*/\n\t\t\treturn this.audio.paused\n\t\t\t\t&& (this.audio.duration === Infinity || this.audio.currentTime > 0)\n\t\t\t\t&& !this.audio.ended;\n\t\t}\n\n\t\tisStopped() {\n\t\t\treturn this.audio.paused && this.audio.currentTime === 0;\n\t\t}\n\n\t\tisEnded() {\n\t\t\treturn this.audio.ended;\n\t\t}\n\n\t\tisFading() {\n\t\t\treturn this._faderId !== null;\n\t\t}\n\n\t\tisSeeking() {\n\t\t\treturn this.audio.seeking;\n\t\t}\n\n\t\thasSource() {\n\t\t\treturn this.sources.length > 0;\n\t\t}\n\n\t\thasNoData() {\n\t\t\treturn this.audio.readyState === HTMLMediaElement.HAVE_NOTHING;\n\t\t}\n\n\t\thasMetadata() {\n\t\t\treturn this.audio.readyState >= HTMLMediaElement.HAVE_METADATA;\n\t\t}\n\n\t\thasSomeData() {\n\t\t\treturn this.audio.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA;\n\t\t}\n\n\t\thasData() {\n\t\t\treturn this.audio.readyState === HTMLMediaElement.HAVE_ENOUGH_DATA;\n\t\t}\n\n\t\ton(...args) {\n\t\t\tjQuery.fn.on.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\tone(...args) {\n\t\t\tjQuery.fn.one.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\toff(...args) {\n\t\t\tjQuery.fn.off.apply(jQuery(this.audio), args);\n\t\t\treturn this;\n\t\t}\n\n\t\t/*\n\t\t\tVerifies that the browser supports the given MIME-type and then retuns either\n\t\t\tthe MIME-type, if it is supported, or `null`, if it is not.\n\t\t*/\n\t\tstatic _verifyType(type) {\n\t\t\tif (!type || !Has.audio) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst cache = AudioTrack._types;\n\n\t\t\tif (!cache.hasOwnProperty(type)) {\n\t\t\t\tconst audio = document.createElement('audio');\n\n\t\t\t\t// Some early implementations return 'no' instead of the empty string.\n\t\t\t\tcache[type] = audio.canPlayType(type).replace(/^no$/i, '') !== '';\n\t\t\t}\n\n\t\t\treturn cache[type] ? type : null;\n\t\t}\n\n\t\t/*\n\t\t\tRetuns the MIME-type associated with the given format-ID, if it is supported,\n\t\t\telsewise `null`.\n\t\t*/\n\t\tstatic getType(format) {\n\t\t\tif (!format || !Has.audio) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst known = AudioTrack.formats;\n\t\t\tconst id    = format.toLowerCase();\n\t\t\tconst type  = known.hasOwnProperty(id) ? known[id] : `audio/${id}`;\n\n\t\t\treturn AudioTrack._verifyType(type);\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the browser potentially supports a format.\n\t\t*/\n\t\tstatic canPlayFormat(format) {\n\t\t\treturn AudioTrack.getType(format) !== null;\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the browser potentially supports a MIME-type.\n\t\t*/\n\t\tstatic canPlayType(type) {\n\t\t\treturn AudioTrack._verifyType(type) !== null;\n\t\t}\n\t}\n\n\t// Attach the static data members.\n\tObject.defineProperties(AudioTrack, {\n\t\t/*\n\t\t\tFormat-ID to MIME-type mappings for common audio types.\n\n\t\t\tIn most cases, the codecs property should not be included with the MIME-type,\n\t\t\tas we have no way of knowing which codec was used—and the browser will figure\n\t\t\tit out.  Conversely, in cases where the relationship relationship between a\n\t\t\tformat-ID and a specific codec is strong, we should include the codecs property.\n\n\t\t\tNOTE: Caveats by browser/engine:\n\t\t\t\tOpera ≤12 (Presto) will return a false-negative if the codecs value is quoted\n\t\t\t\twith single quotes, requiring the use of either double quotes or no quotes.\n\n\t\t\t\tBlink-based browsers (e.g. Chrome, Opera ≥15) will return a false-negative\n\t\t\t\tfor WAVE audio if the preferred MIME-type of 'audio/wave' is specified,\n\t\t\t\trequiring the use of 'audio/wav' instead.\n\t\t*/\n\t\tformats : {\n\t\t\tvalue : { // Leave this object extensible for users.\n\t\t\t\t// AAC — MPEG-2 AAC audio; specific profiles vary, but commonly \"AAC-LC\".\n\t\t\t\taac : 'audio/aac',\n\n\t\t\t\t// CAF — Codecs vary.\n\t\t\t\tcaf     : 'audio/x-caf',\n\t\t\t\t'x-caf' : 'audio/x-caf',\n\n\t\t\t\t// MP3 — MPEG-1/-2 Layer-III audio.\n\t\t\t\tmp3  : 'audio/mpeg; codecs=\"mp3\"',\n\t\t\t\tmpeg : 'audio/mpeg; codecs=\"mp3\"',\n\n\t\t\t\t// MP4 — Codecs vary, but commonly \"mp4a.40.2\" (a.k.a. \"AAC-LC\").\n\t\t\t\tm4a     : 'audio/mp4',\n\t\t\t\tmp4     : 'audio/mp4',\n\t\t\t\t'x-m4a' : 'audio/mp4',\n\t\t\t\t'x-mp4' : 'audio/mp4',\n\n\t\t\t\t// OGG — Codecs vary, but commonly \"vorbis\" and, recently, \"opus\".\n\t\t\t\toga : 'audio/ogg',\n\t\t\t\togg : 'audio/ogg',\n\n\t\t\t\t// OPUS — Opus audio in an Ogg container.\n\t\t\t\topus : 'audio/ogg; codecs=\"opus\"',\n\n\t\t\t\t// WAVE — Codecs vary, but commonly \"1\" (1 is the FourCC for PCM/LPCM).\n\t\t\t\twav  : 'audio/wav',\n\t\t\t\twave : 'audio/wav',\n\n\t\t\t\t// WEBM — Codecs vary, but commonly \"vorbis\" and, recently, \"opus\".\n\t\t\t\tweba : 'audio/webm',\n\t\t\t\twebm : 'audio/webm'\n\t\t\t}\n\t\t},\n\n\t\t/*\n\t\t\tCache of supported MIME-types.\n\t\t*/\n\t\t_types : {\n\t\t\tvalue : {}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAudioList Class.\n\t*******************************************************************************************************************/\n\tclass AudioList {\n\t\tconstructor(obj) {\n\t\t\t// Process the given array of track objects or AudioList object.\n\t\t\tif (obj instanceof Array) {\n\t\t\t\tthis._create(obj);\n\t\t\t}\n\t\t\telse if (obj instanceof AudioList) {\n\t\t\t\tthis._copy(obj);\n\t\t\t\t// this._create(obj.tracks);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('tracks parameter must be either an array, of track objects, or an AudioTrack instance');\n\t\t\t}\n\t\t}\n\n\t\t_create(trackList) {\n\t\t\t// Map the array of tracks to playlist track objects.\n\t\t\tthis._finalize(trackList.map(trackObj => {\n\t\t\t\tif (typeof trackObj !== 'object') { // lazy equality for null\n\t\t\t\t\tthrow new Error('tracks parameter array members must be objects');\n\t\t\t\t}\n\n\t\t\t\tlet own;\n\t\t\t\tlet rate;\n\t\t\t\tlet track;\n\t\t\t\tlet volume;\n\n\t\t\t\tif (trackObj instanceof AudioTrack) {\n\t\t\t\t\town    = true;\n\t\t\t\t\trate   = trackObj.rate();\n\t\t\t\t\ttrack  = trackObj.clone();\n\t\t\t\t\tvolume = trackObj.volume();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (!trackObj.hasOwnProperty('track')) {\n\t\t\t\t\t\tthrow new Error('track object missing required \"track\" property');\n\t\t\t\t\t}\n\t\t\t\t\telse if (!(trackObj.track instanceof AudioTrack)) {\n\t\t\t\t\t\tthrow new Error('track object\\'s \"track\" property must be an AudioTrack object');\n\t\t\t\t\t}\n\t\t\t\t\t// else if (!trackObj.hasOwnProperty('volume')) {\n\t\t\t\t\t// \tthrow new Error('track object missing required \"volume\" property');\n\t\t\t\t\t// }\n\n\t\t\t\t\town    = trackObj.hasOwnProperty('own') && trackObj.own;\n\t\t\t\t\trate   = trackObj.hasOwnProperty('rate') ? trackObj.rate : trackObj.track.rate();\n\t\t\t\t\ttrack  = trackObj.track;\n\t\t\t\t\tvolume = trackObj.hasOwnProperty('volume') ? trackObj.volume : trackObj.track.volume();\n\t\t\t\t}\n\n\t\t\t\ttrack.stop();\n\t\t\t\ttrack.loop(false);\n\t\t\t\ttrack.mute(false);\n\t\t\t\ttrack.rate(rate);\n\t\t\t\ttrack.volume(volume);\n\t\t\t\ttrack.on('ended.AudioList', () => this._onEnd());\n\n\t\t\t\treturn { own, track, volume, rate };\n\t\t\t}));\n\t\t}\n\n\t\t_copy(obj) {\n\t\t\tthis._finalize(clone(obj.tracks));\n\t\t}\n\n\t\t_finalize(tracks) {\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\ttracks : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : Object.freeze(tracks)\n\t\t\t\t},\n\n\t\t\t\tqueue : {\n\t\t\t\t\tconfigurable : true,\n\t\t\t\t\tvalue        : []\n\t\t\t\t},\n\n\t\t\t\tcurrent : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_rate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_volume : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 1\n\t\t\t\t},\n\n\t\t\t\t_mute : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_loop : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t},\n\n\t\t\t\t_shuffle : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : false\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t_destroy() {\n\t\t\t/*\n\t\t\t\tStrictly speaking, self-destruction is not necessary as this object will,\n\t\t\t\teventually, be garbage collected.\n\t\t\t*/\n\t\t\t// Stop playback.\n\t\t\tthis.stop();\n\n\t\t\t// Destroy all owned tracks.\n\t\t\tthis.tracks\n\t\t\t\t.filter(trackObj => trackObj.own)\n\t\t\t\t.forEach(trackObj => trackObj.track._destroy());\n\n\t\t\t// Delete the reference-type properties.\n\t\t\tdelete this.tracks;\n\t\t\tdelete this.queue;\n\t\t}\n\n\t\tload() {\n\t\t\tthis.tracks.forEach(trackObj => trackObj.track.load());\n\t\t}\n\n\t\tunload() {\n\t\t\tthis.stop();\n\t\t\tthis.tracks.forEach(trackObj => trackObj.track.unload());\n\t\t}\n\n\t\tplay() {\n\t\t\tif (this.current === null || this.current.track.isUnavailable() || this.current.track.isEnded()) {\n\t\t\t\tif (this.queue.length === 0) {\n\t\t\t\t\tthis._fillQueue();\n\t\t\t\t}\n\n\t\t\t\tif (!this._next()) {\n\t\t\t\t\treturn Promise.reject(new Error('no tracks were available'));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.current.track.play();\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tthis.play().catch(() => {\n\t\t\t\tconst gestures = _gestureEventNames.map(name => `${name}.AudioList_playWhenAllowed`).join(' ');\n\t\t\t\tjQuery(document).one(gestures, () => {\n\t\t\t\t\tjQuery(document).off('.AudioList_playWhenAllowed');\n\t\t\t\t\tthis.play();\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tpause() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.pause();\n\t\t\t}\n\t\t}\n\n\t\tstop() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.stop();\n\t\t\t\tthis.current = null;\n\t\t\t}\n\n\t\t\tthis._drainQueue();\n\t\t}\n\n\t\tskip() {\n\t\t\tif (this._next()) {\n\t\t\t\tthis.current.track.play();\n\t\t\t}\n\t\t\telse if (this._loop) {\n\t\t\t\tthis.play();\n\t\t\t}\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (typeof duration !== 'number') {\n\t\t\t\tthrow new TypeError('duration parameter must be a number');\n\t\t\t}\n\t\t\tif (typeof toVol !== 'number') {\n\t\t\t\tthrow new TypeError('toVolume parameter must be a number');\n\t\t\t}\n\t\t\tif (fromVol != null && typeof fromVol !== 'number') { // lazy equality for null\n\t\t\t\tthrow new TypeError('fromVolume parameter must be a number');\n\t\t\t}\n\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\tthis._fillQueue();\n\t\t\t}\n\n\t\t\tif (this.current === null || this.current.track.isUnavailable() || this.current.track.isEnded()) {\n\t\t\t\tif (!this._next()) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst adjToVol = Math.clamp(toVol, 0, 1) * this.current.volume;\n\t\t\tlet adjFromVol;\n\n\t\t\tif (fromVol != null) { // lazy equality for null\n\t\t\t\tadjFromVol = Math.clamp(fromVol, 0, 1) * this.current.volume;\n\t\t\t}\n\n\t\t\tthis._volume = toVol; // NOTE: Kludgey, but necessary.\n\n\t\t\treturn this.current.track.fade(duration, adjToVol, adjFromVol);\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\treturn this.fade(duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\treturn this.fade(duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.fadeStop();\n\t\t\t}\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\treturn this._loop;\n\t\t\t}\n\n\t\t\tthis._loop = !!loop;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\treturn this._mute;\n\t\t\t}\n\n\t\t\tthis._mute = !!mute;\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.mute(this._mute);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\treturn this._rate;\n\t\t\t}\n\n\t\t\tif (typeof rate !== 'number') {\n\t\t\t\tthrow new TypeError('rate parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._rate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.rate(this._rate * this.current.rate);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tshuffle(shuffle) {\n\t\t\tif (shuffle == null) { // lazy equality for null\n\t\t\t\treturn this._shuffle;\n\t\t\t}\n\n\t\t\tthis._shuffle = !!shuffle;\n\n\t\t\tif (this.queue.length > 0) {\n\t\t\t\tthis._fillQueue();\n\n\t\t\t\t// Try not to immediately replay the last track when not shuffling.\n\t\t\t\tif (!this._shuffle && this.current !== null && this.queue.length > 1) {\n\t\t\t\t\tconst firstIdx = this.queue.findIndex(trackObj => trackObj === this.current);\n\n\t\t\t\t\tif (firstIdx !== -1) {\n\t\t\t\t\t\tthis.queue.push(...this.queue.splice(0, firstIdx + 1));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\treturn this._volume;\n\t\t\t}\n\n\t\t\tif (typeof volume !== 'number') {\n\t\t\t\tthrow new TypeError('volume parameter must be a number');\n\t\t\t}\n\n\t\t\tthis._volume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.volume(this._volume * this.current.volume);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tduration() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('duration takes no parameters');\n\t\t\t}\n\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\treturn this.tracks\n\t\t\t\t.map(trackObj => trackObj.track.duration())\n\t\t\t\t.reduce((prev, cur) => prev + cur, 0);\n\t\t}\n\n\t\tremaining() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('remaining takes no parameters');\n\t\t\t}\n\n\t\t\t// NOTE: May return a double (normally), Infinity (for streams), or NaN (without metadata).\n\t\t\tlet remainingTime = this.queue\n\t\t\t\t.map(trackObj => trackObj.track.duration())\n\t\t\t\t.reduce((prev, cur) => prev + cur, 0);\n\n\t\t\tif (this.current !== null) {\n\t\t\t\tremainingTime += this.current.track.remaining();\n\t\t\t}\n\n\t\t\treturn remainingTime;\n\t\t}\n\n\t\ttime() {\n\t\t\tif (arguments.length > 0) {\n\t\t\t\tthrow new Error('time takes no parameters');\n\t\t\t}\n\n\t\t\treturn this.duration() - this.remaining();\n\t\t}\n\n\t\tisPlaying() {\n\t\t\treturn this.current !== null && this.current.track.isPlaying();\n\t\t}\n\n\t\tisPaused() {\n\t\t\treturn this.current === null || this.current.track.isPaused();\n\t\t}\n\n\t\tisStopped() {\n\t\t\treturn this.queue.length === 0 && this.current === null;\n\t\t}\n\n\t\tisEnded() {\n\t\t\treturn this.queue.length === 0 && (this.current === null || this.current.track.isEnded());\n\t\t}\n\n\t\tisFading() {\n\t\t\treturn this.current !== null && this.current.track.isFading();\n\t\t}\n\n\t\t_next() {\n\t\t\tif (this.current !== null) {\n\t\t\t\tthis.current.track.stop();\n\t\t\t\tthis.current = null;\n\t\t\t}\n\n\t\t\tlet nextTrack;\n\n\t\t\twhile ((nextTrack = this.queue.shift())) {\n\t\t\t\tif (!nextTrack.track.isUnavailable()) {\n\t\t\t\t\tthis.current = nextTrack;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.current === null) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis.current.track.mute(this._mute);\n\t\t\tthis.current.track.rate(this._rate * this.current.rate);\n\t\t\tthis.current.track.volume(this._volume * this.current.volume);\n\n\t\t\t// Attempt to protect against the `loop` state being reenabled\n\t\t\t// outside of the playlist.  Mostly for unowned tracks.\n\t\t\t//\n\t\t\t// TODO: Should we reapply the `ended` event handler too?\n\t\t\tthis.current.track.loop(false);\n\n\t\t\treturn true;\n\t\t}\n\n\t\t_onEnd() {\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\tif (!this._loop) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._fillQueue();\n\t\t\t}\n\n\t\t\tif (!this._next()) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.current.track.play();\n\t\t}\n\n\t\t_drainQueue() {\n\t\t\tthis.queue.splice(0);\n\t\t}\n\n\t\t_fillQueue() {\n\t\t\tthis._drainQueue();\n\t\t\tthis.queue.push(...this.tracks.filter(trackObj => !trackObj.track.isUnavailable()));\n\n\t\t\tif (this.queue.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (this._shuffle) {\n\t\t\t\tthis.queue.shuffle();\n\n\t\t\t\t// Try not to immediately replay the last track when shuffling.\n\t\t\t\tif (this.queue.length > 1 && this.queue[0] === this.current) {\n\t\t\t\t\tthis.queue.push(this.queue.shift());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAudioRunner Class.\n\t*******************************************************************************************************************/\n\tclass AudioRunner {\n\t\tconstructor(list) {\n\t\t\tif (!(list instanceof Set || list instanceof AudioRunner)) {\n\t\t\t\tthrow new TypeError('list parameter must be a Set or a AudioRunner instance');\n\t\t\t}\n\n\t\t\t// Set up our own properties.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\ttrackIds : {\n\t\t\t\t\tvalue : new Set(list instanceof AudioRunner ? list.trackIds : list)\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tload() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.load);\n\t\t}\n\n\t\tunload() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.unload);\n\t\t}\n\n\t\tplay() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.play);\n\t\t}\n\n\t\tplayWhenAllowed() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.playWhenAllowed);\n\t\t}\n\n\t\tpause() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.pause);\n\t\t}\n\n\t\tstop() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.stop);\n\t\t}\n\n\t\tfade(duration, toVol, fromVol) {\n\t\t\tif (duration == null || toVol == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fade requires parameters');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fade, duration, toVol, fromVol);\n\t\t}\n\n\t\tfadeIn(duration, fromVol) {\n\t\t\tif (duration == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fadeIn requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeIn, duration, 1, fromVol);\n\t\t}\n\n\t\tfadeOut(duration, fromVol) {\n\t\t\tif (duration == null) { // lazy equality for null\n\t\t\t\tthrow new Error('fadeOut requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeOut, duration, 0, fromVol);\n\t\t}\n\n\t\tfadeStop() {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.fadeStop);\n\t\t}\n\n\t\tloop(loop) {\n\t\t\tif (loop == null) { // lazy equality for null\n\t\t\t\tthrow new Error('loop requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.loop, loop);\n\t\t\treturn this;\n\t\t}\n\n\t\tmute(mute) {\n\t\t\tif (mute == null) { // lazy equality for null\n\t\t\t\tthrow new Error('mute requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.mute, mute);\n\t\t\treturn this;\n\t\t}\n\n\t\trate(rate) {\n\t\t\tif (rate == null) { // lazy equality for null\n\t\t\t\tthrow new Error('rate requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.rate, rate);\n\t\t\treturn this;\n\t\t}\n\n\t\ttime(time) {\n\t\t\tif (time == null) { // lazy equality for null\n\t\t\t\tthrow new Error('time requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.time, time);\n\t\t\treturn this;\n\t\t}\n\n\t\tvolume(volume) {\n\t\t\tif (volume == null) { // lazy equality for null\n\t\t\t\tthrow new Error('volume requires a parameter');\n\t\t\t}\n\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.volume, volume);\n\t\t\treturn this;\n\t\t}\n\n\t\ton(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.on, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\tone(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.one, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\toff(...args) {\n\t\t\tAudioRunner._run(this.trackIds, AudioTrack.prototype.off, ...args);\n\t\t\treturn this;\n\t\t}\n\n\t\tstatic _run(ids, fn, ...args) {\n\t\t\tids.forEach(id => {\n\t\t\t\tconst track = _tracks.get(id);\n\n\t\t\t\tif (track) {\n\t\t\t\t\tfn.apply(track, args);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTrack Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.tracks.add(trackId, sources…);\n\n\t\tE.g.\n\t\t\tSimpleAudio.tracks.add(\n\t\t\t\t'over_the_top',\n\t\t\t\t'https://audiohost.tld/id/over_the_top.mp3',\n\t\t\t\t'https://audiohost.tld/id/over_the_top.ogg'\n\t\t\t);\n\t*/\n\tfunction trackAdd(/* trackId , sources… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('track ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('sources'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `track ID \"${id}\"`;\n\n\t\tif (_badIdRe.test(id)) {\n\t\t\tthrow new Error(`invalid ${what}: track IDs must not contain colons or whitespace`);\n\t\t}\n\n\t\tconst sources = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet track;\n\n\t\ttry {\n\t\t\ttrack = _newTrack(sources);\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during track initialization: ${ex.message}`);\n\t\t}\n\n\t\t// If in Test Mode and no supported sources were specified, throw an error.\n\t\tif (Config.debug && !track.hasSource()) {\n\t\t\tthrow new Error(`${what}: no supported audio sources found`);\n\t\t}\n\n\t\t// If a track by the given ID already exists, destroy it.\n\t\tif (_tracks.has(id)) {\n\t\t\t_tracks.get(id)._destroy();\n\t\t}\n\n\t\t// Add the track to the cache.\n\t\t_tracks.set(id, track);\n\t}\n\n\tfunction trackDelete(id) {\n\t\tif (_tracks.has(id)) {\n\t\t\t_tracks.get(id)._destroy();\n\t\t}\n\n\t\t// TODO: Should this also remove references to the track from groups and playlists?\n\n\t\treturn _tracks.delete(id);\n\t}\n\n\tfunction trackClear() {\n\t\t_tracks.forEach(track => track._destroy());\n\t\t_tracks.clear();\n\t}\n\n\tfunction trackHas(id) {\n\t\treturn _tracks.has(id);\n\t}\n\n\tfunction trackGet(id) {\n\t\treturn _tracks.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tGroup Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.groups.add(groupId, trackIds…);\n\n\t\tE.g.\n\t\t\tSimpleAudio.groups.add(':ui', 'beep', 'boop', 'boing');\n\t*/\n\tfunction groupAdd(/* groupId , trackIds… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('group ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('track IDs'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `group ID \"${id}\"`;\n\n\t\tif (id[0] !== ':' || _badIdRe.test(id.slice(1))) {\n\t\t\tthrow new Error(`invalid ${what}: group IDs must start with a colon and must not contain colons or whitespace`);\n\t\t}\n\n\t\tif (_specialIds.includes(id)) {\n\t\t\tthrow new Error(`cannot clobber special ${what}`);\n\t\t}\n\n\t\tconst trackIds = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet group;\n\n\t\ttry {\n\t\t\tgroup = new Set(trackIds.map(trackId => {\n\t\t\t\tif (!_tracks.has(trackId)) {\n\t\t\t\t\tthrow new Error(`track \"${trackId}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\treturn trackId;\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during group initialization: ${ex.message}`);\n\t\t}\n\n\t\t// Add the group to the cache.\n\t\t_groups.set(id, Object.freeze(Array.from(group)));\n\t}\n\n\tfunction groupDelete(id) {\n\t\treturn _groups.delete(id);\n\t}\n\n\tfunction groupClear() {\n\t\t_groups.clear();\n\t}\n\n\tfunction groupHas(id) {\n\t\treturn _groups.has(id);\n\t}\n\n\tfunction groupGet(id) {\n\t\treturn _groups.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPlaylist Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tSimpleAudio.lists.add(listId, sources…);\n\t\t\tWhere `sources` may be either a track ID or descriptor (object).\n\t\t\tTrack descriptors are either { id, [own], [rate], [volume] } or { sources, [rate], [volume] }.\n\n\t\tNOTE: Rate properties are currently unsupported due to poor browser support.\n\n\t\tE.g.\n\t\t\tSimpleAudio.lists.add(\n\t\t\t\t'bgm',\n\t\t\t\t'over_the_top',\n\t\t\t\t{\n\t\t\t\t\tid     : 'heavens_a_lie',\n\t\t\t\t\tvolume : 0.5,\n\t\t\t\t\town    : true\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tsources : [\n\t\t\t\t\t\t'https://audiohost.tld/id/swamped.mp3',\n\t\t\t\t\t\t'https://audiohost.tld/id/swamped.ogg'\n\t\t\t\t\t],\n\t\t\t\t\tvolume  : 0.75\n\t\t\t\t}\n\t\t\t);\n\t*/\n\tfunction listAdd(/* listId , sources… */) {\n\t\tif (arguments.length < 2) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('list ID'); }\n\t\t\tif (arguments.length < 2) { errors.push('track IDs'); }\n\t\t\tthrow new Error(`no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tconst id   = String(arguments[0]).trim();\n\t\tconst what = `list ID \"${id}\"`;\n\n\t\tif (_badIdRe.test(id)) {\n\t\t\treturn this.error(`invalid ${what}: list IDs must not contain colons or whitespace`);\n\t\t}\n\n\t\tconst descriptors = Array.isArray(arguments[1])\n\t\t\t? Array.from(arguments[1])\n\t\t\t: Array.from(arguments).slice(1);\n\t\tlet list;\n\n\t\ttry {\n\t\t\tlist = new AudioList(descriptors.map(desc => {\n\t\t\t\tif (desc === null) {\n\t\t\t\t\tthrow new Error('track descriptor must be a string or object (type: null)');\n\t\t\t\t}\n\n\t\t\t\tswitch (typeof desc) {\n\t\t\t\tcase 'string':\n\t\t\t\t\t// Simply a track ID, so convert it into an object.\n\t\t\t\t\tdesc = { id : desc }; // eslint-disable-line no-param-reassign\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\tif (!desc.hasOwnProperty('id') && !desc.hasOwnProperty('sources')) {\n\t\t\t\t\t\tthrow new Error('track descriptor must contain one of either an \"id\" or a \"sources\" property');\n\t\t\t\t\t}\n\t\t\t\t\telse if (desc.hasOwnProperty('id') && desc.hasOwnProperty('sources')) {\n\t\t\t\t\t\tthrow new Error('track descriptor must contain either an \"id\" or a \"sources\" property, not both');\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`track descriptor must be a string or object (type: ${typeof desc})`);\n\t\t\t\t}\n\n\t\t\t\tlet own;\n\t\t\t\t// let rate;\n\t\t\t\tlet track;\n\t\t\t\tlet volume;\n\n\t\t\t\tif (desc.hasOwnProperty('id')) {\n\t\t\t\t\tif (typeof desc.id !== 'string') {\n\t\t\t\t\t\tthrow new Error('\"id\" property must be a string');\n\t\t\t\t\t}\n\t\t\t\t\tif (!_tracks.has(desc.id)) {\n\t\t\t\t\t\tthrow new Error(`track \"${desc.id}\" does not exist`);\n\t\t\t\t\t}\n\n\t\t\t\t\ttrack = _tracks.get(desc.id);\n\t\t\t\t}\n\t\t\t\telse if (desc.hasOwnProperty('sources')) {\n\t\t\t\t\tif (!Array.isArray(desc.sources) || desc.sources.length === 0) {\n\t\t\t\t\t\tthrow new Error('\"sources\" property must be a non-empty array');\n\t\t\t\t\t}\n\t\t\t\t\tif (desc.hasOwnProperty('own')) {\n\t\t\t\t\t\tthrow new Error('\"own\" property is not allowed with the \"sources\" property');\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\ttrack = _newTrack(desc.sources);\n\t\t\t\t\t\town = true;\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`error during track initialization: ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// If in Test Mode and no supported sources were specified, return an error.\n\t\t\t\t\tif (Config.debug && !track.hasSource()) {\n\t\t\t\t\t\tthrow new Error('no supported audio sources found');\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (desc.hasOwnProperty('own')) {\n\t\t\t\t\tif (typeof desc.own !== 'boolean') {\n\t\t\t\t\t\tthrow new Error('\"own\" property must be a boolean');\n\t\t\t\t\t}\n\n\t\t\t\t\town = desc.own;\n\n\t\t\t\t\tif (own) {\n\t\t\t\t\t\ttrack = track.clone();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if (desc.hasOwnProperty('rate')) {\n\t\t\t\t// \tif (\n\t\t\t\t// \t\t   typeof desc.rate !== 'number'\n\t\t\t\t// \t\t|| Number.isNaN(desc.rate)\n\t\t\t\t// \t\t|| !Number.isFinite(desc.rate)\n\t\t\t\t// \t) {\n\t\t\t\t// \t\tthrow new Error('\"rate\" property must be a finite number');\n\t\t\t\t// \t}\n\t\t\t\t//\n\t\t\t\t// \trate = desc.rate;\n\t\t\t\t// }\n\n\t\t\t\tif (desc.hasOwnProperty('volume')) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t   typeof desc.volume !== 'number'\n\t\t\t\t\t\t|| Number.isNaN(desc.volume)\n\t\t\t\t\t\t|| !Number.isFinite(desc.volume)\n\t\t\t\t\t\t|| desc.volume < 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new Error('\"volume\" property must be a non-negative finite number');\n\t\t\t\t\t}\n\n\t\t\t\t\tvolume = desc.volume;\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\town    : own != null ? own : false, // lazy equality for null,\n\t\t\t\t\t// rate   : rate != null ? rate : track.rate(), // lazy equality for null,\n\t\t\t\t\ttrack,\n\t\t\t\t\tvolume : volume != null ? volume : track.volume() // lazy equality for null\n\t\t\t\t};\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`${what}: error during playlist initialization: ${ex.message}`);\n\t\t}\n\n\t\t// If a playlist by the given ID already exists, destroy it.\n\t\tif (_lists.has(id)) {\n\t\t\t_lists.get(id)._destroy();\n\t\t}\n\n\t\t// Add the playlist to the cache.\n\t\t_lists.set(id, list);\n\t}\n\n\tfunction listDelete(id) {\n\t\tif (_lists.has(id)) {\n\t\t\t_lists.get(id)._destroy();\n\t\t}\n\n\t\treturn _lists.delete(id);\n\t}\n\n\tfunction listClear() {\n\t\t_lists.forEach(list => list._destroy());\n\t\t_lists.clear();\n\t}\n\n\tfunction listHas(id) {\n\t\treturn _lists.has(id);\n\t}\n\n\tfunction listGet(id) {\n\t\treturn _lists.get(id) || null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tRunner Functions.\n\t*******************************************************************************************************************/\n\tconst _runnerParseSelector = (() => {\n\t\tconst notWsRe = /\\S/g;\n\t\tconst parenRe = /[()]/g;\n\n\t\tfunction processNegation(str, startPos) {\n\t\t\tlet match;\n\n\t\t\tnotWsRe.lastIndex = startPos;\n\t\t\tmatch = notWsRe.exec(str);\n\n\t\t\tif (match === null || match[0] !== '(') {\n\t\t\t\tthrow new Error('invalid \":not()\" syntax: missing parentheticals');\n\t\t\t}\n\n\t\t\tparenRe.lastIndex = notWsRe.lastIndex;\n\t\t\tconst start  = notWsRe.lastIndex;\n\t\t\tconst result = { str : '', nextMatch : -1 };\n\t\t\tlet depth = 1;\n\n\t\t\twhile ((match = parenRe.exec(str)) !== null) {\n\t\t\t\tif (match[0] === '(') {\n\t\t\t\t\t++depth;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t--depth;\n\t\t\t\t}\n\n\t\t\t\tif (depth < 1) {\n\t\t\t\t\tresult.nextMatch = parenRe.lastIndex;\n\t\t\t\t\tresult.str = str.slice(start, result.nextMatch - 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tfunction parseSelector(idArg) {\n\t\t\tconst ids  = [];\n\t\t\tconst idRe = /:?[^\\s:()]+/g;\n\t\t\tlet match;\n\n\t\t\twhile ((match = idRe.exec(idArg)) !== null) {\n\t\t\t\tconst id = match[0];\n\n\t\t\t\t// Group negation.\n\t\t\t\tif (id === ':not') {\n\t\t\t\t\tif (ids.length === 0) {\n\t\t\t\t\t\tthrow new Error('invalid negation: no group ID preceded \":not()\"');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst parent = ids[ids.length - 1];\n\n\t\t\t\t\tif (parent.id[0] !== ':') {\n\t\t\t\t\t\tthrow new Error(`invalid negation of track \"${parent.id}\": only groups may be negated with \":not()\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst negation = processNegation(idArg, idRe.lastIndex);\n\n\t\t\t\t\tif (negation.nextMatch === -1) {\n\t\t\t\t\t\tthrow new Error('unknown error parsing \":not()\"');\n\t\t\t\t\t}\n\n\t\t\t\t\tidRe.lastIndex = negation.nextMatch;\n\t\t\t\t\tparent.not = parseSelector(negation.str);\n\t\t\t\t}\n\n\t\t\t\t// Group or track ID.\n\t\t\t\telse {\n\t\t\t\t\tids.push({ id });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn ids;\n\t\t}\n\n\t\treturn parseSelector;\n\t})();\n\n\t/*\n\t\tSimpleAudio.select(selector).…;\n\n\t\tE.g.\n\t\t\tSimpleAudio.select(':ui').…\n\t\t\tSimpleAudio.select(':ui:not(boop)').…\n\t\t\tSimpleAudio.select('boop beep').…\n\t\t\tSimpleAudio.select(':ui :sfx').…\n\t\t\tSimpleAudio.select(':ui:not(boop) :sfx overthetop').…\n\t*/\n\tfunction runnerGet(/* selector */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('no track selector specified');\n\t\t}\n\n\t\tconst selector = String(arguments[0]).trim();\n\t\tconst trackIds = new Set();\n\n\t\ttry {\n\t\t\tconst allIds = Array.from(_tracks.keys());\n\n\t\t\tfunction renderIds(idObj) {\n\t\t\t\tconst id = idObj.id;\n\t\t\t\tlet ids;\n\n\t\t\t\tswitch (id) {\n\t\t\t\tcase ':all':     ids = allIds; break;\n\t\t\t\tcase ':looped':  ids = allIds.filter(id => _tracks.get(id).loop()); break;\n\t\t\t\tcase ':muted':   ids = allIds.filter(id => _tracks.get(id).mute()); break;\n\t\t\t\tcase ':paused':  ids = allIds.filter(id => _tracks.get(id).isPaused()); break;\n\t\t\t\tcase ':playing': ids = allIds.filter(id => _tracks.get(id).isPlaying()); break;\n\t\t\t\tdefault:         ids = id[0] === ':' ? _groups.get(id) : [id]; break;\n\t\t\t\t}\n\n\t\t\t\tif (idObj.hasOwnProperty('not')) {\n\t\t\t\t\tconst negated = idObj.not.map(idObj => renderIds(idObj)).flat(Infinity);\n\t\t\t\t\tids = ids.filter(id => !negated.includes(id));\n\t\t\t\t}\n\n\t\t\t\treturn ids;\n\t\t\t}\n\n\t\t\t_runnerParseSelector(selector).forEach(idObj => renderIds(idObj).forEach(id => {\n\t\t\t\tif (!_tracks.has(id)) {\n\t\t\t\t\tthrow new Error(`track \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\ttrackIds.add(id);\n\t\t\t}));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tthrow new Error(`error during runner initialization: ${ex.message}`);\n\t\t}\n\n\t\treturn new AudioRunner(trackIds);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMaster Audio Functions.\n\t*******************************************************************************************************************/\n\tfunction masterLoad() {\n\t\tpublish('load');\n\t}\n\n\tfunction masterLoadWithScreen() {\n\t\tpublish('loadwithscreen');\n\t}\n\n\tfunction masterMute(mute) {\n\t\tif (mute == null) { // lazy equality for null\n\t\t\treturn _masterMute;\n\t\t}\n\n\t\t_masterMute = !!mute;\n\t\tpublish('mute', _masterMute);\n\t}\n\n\tfunction masterMuteOnHidden(mute) {\n\t\t// NOTE: Some older browsers—notably: IE 9—do not support the Page Visibility API.\n\t\tif (!Visibility.isEnabled()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (mute == null) { // lazy equality for null\n\t\t\treturn _masterMuteOnHidden;\n\t\t}\n\n\t\t_masterMuteOnHidden = !!mute;\n\n\t\tconst namespace = '.SimpleAudio_masterMuteOnHidden';\n\n\t\tif (_masterMuteOnHidden) {\n\t\t\tconst visibilityChange = `${Visibility.changeEvent}${namespace}`;\n\t\t\tjQuery(document)\n\t\t\t\t.off(namespace)\n\t\t\t\t.on(visibilityChange, () => masterMute(Visibility.isHidden()));\n\n\t\t\t// Only change the mute state initially if hidden.\n\t\t\tif (Visibility.isHidden()) {\n\t\t\t\tmasterMute(true);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tjQuery(document).off(namespace);\n\t\t}\n\t}\n\n\tfunction masterRate(rate) {\n\t\tif (rate == null) { // lazy equality for null\n\t\t\treturn _masterRate;\n\t\t}\n\n\t\tif (typeof rate !== 'number' || Number.isNaN(rate) || !Number.isFinite(rate)) {\n\t\t\tthrow new Error('rate must be a finite number');\n\t\t}\n\n\t\t_masterRate = Math.clamp(rate, 0.2, 5); // clamp to 5× slower & faster\n\t\tpublish('rate', _masterRate);\n\t}\n\n\tfunction masterStop() {\n\t\tpublish('stop');\n\t}\n\n\tfunction masterUnload() {\n\t\tpublish('unload');\n\t}\n\n\tfunction masterVolume(volume) {\n\t\tif (volume == null) { // lazy equality for null\n\t\t\treturn _masterVolume;\n\t\t}\n\n\t\tif (typeof volume !== 'number' || Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\tthrow new Error('volume must be a finite number');\n\t\t}\n\n\t\t_masterVolume = Math.clamp(volume, 0, 1); // clamp to 0 (silent) & 1 (full loudness)\n\t\tpublish('volume', _masterVolume);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSubscription Functions.\n\t*******************************************************************************************************************/\n\tfunction subscribe(id, callback) {\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new Error('callback parameter must be a function');\n\t\t}\n\n\t\t_subscribers.set(id, callback);\n\t}\n\n\tfunction unsubscribe(id) {\n\t\t_subscribers.delete(id);\n\t}\n\n\tfunction publish(mesg, data) {\n\t\t_subscribers.forEach(fn => fn(mesg, data));\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _newTrack(sources) {\n\t\treturn new AudioTrack(sources.map(source => {\n\t\t\t// Handle audio passages.\n\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\tif (passage.tags.includes('Twine.audio')) {\n\t\t\t\t\treturn passage.text.trim();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle URIs—possibly prefixed with a format specifier.\n\t\t\tconst match = _formatSpecRe.exec(source);\n\t\t\treturn match === null ? source : {\n\t\t\t\tformat : match[1],\n\t\t\t\tsrc    : match[2]\n\t\t\t};\n\t\t}));\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Track Functions.\n\t\ttracks : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : trackAdd },\n\t\t\t\tdelete : { value : trackDelete },\n\t\t\t\tclear  : { value : trackClear },\n\t\t\t\thas    : { value : trackHas },\n\t\t\t\tget    : { value : trackGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Group Functions.\n\t\tgroups : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : groupAdd },\n\t\t\t\tdelete : { value : groupDelete },\n\t\t\t\tclear  : { value : groupClear },\n\t\t\t\thas    : { value : groupHas },\n\t\t\t\tget    : { value : groupGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Playlist Functions.\n\t\tlists : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd    : { value : listAdd },\n\t\t\t\tdelete : { value : listDelete },\n\t\t\t\tclear  : { value : listClear },\n\t\t\t\thas    : { value : listHas },\n\t\t\t\tget    : { value : listGet }\n\t\t\t}))\n\t\t},\n\n\t\t// Runner Functions.\n\t\tselect : { value : runnerGet },\n\n\t\t// Master Audio Functions.\n\t\tload           : { value : masterLoad },\n\t\tloadWithScreen : { value : masterLoadWithScreen },\n\t\tmute           : { value : masterMute },\n\t\tmuteOnHidden   : { value : masterMuteOnHidden },\n\t\trate           : { value : masterRate },\n\t\tstop           : { value : masterStop },\n\t\tunload         : { value : masterUnload },\n\t\tvolume         : { value : masterVolume }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tstate.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Diff, Engine, PRNGWrapper, Patterns, clone, session, storage */\n\nvar State = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// History moment stack.\n\tlet _history = [];\n\n\t// Currently active/played moment.\n\tlet _active = momentCreate();\n\n\t// Currently active/played moment index.\n\tlet _activeIndex = -1;\n\n\t// Titles of all moments which have expired (i.e. fallen off the bottom of the stack).\n\tlet _expired = [];\n\n\t// (optional) Seedable PRNG object.\n\tlet _prng = null;\n\n\t// Temporary variables object.\n\tlet _tempVariables = {};\n\n\n\t/*******************************************************************************************************************\n\t\tState Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tResets the story state.\n\t*/\n\tfunction stateReset() {\n\t\tif (DEBUG) { console.log('[State/stateReset()]'); }\n\n\t\t/*\n\t\t\tDelete the active session.\n\t\t*/\n\t\tsession.delete('state');\n\n\t\t/*\n\t\t\tReset the properties.\n\t\t*/\n\t\t_history     = [];\n\t\t_active      = momentCreate();\n\t\t_activeIndex = -1;\n\t\t_expired     = [];\n\t\t_prng        = _prng === null ? null : new PRNGWrapper(_prng.seed, false);\n\t}\n\n\t/*\n\t\tRestores the story state from the active session.\n\t*/\n\tfunction stateRestore() {\n\t\tif (DEBUG) { console.log('[State/stateRestore()]'); }\n\n\t\t/*\n\t\t\tAttempt to restore an active session.\n\t\t*/\n\t\tif (session.has('state')) {\n\t\t\t/*\n\t\t\t\tRetrieve the session.\n\t\t\t*/\n\t\t\tconst stateObj = session.get('state');\n\n\t\t\tif (DEBUG) { console.log('\\tsession state:', stateObj); }\n\n\t\t\tif (stateObj == null) { // lazy equality for null\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tRestore the session.\n\t\t\t*/\n\t\t\tstateUnmarshal(stateObj);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tReturns the current story state marshaled into a serializable object.\n\t*/\n\tfunction stateMarshal(noDelta) {\n\t\t/*\n\t\t\tGather the properties.\n\t\t*/\n\t\tconst stateObj = {\n\t\t\tindex : _activeIndex\n\t\t};\n\n\t\tif (noDelta) {\n\t\t\tstateObj.history = clone(_history);\n\t\t}\n\t\telse {\n\t\t\tstateObj.delta = historyDeltaEncode(_history);\n\t\t}\n\n\t\tif (_expired.length > 0) {\n\t\t\tstateObj.expired = [];\n\t\t}\n\n\t\tif (_prng !== null) {\n\t\t\tstateObj.seed = _prng.seed;\n\t\t}\n\n\t\treturn stateObj;\n\t}\n\n\t/*\n\t\tRestores the story state from a marshaled story state serialization object.\n\t*/\n\tfunction stateUnmarshal(stateObj, noDelta) {\n\t\tif (stateObj == null) { // lazy equality for null\n\t\t\tthrow new Error('state object is null or undefined');\n\t\t}\n\n\t\tif (\n\t\t\t   !stateObj.hasOwnProperty(noDelta ? 'history' : 'delta')\n\t\t\t|| stateObj[noDelta ? 'history' : 'delta'].length === 0\n\t\t) {\n\t\t\tthrow new Error('state object has no history or history is empty');\n\t\t}\n\n\t\tif (!stateObj.hasOwnProperty('index')) {\n\t\t\tthrow new Error('state object has no index');\n\t\t}\n\n\t\tif (_prng !== null && !stateObj.hasOwnProperty('seed')) {\n\t\t\tthrow new Error('state object has no seed, but PRNG is enabled');\n\t\t}\n\n\t\tif (_prng === null && stateObj.hasOwnProperty('seed')) {\n\t\t\tthrow new Error('state object has seed, but PRNG is disabled');\n\t\t}\n\n\t\t/*\n\t\t\tRestore the properties.\n\t\t*/\n\t\t_history     = noDelta ? clone(stateObj.history) : historyDeltaDecode(stateObj.delta);\n\t\t_activeIndex = stateObj.index;\n\t\t_expired     = stateObj.hasOwnProperty('expired') ? [...stateObj.expired] : [];\n\n\t\tif (stateObj.hasOwnProperty('seed')) {\n\t\t\t/*\n\t\t\t\tWe only need to restore the PRNG's seed here as `momentActivate()` will handle\n\t\t\t\tfully restoring the PRNG to its proper state.\n\t\t\t*/\n\t\t\t_prng.seed = stateObj.seed;\n\t\t}\n\n\t\t/*\n\t\t\tActivate the current moment (do this only after all properties have been restored).\n\t\t*/\n\t\tmomentActivate(_activeIndex);\n\t}\n\n\t/*\n\t\tReturns the current story state marshaled into a save-compatible serializable object.\n\t*/\n\tfunction stateMarshalForSave() {\n\t\treturn stateMarshal(true);\n\t}\n\n\t/*\n\t\tRestores the story state from a marshaled save-compatible story state serialization object.\n\t*/\n\tfunction stateUnmarshalForSave(stateObj) {\n\t\treturn stateUnmarshal(stateObj, true);\n\t}\n\n\t/*\n\t\tReturns the titles of expired moments.\n\t*/\n\tfunction stateExpired() {\n\t\treturn _expired;\n\t}\n\n\t/*\n\t\tReturns the total number of played moments (expired + in-play history moments).\n\t*/\n\tfunction stateTurns() {\n\t\treturn _expired.length + historyLength();\n\t}\n\n\t/*\n\t\tReturns the passage titles of all played moments (expired + in-play history moments).\n\t*/\n\tfunction stateTitles() {\n\t\treturn _expired.concat(_history.slice(0, historyLength()).map(moment => moment.title));\n\t}\n\n\t/*\n\t\tReturns whether a passage with the given title has been played (expired + in-play history moments).\n\t*/\n\tfunction stateHasPlayed(title) {\n\t\tif (title == null || title === '') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tif (_expired.includes(title)) {\n\t\t\treturn true;\n\t\t}\n\t\telse if (_history.slice(0, historyLength()).some(moment => moment.title === title)) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMoment Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a new moment object created from the given passage title and variables object.\n\t*/\n\tfunction momentCreate(title, variables) {\n\t\treturn {\n\t\t\ttitle     : title == null ? '' : String(title), // lazy equality for null\n\t\t\tvariables : variables == null ? {} : variables   // lazy equality for null\n\t\t};\n\t}\n\n\t/*\n\t\tReturns the active (present) moment.\n\t*/\n\tfunction momentActive() {\n\t\treturn _active;\n\t}\n\n\t/*\n\t\tReturns the index within the history of the active (present) moment.\n\t*/\n\tfunction momentActiveIndex() {\n\t\treturn _activeIndex;\n\t}\n\n\t/*\n\t\tReturns the title from the active (present) moment.\n\t*/\n\tfunction momentActiveTitle() {\n\t\treturn _active.title;\n\t}\n\n\t/*\n\t\tReturns the variables from the active (present) moment.\n\t*/\n\tfunction momentActiveVariables() {\n\t\treturn _active.variables;\n\t}\n\n\t/*\n\t\tReturns the active (present) moment after setting it to either the given moment object\n\t\tor the moment object at the given history index.  Additionally, updates the active session\n\t\tand triggers a history update event.\n\t*/\n\tfunction momentActivate(moment) {\n\t\tif (moment == null) { // lazy equality for null\n\t\t\tthrow new Error('moment activation attempted with null or undefined');\n\t\t}\n\n\t\t/*\n\t\t\tSet the active moment.\n\t\t*/\n\t\tswitch (typeof moment) {\n\t\tcase 'object':\n\t\t\t_active = clone(moment);\n\t\t\tbreak;\n\n\t\tcase 'number':\n\t\t\tif (historyIsEmpty()) {\n\t\t\t\tthrow new Error('moment activation attempted with index on empty history');\n\t\t\t}\n\n\t\t\tif (moment < 0 || moment >= historySize()) {\n\t\t\t\tthrow new RangeError(`moment activation attempted with out-of-bounds index; need [0, ${historySize() - 1}], got ${moment}`);\n\t\t\t}\n\n\t\t\t_active = clone(_history[moment]);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new TypeError(`moment activation attempted with a \"${typeof moment}\"; must be an object or valid history stack index`);\n\t\t}\n\n\t\t/*\n\t\t\tRestore the seedable PRNG.\n\n\t\t\tNOTE: We cannot simply set `_prng.pull` to `_active.pull` as that would\n\t\t\tnot properly mutate the PRNG's internal state.\n\t\t*/\n\t\tif (_prng !== null) {\n\t\t\t_prng = PRNGWrapper.unmarshal({\n\t\t\t\tseed : _prng.seed,\n\t\t\t\tpull : _active.pull\n\t\t\t});\n\t\t}\n\n\t\t/*\n\t\t\tUpdate the active session.\n\t\t*/\n\t\tsession.set('state', stateMarshal());\n\n\t\t/*\n\t\t\tTrigger a global `:historyupdate` event.\n\n\t\t\tNOTE: We do this here because setting a new active moment is a core component\n\t\t\tof, virtually, all history updates.\n\t\t*/\n\t\tjQuery.event.trigger(':historyupdate');\n\n\t\treturn _active;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tHistory Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the moment history.\n\t*/\n\tfunction historyGet() {\n\t\treturn _history;\n\t}\n\n\t/*\n\t\tReturns the number of active history moments (past only).\n\t*/\n\tfunction historyLength() {\n\t\treturn _activeIndex + 1;\n\t}\n\n\t/*\n\t\tReturns the total number of history moments (past + future).\n\t*/\n\tfunction historySize() {\n\t\treturn _history.length;\n\t}\n\n\t/*\n\t\tReturns whether the history is empty.\n\t*/\n\tfunction historyIsEmpty() {\n\t\treturn _history.length === 0;\n\t}\n\n\t/*\n\t\tReturns the current (pre-play version of the active) moment within the history.\n\t*/\n\tfunction historyCurrent() {\n\t\treturn _history.length > 0 ? _history[_activeIndex] : null;\n\t}\n\n\t/*\n\t\tReturns the topmost (most recent) moment within the history.\n\t*/\n\tfunction historyTop() {\n\t\treturn _history.length > 0 ? _history[_history.length - 1] : null;\n\t}\n\n\t/*\n\t\tReturns the bottommost (least recent) moment within the history.\n\t*/\n\tfunction historyBottom() {\n\t\treturn _history.length > 0 ? _history[0] : null;\n\t}\n\n\t/*\n\t\tReturns the moment at the given index within the history.\n\t*/\n\tfunction historyIndex(index) {\n\t\tif (historyIsEmpty() || index < 0 || index > _activeIndex) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn _history[index];\n\t}\n\n\t/*\n\t\tReturns the moment at the given offset from the active moment within the history.\n\t*/\n\tfunction historyPeek(offset) {\n\t\tif (historyIsEmpty()) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst lengthOffset = 1 + (offset ? Math.abs(offset) : 0);\n\n\t\tif (lengthOffset > historyLength()) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn _history[historyLength() - lengthOffset];\n\t}\n\n\t/*\n\t\tReturns whether a moment with the given title exists within the history.\n\t*/\n\tfunction historyHas(title) {\n\t\tif (historyIsEmpty() || title == null || title === '') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (let i = _activeIndex; i >= 0; --i) {\n\t\t\tif (_history[i].title === title) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tCreates a new moment and pushes it onto the history, discarding future moments if necessary.\n\t*/\n\tfunction historyCreate(title) {\n\t\tif (DEBUG) { console.log(`[State/historyCreate(title: \"${title}\")]`); }\n\n\t\t/*\n\t\t\tTODO: It might be good to have some assertions about the passage title here.\n\t\t*/\n\n\t\t/*\n\t\t\tIf we're not at the top of the stack, discard the future moments.\n\t\t*/\n\t\tif (historyLength() < historySize()) {\n\t\t\tif (DEBUG) { console.log(`\\tnon-top push; discarding ${historySize() - historyLength()} future moments`); }\n\n\t\t\t_history.splice(historyLength(), historySize() - historyLength());\n\t\t}\n\n\t\t/*\n\t\t\tPush the new moment onto the history stack.\n\t\t*/\n\t\t_history.push(momentCreate(title, _active.variables));\n\n\t\tif (_prng) {\n\t\t\thistoryTop().pull = _prng.pull;\n\t\t}\n\n\t\t/*\n\t\t\tTruncate the history, if necessary, by discarding moments from the bottom.\n\t\t*/\n\t\tif (Config.history.maxStates > 0) {\n\t\t\twhile (historySize() > Config.history.maxStates) {\n\t\t\t\t_expired.push(_history.shift().title);\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t\tActivate the new top moment.\n\t\t*/\n\t\t_activeIndex = historySize() - 1;\n\t\tmomentActivate(_activeIndex);\n\n\t\treturn historyLength();\n\t}\n\n\t/*\n\t\tActivate the moment at the given index within the history.\n\t*/\n\tfunction historyGoTo(index) {\n\t\tif (DEBUG) { console.log(`[State/historyGoTo(index: ${index})]`); }\n\n\t\tif (\n\t\t\t   index == null /* lazy equality for null */\n\t\t\t|| index < 0\n\t\t\t|| index >= historySize()\n\t\t\t|| index === _activeIndex\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\t_activeIndex = index;\n\t\tmomentActivate(_activeIndex);\n\n\t\treturn true;\n\t}\n\n\t/*\n\t\tActivate the moment at the given offset from the active moment within the history.\n\t*/\n\tfunction historyGo(offset) {\n\t\tif (DEBUG) { console.log(`[State/historyGo(offset: ${offset})]`); }\n\n\t\tif (offset == null || offset === 0) { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\treturn historyGoTo(_activeIndex + offset);\n\t}\n\n\t/*\n\t\tReturns the delta encoded form of the given history array.\n\t*/\n\tfunction historyDeltaEncode(historyArr) {\n\t\tif (!Array.isArray(historyArr)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (historyArr.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst delta = [historyArr[0]];\n\n\t\tfor (let i = 1, iend = historyArr.length; i < iend; ++i) {\n\t\t\tdelta.push(Diff.diff(historyArr[i - 1], historyArr[i]));\n\t\t}\n\n\t\treturn delta;\n\t}\n\n\t/*\n\t\tReturns a history array from the given delta encoded history array.\n\t*/\n\tfunction historyDeltaDecode(delta) {\n\t\tif (!Array.isArray(delta)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (delta.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst historyArr = [clone(delta[0])];\n\n\t\tfor (let i = 1, iend = delta.length; i < iend; ++i) {\n\t\t\thistoryArr.push(Diff.patch(historyArr[i - 1], delta[i]));\n\t\t}\n\n\t\treturn historyArr;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPRNG Functions.\n\t*******************************************************************************************************************/\n\tfunction prngInit(seed, useEntropy) {\n\t\tif (DEBUG) { console.log(`[State/prngInit(seed: ${seed}, useEntropy: ${useEntropy})]`); }\n\n\t\tif (!historyIsEmpty()) {\n\t\t\tlet scriptSection;\n\n\t\t\tif (TWINE1) { // for Twine 1\n\t\t\t\tscriptSection = 'a script-tagged passage';\n\t\t\t}\n\t\t\telse { // for Twine 2\n\t\t\t\tscriptSection = 'the Story JavaScript';\n\t\t\t}\n\n\t\t\tthrow new Error(`State.initPRNG must be called during initialization, within either ${scriptSection} or the StoryInit special passage`);\n\t\t}\n\n\t\t_prng = new PRNGWrapper(seed, useEntropy);\n\t\t_active.pull = _prng.pull;\n\t}\n\n\tfunction prngIsEnabled() {\n\t\treturn _prng !== null;\n\t}\n\n\tfunction prngPull() {\n\t\treturn _prng ? _prng.pull : NaN;\n\t}\n\n\tfunction prngSeed() {\n\t\treturn _prng ? _prng.seed : null;\n\t}\n\n\tfunction prngRandom() {\n\t\tif (DEBUG) { console.log('[State/prngRandom()]'); }\n\n\t\treturn _prng ? _prng.random() : Math.random();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTemporary Variables Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tClear the temporary variables.\n\t*/\n\tfunction tempVariablesClear() {\n\t\tif (DEBUG) { console.log('[State/tempVariablesReset()]'); }\n\n\t\t_tempVariables = {};\n\n\t\t/* legacy */\n\t\tTempVariables = _tempVariables; // eslint-disable-line no-undef\n\t\t/* /legacy */\n\t}\n\n\t/*\n\t\tReturns the current temporary variables.\n\t*/\n\tfunction tempVariables() {\n\t\treturn _tempVariables;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tVariable Chain Parsing Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the value of the given story/temporary variable.\n\t*/\n\tfunction variableGet(name) {\n\t\tconst varData = _parseVariableChain(name);\n\n\t\tif (varData === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst pNames = varData.names;\n\t\tlet retVal = varData.store;\n\n\t\tfor (let i = 0, iend = pNames.length; i < iend; ++i) {\n\t\t\tif (typeof retVal[pNames[i]] === 'undefined') {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tretVal = retVal[pNames[i]];\n\t\t}\n\n\t\treturn retVal;\n\t}\n\n\t/*\n\t\tSets the value of the given story/temporary variable.\n\t*/\n\tfunction variableSet(name, value) {\n\t\tconst varData = _parseVariableChain(name);\n\n\t\tif (varData === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst pNames  = varData.names;\n\t\tconst varName = pNames.pop();\n\t\tlet baseObj = varData.store;\n\n\t\tfor (let i = 0, iend = pNames.length; i < iend; ++i) {\n\t\t\tif (typeof baseObj[pNames[i]] === 'undefined') {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tbaseObj = baseObj[pNames[i]];\n\t\t}\n\n\t\tbaseObj[varName] = value;\n\t\treturn true;\n\t}\n\n\t/*\n\t\tReturns the property name chain of the given story/temporary variable,\n\t\twhich may be of arbitrary complexity.\n\t*/\n\tconst _parseVarRegExp = new RegExp(`^(?:${Patterns.variableSigil}(${Patterns.identifier})|\\\\.(${Patterns.identifier})|\\\\[(?:(?:\"((?:\\\\\\\\.|[^\"\\\\\\\\])+)\")|(?:'((?:\\\\\\\\.|[^'\\\\\\\\])+)')|(${Patterns.variableSigil}${Patterns.identifierFirstChar}.*)|(\\\\d+))\\\\])`);\n\tfunction _parseVariableChain(varText) {\n\t\tconst retVal = {\n\t\t\tstore : varText[0] === '$' ? State.variables : State.temporary,\n\t\t\tnames : []\n\t\t};\n\t\tlet text  = varText;\n\t\tlet match;\n\n\t\twhile ((match = _parseVarRegExp.exec(text)) !== null) {\n\t\t\t// Remove full match from text.\n\t\t\ttext = text.slice(match[0].length);\n\n\t\t\t// Base variable.\n\t\t\tif (match[1]) {\n\t\t\t\tretVal.names.push(match[1]);\n\t\t\t}\n\n\t\t\t// Dot property.\n\t\t\telse if (match[2]) {\n\t\t\t\tretVal.names.push(match[2]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (double quoted).\n\t\t\telse if (match[3]) {\n\t\t\t\tretVal.names.push(match[3]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (single quoted).\n\t\t\telse if (match[4]) {\n\t\t\t\tretVal.names.push(match[4]);\n\t\t\t}\n\n\t\t\t// Square-bracketed property (embedded variable).\n\t\t\telse if (match[5]) {\n\t\t\t\tretVal.names.push(variableGet(match[5]));\n\t\t\t}\n\n\t\t\t// Square-bracketed property (numeric index).\n\t\t\telse if (match[6]) {\n\t\t\t\tretVal.names.push(Number(match[6]));\n\t\t\t}\n\t\t}\n\n\t\treturn text === '' ? retVal : null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tStory Metadata Functions.\n\t*******************************************************************************************************************/\n\tconst _METADATA_STORE = 'metadata';\n\n\tfunction metadataClear() {\n\t\tstorage.delete(_METADATA_STORE);\n\t}\n\n\tfunction metadataDelete(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.delete key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\n\t\tif (store && store.hasOwnProperty(key)) {\n\t\t\tif (Object.keys(store).length === 1) {\n\t\t\t\tstorage.delete(_METADATA_STORE);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdelete store[key];\n\t\t\t\tstorage.set(_METADATA_STORE, store);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction metadataGet(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.get key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store && store.hasOwnProperty(key) ? store[key] : undefined;\n\t}\n\n\tfunction metadataHas(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.has key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store && store.hasOwnProperty(key);\n\t}\n\n\tfunction metadataSet(key, value) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`State.metadata.set key parameter must be a string (received: ${typeof key})`);\n\t\t}\n\n\t\tif (typeof value === 'undefined') {\n\t\t\tmetadataDelete(key);\n\t\t}\n\t\telse {\n\t\t\tconst store = storage.get(_METADATA_STORE) || {};\n\t\t\tstore[key] = value;\n\t\t\tstorage.set(_METADATA_STORE, store);\n\t\t}\n\t}\n\n\tfunction metadataSize() {\n\t\tconst store = storage.get(_METADATA_STORE);\n\t\treturn store ? Object.keys(store).length : 0;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tState Functions.\n\t\t*/\n\t\treset            : { value : stateReset },\n\t\trestore          : { value : stateRestore },\n\t\tmarshalForSave   : { value : stateMarshalForSave },\n\t\tunmarshalForSave : { value : stateUnmarshalForSave },\n\t\texpired          : { get : stateExpired },\n\t\tturns            : { get : stateTurns },\n\t\tpassages         : { get : stateTitles },\n\t\thasPlayed        : { value : stateHasPlayed },\n\n\t\t/*\n\t\t\tMoment Functions.\n\t\t*/\n\t\tactive      : { get : momentActive },\n\t\tactiveIndex : { get : momentActiveIndex },\n\t\tpassage     : { get : momentActiveTitle },     // shortcut for `State.active.title`\n\t\tvariables   : { get : momentActiveVariables }, // shortcut for `State.active.variables`\n\n\t\t/*\n\t\t\tHistory Functions.\n\t\t*/\n\t\thistory     : { get : historyGet },\n\t\tlength      : { get : historyLength },\n\t\tsize        : { get : historySize },\n\t\tisEmpty     : { value : historyIsEmpty },\n\t\tcurrent     : { get : historyCurrent },\n\t\ttop         : { get : historyTop },\n\t\tbottom      : { get : historyBottom },\n\t\tindex       : { value : historyIndex },\n\t\tpeek        : { value : historyPeek },\n\t\thas         : { value : historyHas },\n\t\tcreate      : { value : historyCreate },\n\t\tgoTo        : { value : historyGoTo },\n\t\tgo          : { value : historyGo },\n\t\tdeltaEncode : { value : historyDeltaEncode },\n\t\tdeltaDecode : { value : historyDeltaDecode },\n\n\t\t/*\n\t\t\tPRNG Functions.\n\t\t*/\n\t\tprng : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tinit      : { value : prngInit },\n\t\t\t\tisEnabled : { value : prngIsEnabled },\n\t\t\t\tpull      : { get : prngPull },\n\t\t\t\tseed      : { get : prngSeed }\n\t\t\t}))\n\t\t},\n\t\trandom : { value : prngRandom },\n\n\t\t/*\n\t\t\tTemporary Variables Functions.\n\t\t*/\n\t\tclearTemporary : { value : tempVariablesClear },\n\t\ttemporary      : { get : tempVariables },\n\n\t\t/*\n\t\t\tVariable Chain Parsing Functions.\n\t\t*/\n\t\tgetVar : { value : variableGet },\n\t\tsetVar : { value : variableSet },\n\n\t\t/*\n\t\t\tStory Metadata Functions.\n\t\t*/\n\t\tmetadata : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tclear  : { value : metadataClear },\n\t\t\t\tdelete : { value : metadataDelete },\n\t\t\t\tget    : { value : metadataGet },\n\t\t\t\thas    : { value : metadataHas },\n\t\t\t\tset    : { value : metadataSet },\n\t\t\t\tsize   : { get : metadataSize }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tinitPRNG : { value : prngInit },\n\t\trestart  : { value : () => Engine.restart() },\n\t\tbackward : { value : () => Engine.backward() },\n\t\tforward  : { value : () => Engine.forward() },\n\t\tdisplay  : { value : (...args) => Engine.display(...args) },\n\t\tshow     : { value : (...args) => Engine.show(...args) },\n\t\tplay     : { value : (...args) => Engine.play(...args) }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/scripting.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Engine, Patterns, State, Story, Util */\n\nvar Scripting = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/* eslint-disable no-unused-vars */\n\n\t/*******************************************************************************************************************\n\t\tDeprecated Legacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Returns the jQuery-wrapped target element(s) after making them accessible\n\t\tclickables (ARIA compatibility).\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction addAccessibleClickHandler(targets, selector, handler, one, namespace) {\n\t\tif (arguments.length < 2) {\n\t\t\tthrow new Error('addAccessibleClickHandler insufficient number of parameters');\n\t\t}\n\n\t\tlet fn;\n\t\tlet opts;\n\n\t\tif (typeof selector === 'function') {\n\t\t\tfn = selector;\n\t\t\topts = {\n\t\t\t\tnamespace : one,\n\t\t\t\tone       : !!handler\n\t\t\t};\n\t\t}\n\t\telse {\n\t\t\tfn = handler;\n\t\t\topts = {\n\t\t\t\tnamespace,\n\t\t\t\tone : !!one,\n\t\t\t\tselector\n\t\t\t};\n\t\t}\n\n\t\tif (typeof fn !== 'function') {\n\t\t\tthrow new TypeError('addAccessibleClickHandler handler parameter must be a function');\n\t\t}\n\n\t\treturn jQuery(targets).ariaClick(opts, fn);\n\t}\n\n\t/*\n\t\t[DEPRECATED] Returns a new DOM element, optionally appending it to the passed DOM element, if any.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction insertElement(place, type, id, classNames, text, title) { // eslint-disable-line max-params\n\t\tconst $el = jQuery(document.createElement(type));\n\n\t\t// Add attributes/properties.\n\t\tif (id) {\n\t\t\t$el.attr('id', id);\n\t\t}\n\n\t\tif (classNames) {\n\t\t\t$el.addClass(classNames);\n\t\t}\n\n\t\tif (title) {\n\t\t\t$el.attr('title', title);\n\t\t}\n\n\t\t// Add text content.\n\t\tif (text) {\n\t\t\t$el.text(text);\n\t\t}\n\n\t\t// Append it to the given node.\n\t\tif (place) {\n\t\t\t$el.appendTo(place);\n\t\t}\n\n\t\treturn $el[0];\n\t}\n\n\t/*\n\t\t[DEPRECATED] Creates a new text node and appends it to the passed DOM element.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction insertText(place, text) {\n\t\tjQuery(place).append(document.createTextNode(text));\n\t}\n\n\t/*\n\t\t[DEPRECATED] Removes all children from the passed DOM node.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction removeChildren(node) {\n\t\tjQuery(node).empty();\n\t}\n\n\t/*\n\t\t[DEPRECATED] Removes the passed DOM node.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction removeElement(node) {\n\t\tjQuery(node).remove();\n\t}\n\n\t/*\n\t\t[DEPRECATED] Fades a DOM element in or out.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction fade(el, options) {\n\t\t/* eslint-disable no-param-reassign */\n\t\tconst direction = options.fade === 'in' ? 1 : -1;\n\t\tlet current;\n\t\tlet proxy      = el.cloneNode(true);\n\t\tlet intervalId; // eslint-disable-line prefer-const\n\n\t\tfunction tick() {\n\t\t\tcurrent += 0.05 * direction;\n\t\t\tsetOpacity(proxy, Math.easeInOut(current));\n\n\t\t\tif (direction === 1 && current >= 1 || direction === -1 && current <= 0) {\n\t\t\t\tel.style.visibility = options.fade === 'in' ? 'visible' : 'hidden';\n\t\t\t\tproxy.parentNode.replaceChild(el, proxy);\n\t\t\t\tproxy = null;\n\t\t\t\twindow.clearInterval(intervalId);\n\n\t\t\t\tif (options.onComplete) {\n\t\t\t\t\toptions.onComplete();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction setOpacity(el, opacity) {\n\t\t\t// Old IE.\n\t\t\tel.style.zoom = 1;\n\t\t\tel.style.filter = `alpha(opacity=${Math.floor(opacity * 100)})`;\n\n\t\t\t// CSS.\n\t\t\tel.style.opacity = opacity;\n\t\t}\n\n\t\tel.parentNode.replaceChild(proxy, el);\n\n\t\tif (options.fade === 'in') {\n\t\t\tcurrent = 0;\n\t\t\tproxy.style.visibility = 'visible';\n\t\t}\n\t\telse {\n\t\t\tcurrent = 1;\n\t\t}\n\n\t\tsetOpacity(proxy, current);\n\t\tintervalId = window.setInterval(tick, 25);\n\t\t/* eslint-enable no-param-reassign */\n\t}\n\n\t/*\n\t\t[DEPRECATED] Scrolls the browser window to ensure that a DOM element is in view.\n\n\t\tNOTE: Unused, included only for compatibility.\n\t*/\n\tfunction scrollWindowTo(el, incrementBy) {\n\t\t/* eslint-disable no-param-reassign */\n\t\tlet increment = incrementBy != null ? Number(incrementBy) : 0.1; // lazy equality for null\n\n\t\tif (Number.isNaN(increment) || !Number.isFinite(increment) || increment < 0) {\n\t\t\tincrement = 0.1;\n\t\t}\n\t\telse if (increment > 1) {\n\t\t\tincrement = 1;\n\t\t}\n\n\t\tconst start     = window.scrollY ? window.scrollY : document.body.scrollTop;\n\t\tconst end       = ensureVisible(el);\n\t\tconst distance  = Math.abs(start - end);\n\t\tconst direction = start > end ? -1 : 1;\n\t\tlet progress   = 0;\n\t\tlet intervalId; // eslint-disable-line prefer-const\n\n\t\tfunction tick() {\n\t\t\tprogress += increment;\n\t\t\twindow.scroll(0, start + direction * (distance * Math.easeInOut(progress)));\n\n\t\t\tif (progress >= 1) {\n\t\t\t\twindow.clearInterval(intervalId);\n\t\t\t}\n\t\t}\n\n\t\tfunction findPosY(el) { // eslint-disable-line no-shadow\n\t\t\tlet curtop = 0;\n\n\t\t\twhile (el.offsetParent) {\n\t\t\t\tcurtop += el.offsetTop;\n\t\t\t\tel = el.offsetParent;\n\t\t\t}\n\n\t\t\treturn curtop;\n\t\t}\n\n\t\tfunction ensureVisible(el) { // eslint-disable-line no-shadow\n\t\t\tconst posTop    = findPosY(el);\n\t\t\tconst posBottom = posTop + el.offsetHeight;\n\t\t\tconst winTop    = window.scrollY ? window.scrollY : document.body.scrollTop;\n\t\t\tconst winHeight = window.innerHeight ? window.innerHeight : document.body.clientHeight;\n\t\t\tconst winBottom = winTop + winHeight;\n\n\t\t\treturn posTop >= winTop && posBottom > winBottom && el.offsetHeight < winHeight\n\t\t\t\t? posTop - (winHeight - el.offsetHeight) + 20\n\t\t\t\t: posTop;\n\t\t}\n\n\t\tintervalId = window.setInterval(tick, 25);\n\t\t/* eslint-enable no-param-reassign */\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUser Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns a random value from its given arguments.\n\t*/\n\tfunction either(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn Array.prototype.concat.apply([], arguments).random();\n\t}\n\n\t/*\n\t\tRemoves the given key, and its value, from the story metadata store.\n\t*/\n\tfunction forget(key) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`forget key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\tState.metadata.delete(key);\n\t}\n\n\t/*\n\t\tReturns whether a passage with the given title exists within the story\n\t\thistory.  If multiple passage titles are given, returns the logical-AND\n\t\taggregate of the set.\n\t*/\n\tfunction hasVisited(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('hasVisited called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst played  = State.passages;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend; ++i) {\n\t\t\tif (!played.includes(needles[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/*\n\t\tReturns the number of turns that have passed since the last instance of the given passage\n\t\toccurred within the story history or `-1` if it does not exist.  If multiple passages are\n\t\tgiven, returns the lowest count (which can be `-1`).\n\t*/\n\tfunction lastVisited(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('lastVisited called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn -1;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst played  = State.passages;\n\t\tconst uBound  = played.length - 1;\n\t\tlet turns = State.turns;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend && turns > -1; ++i) {\n\t\t\tconst lastIndex = played.lastIndexOf(needles[i]);\n\t\t\tturns = Math.min(turns, lastIndex === -1 ? -1 : uBound - lastIndex);\n\t\t}\n\n\t\treturn turns;\n\t}\n\n\t/*\n\t\tSets the given key/value pair within the story metadata store.\n\t*/\n\tfunction memorize(key, value) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`memorize key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\tState.metadata.set(key, value);\n\t}\n\n\t/*\n\t\tReturns the title of the current passage.\n\t*/\n\tfunction passage() {\n\t\treturn State.passage;\n\t}\n\n\t/*\n\t\tReturns the title of a previous passage, either the most recent one whose title does not\n\t\tmatch that of the active passage or the one at the optional offset, or an empty string,\n\t\tif there is no such passage.\n\t*/\n\tfunction previous(/* legacy: offset */) {\n\t\tconst passages = State.passages;\n\n\t\t/* legacy: behavior with an offset */\n\t\tif (arguments.length > 0) {\n\t\t\tconst offset = Number(arguments[0]);\n\n\t\t\tif (!Number.isSafeInteger(offset) || offset < 1) {\n\t\t\t\tthrow new RangeError('previous offset parameter must be a positive integer greater than zero');\n\t\t\t}\n\n\t\t\treturn passages.length > offset ? passages[passages.length - 1 - offset] : '';\n\t\t}\n\t\t/* /legacy */\n\n\t\tfor (let i = passages.length - 2; i >= 0; --i) {\n\t\t\tif (passages[i] !== State.passage) {\n\t\t\t\treturn passages[i];\n\t\t\t}\n\t\t}\n\n\t\treturn '';\n\t}\n\n\t/*\n\t\tReturns a pseudo-random whole number (integer) within the range of the given bounds.\n\t*/\n\tfunction random(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('random called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0;\n\t\t\tmax = Math.trunc(arguments[0]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Math.trunc(arguments[0]);\n\t\t\tmax = Math.trunc(arguments[1]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (!Number.isInteger(min)) {\n\t\t\tthrow new Error('random min parameter must be an integer');\n\t\t}\n\t\tif (!Number.isInteger(max)) {\n\t\t\tthrow new Error('random max parameter must be an integer');\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn Math.floor(State.random() * (max - min + 1)) + min;\n\t}\n\n\t/*\n\t\tReturns a pseudo-random real number (floating-point) within the range of the given bounds.\n\n\t\tNOTE: Unlike with its sibling function `random()`, the `max` parameter\n\t\tis exclusive, not inclusive—i.e. the range goes to, but does not include,\n\t\tthe given value.\n\t*/\n\tfunction randomFloat(/* [min ,] max */) {\n\t\tlet min;\n\t\tlet max;\n\n\t\tswitch (arguments.length) {\n\t\tcase 0:\n\t\t\tthrow new Error('randomFloat called with insufficient parameters');\n\t\tcase 1:\n\t\t\tmin = 0.0;\n\t\t\tmax = Number(arguments[0]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tmin = Number(arguments[0]);\n\t\t\tmax = Number(arguments[1]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (Number.isNaN(min) || !Number.isFinite(min)) {\n\t\t\tthrow new Error('randomFloat min parameter must be a number');\n\t\t}\n\t\tif (Number.isNaN(max) || !Number.isFinite(max)) {\n\t\t\tthrow new Error('randomFloat max parameter must be a number');\n\t\t}\n\n\t\tif (min > max) {\n\t\t\t[min, max] = [max, min];\n\t\t}\n\n\t\treturn State.random() * (max - min) + min;\n\t}\n\n\t/*\n\t\tReturns the value of the given key from the story metadata store\n\t\tor the given default value if the key does not exist.\n\t*/\n\tfunction recall(key, defaultValue) {\n\t\tif (typeof key !== 'string') {\n\t\t\tthrow new TypeError(`recall key parameter must be a string (received: ${Util.getType(key)})`);\n\t\t}\n\n\t\treturn State.metadata.has(key) ? State.metadata.get(key) : defaultValue;\n\t}\n\n\t/*\n\t\tReturns a new array consisting of all of the tags of the given passages.\n\t*/\n\tfunction tags(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\treturn Story.get(State.passage).tags.slice(0);\n\t\t}\n\n\t\tconst passages = Array.prototype.concat.apply([], arguments);\n\t\tlet tags = [];\n\n\t\tfor (let i = 0, iend = passages.length; i < iend; ++i) {\n\t\t\ttags = tags.concat(Story.get(passages[i]).tags);\n\t\t}\n\n\t\treturn tags;\n\t}\n\n\t/*\n\t\tReturns a reference to the current temporary _variables store.\n\t*/\n\tfunction temporary() {\n\t\treturn State.temporary;\n\t}\n\n\t/*\n\t\tReturns the number of milliseconds which have passed since the current passage was rendered.\n\t*/\n\tfunction time() {\n\t\treturn Engine.lastPlay === null ? 0 : Util.now() - Engine.lastPlay;\n\t}\n\n\t/*\n\t\tReturns the number of passages that the player has visited.\n\n\t\tNOTE: Passages which were visited but have been undone—e.g. via the backward\n\t\tbutton or the `<<back>>` macro—are no longer part of the in-play story\n\t\thistory and thus are not tallied.  Passages which were visited but have\n\t\texpired from the story history, on the other hand, are tallied.\n\t*/\n\tfunction turns() {\n\t\treturn State.turns;\n\t}\n\n\t/*\n\t\tReturns a reference to the current story $variables store.\n\t*/\n\tfunction variables() {\n\t\treturn State.variables;\n\t}\n\n\t/*\n\t\tReturns the number of times that the passage with the given title exists within the story\n\t\thistory.  If multiple passage titles are given, returns the lowest count.\n\t*/\n\tfunction visited(/* variadic */) {\n\t\tif (State.isEmpty()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments.length === 0 ? [State.passage] : arguments);\n\t\tconst played  = State.passages;\n\t\tlet count = State.turns;\n\n\t\tfor (let i = 0, iend = needles.length; i < iend && count > 0; ++i) {\n\t\t\tcount = Math.min(count, played.count(needles[i]));\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/*\n\t\tReturns the number of passages within the story history which are tagged with all of the given tags.\n\t*/\n\tfunction visitedTags(/* variadic */) {\n\t\tif (arguments.length === 0) {\n\t\t\tthrow new Error('visitedTags called with insufficient parameters');\n\t\t}\n\n\t\tif (State.isEmpty()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst needles = Array.prototype.concat.apply([], arguments);\n\t\tconst nLength = needles.length;\n\t\tconst played  = State.passages;\n\t\tconst seen    = new Map();\n\t\tlet count = 0;\n\n\t\tfor (let i = 0, iend = played.length; i < iend; ++i) {\n\t\t\tconst title = played[i];\n\n\t\t\tif (seen.has(title)) {\n\t\t\t\tif (seen.get(title)) {\n\t\t\t\t\t++count;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst tags = Story.get(title).tags;\n\n\t\t\t\tif (tags.length > 0) {\n\t\t\t\t\tlet found = 0;\n\n\t\t\t\t\tfor (let j = 0; j < nLength; ++j) {\n\t\t\t\t\t\tif (tags.includes(needles[j])) {\n\t\t\t\t\t\t\t++found;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (found === nLength) {\n\t\t\t\t\t\t++count;\n\t\t\t\t\t\tseen.set(title, true);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tseen.set(title, false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/* eslint-enable no-unused-vars */\n\n\n\t/*******************************************************************************************************************\n\t\tImport Functions.\n\t*******************************************************************************************************************/\n\tvar { // eslint-disable-line no-var\n\t\t/* eslint-disable no-unused-vars */\n\t\timportScripts,\n\t\timportStyles\n\t\t/* eslint-enable no-unused-vars */\n\t} = (() => {\n\t\t// Slugify the given URL.\n\t\tfunction slugifyUrl(url) {\n\t\t\treturn Util.parseUrl(url).path\n\t\t\t\t.replace(/^[^\\w]+|[^\\w]+$/g, '')\n\t\t\t\t.replace(/[^\\w]+/g, '-')\n\t\t\t\t.toLocaleLowerCase();\n\t\t}\n\n\t\t// Add a <script> element which will load the script from the given URL.\n\t\tfunction addScript(url) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t/*\n\t\t\t\t\tWARNING: The ordering of the code within this function is important,\n\t\t\t\t\tas some browsers don't play well with different arrangements, so\n\t\t\t\t\tbe careful when mucking around with it.\n\n\t\t\t\t\tThe best supported ordering seems be: events → DOM append → attributes.\n\t\t\t\t*/\n\t\t\t\tjQuery(document.createElement('script'))\n\t\t\t\t\t.one('load abort error', ev => {\n\t\t\t\t\t\tjQuery(ev.target).off();\n\n\t\t\t\t\t\tif (ev.type === 'load') {\n\t\t\t\t\t\t\tresolve(ev.target);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treject(new Error(`importScripts failed to load the script \"${url}\".`));\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo(document.head)\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid   : `script-imported-${slugifyUrl(url)}`,\n\t\t\t\t\t\ttype : 'text/javascript',\n\t\t\t\t\t\tsrc  : url\n\t\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\t// Add a <link> element which will load the stylesheet from the given URL.\n\t\tfunction addStyle(url) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t/*\n\t\t\t\t\tWARNING: The ordering of the code within this function is important,\n\t\t\t\t\tas some browsers don't play well with different arrangements, so\n\t\t\t\t\tbe careful when mucking around with it.\n\n\t\t\t\t\tThe best supported ordering seems be: events → DOM append → attributes.\n\t\t\t\t*/\n\t\t\t\tjQuery(document.createElement('link'))\n\t\t\t\t\t.one('load abort error', ev => {\n\t\t\t\t\t\tjQuery(ev.target).off();\n\n\t\t\t\t\t\tif (ev.type === 'load') {\n\t\t\t\t\t\t\tresolve(ev.target);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treject(new Error(`importStyles failed to load the stylesheet \"${url}\".`));\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo(document.head)\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid   : `style-imported-${slugifyUrl(url)}`,\n\t\t\t\t\t\trel  : 'stylesheet',\n\t\t\t\t\t\thref : url\n\t\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\t// Turn a list of callbacks into a sequential chain of `Promise` objects.\n\t\tfunction sequence(callbacks) {\n\t\t\treturn callbacks.reduce((seq, fn) => seq = seq.then(fn), Promise.resolve()); // eslint-disable-line no-param-reassign\n\t\t}\n\n\t\t/*\n\t\t\tImport scripts from a URL.\n\t\t*/\n\t\tfunction importScripts(...urls) {\n\t\t\treturn Promise.all(urls.map(oneOrSeries => {\n\t\t\t\t// Array of URLs to be imported in sequence.\n\t\t\t\tif (Array.isArray(oneOrSeries)) {\n\t\t\t\t\treturn sequence(oneOrSeries.map(url => () => addScript(url)));\n\t\t\t\t}\n\n\t\t\t\t// Single URL to be imported.\n\t\t\t\treturn addScript(oneOrSeries);\n\t\t\t}));\n\t\t}\n\n\t\t/*\n\t\t\tImport stylesheets from a URL.\n\t\t*/\n\t\tfunction importStyles(...urls) {\n\t\t\treturn Promise.all(urls.map(oneOrSeries => {\n\t\t\t\t// Array of URLs to be imported in sequence.\n\t\t\t\tif (Array.isArray(oneOrSeries)) {\n\t\t\t\t\treturn sequence(oneOrSeries.map(url => () => addStyle(url)));\n\t\t\t\t}\n\n\t\t\t\t// Single URL to be imported.\n\t\t\t\treturn addStyle(oneOrSeries);\n\t\t\t}));\n\t\t}\n\n\t\t// Exports.\n\t\treturn {\n\t\t\timportScripts,\n\t\t\timportStyles\n\t\t};\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tParsing Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tReturns the given string after converting all TwineScript syntactical sugars to\n\t\ttheir native JavaScript counterparts.\n\t*/\n\tconst parse = (() => {\n\t\tconst parseMap = Object.freeze({\n\t\t\t/* eslint-disable quote-props */\n\t\t\t// Story $variable sigil-prefix.\n\t\t\t'$'     : 'State.variables.',\n\t\t\t// Temporary _variable sigil-prefix.\n\t\t\t'_'     : 'State.temporary.',\n\t\t\t// Assignment operators.\n\t\t\t'to'    : '=',\n\t\t\t// Equality operators.\n\t\t\t'eq'    : '==',\n\t\t\t'neq'   : '!=',\n\t\t\t'is'    : '===',\n\t\t\t'isnot' : '!==',\n\t\t\t// Relational operators.\n\t\t\t'gt'    : '>',\n\t\t\t'gte'   : '>=',\n\t\t\t'lt'    : '<',\n\t\t\t'lte'   : '<=',\n\t\t\t// Logical operators.\n\t\t\t'and'   : '&&',\n\t\t\t'or'    : '||',\n\t\t\t// Unary operators.\n\t\t\t'not'   : '!',\n\t\t\t'def'   : '\"undefined\" !== typeof',\n\t\t\t'ndef'  : '\"undefined\" === typeof'\n\t\t\t/* eslint-enable quote-props */\n\t\t});\n\t\tconst parseRe = new RegExp([\n\t\t\t'(\"\"|\\'\\')',                                          // 1=Empty quotes\n\t\t\t'(\"(?:\\\\\\\\.|[^\"\\\\\\\\])+\")',                            // 2=Double quoted, non-empty\n\t\t\t\"('(?:\\\\\\\\.|[^'\\\\\\\\])+')\",                            // 3=Single quoted, non-empty\n\t\t\t'([=+\\\\-*\\\\/%<>&\\\\|\\\\^~!?:,;\\\\(\\\\)\\\\[\\\\]{}]+)',       // 4=Operator delimiters\n\t\t\t'([^\"\\'=+\\\\-*\\\\/%<>&\\\\|\\\\^~!?:,;\\\\(\\\\)\\\\[\\\\]{}\\\\s]+)' // 5=Barewords\n\t\t].join('|'), 'g');\n\t\tconst varTest = new RegExp(`^${Patterns.variable}`);\n\n\t\tfunction parse(rawCodeString) {\n\t\t\tif (parseRe.lastIndex !== 0) {\n\t\t\t\tthrow new RangeError('Scripting.parse last index is non-zero at start');\n\t\t\t}\n\n\t\t\tlet code  = rawCodeString;\n\t\t\tlet match;\n\n\t\t\twhile ((match = parseRe.exec(code)) !== null) {\n\t\t\t\t// no-op: Empty quotes | Double quoted | Single quoted | Operator delimiters\n\n\t\t\t\t/*\n\t\t\t\t\tBarewords.\n\t\t\t\t*/\n\t\t\t\tif (match[5]) {\n\t\t\t\t\tlet token = match[5];\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is simply a dollar-sign or underscore, then it's either\n\t\t\t\t\t\tjust the raw character or, probably, a function alias, so skip it.\n\t\t\t\t\t*/\n\t\t\t\t\tif (token === '$' || token === '_') {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is a story $variable or temporary _variable, reset it\n\t\t\t\t\t\tto just its sigil—for later mapping.\n\t\t\t\t\t*/\n\t\t\t\t\telse if (varTest.test(token)) {\n\t\t\t\t\t\ttoken = token[0];\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the token is `is`, check to see if it's followed by `not`, if so,\n\t\t\t\t\t\tconvert them into the `isnot` operator.\n\n\t\t\t\t\t\tNOTE: This is a safety feature, since `$a is not $b` probably sounds\n\t\t\t\t\t\treasonable to most users.\n\t\t\t\t\t*/\n\t\t\t\t\telse if (token === 'is') {\n\t\t\t\t\t\tconst start = parseRe.lastIndex;\n\t\t\t\t\t\tconst part  = code.slice(start);\n\n\t\t\t\t\t\tif (/^\\s+not\\b/.test(part)) {\n\t\t\t\t\t\t\tcode = code.splice(start, part.search(/\\S/));\n\t\t\t\t\t\t\ttoken = 'isnot';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tIf the finalized token has a mapping, replace it within the code string\n\t\t\t\t\t\twith its counterpart.\n\n\t\t\t\t\t\tNOTE: We must use `parseMap.hasOwnProperty(token)` here, rather than\n\t\t\t\t\t\tsimply using something like `parseMap[token]`, otherwise tokens which\n\t\t\t\t\t\tmatch properties from the prototype chain will cause shenanigans.\n\t\t\t\t\t*/\n\t\t\t\t\tif (parseMap.hasOwnProperty(token)) {\n\t\t\t\t\t\tcode = code.splice(\n\t\t\t\t\t\t\tmatch.index,    // starting index\n\t\t\t\t\t\t\ttoken.length,   // replace how many\n\t\t\t\t\t\t\tparseMap[token] // replacement string\n\t\t\t\t\t\t);\n\t\t\t\t\t\tparseRe.lastIndex += parseMap[token].length - token.length;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn code;\n\t\t}\n\n\t\treturn parse;\n\t})();\n\n\n\t/*******************************************************************************************************************\n\t\tEval Functions.\n\t*******************************************************************************************************************/\n\t/* eslint-disable no-eval, no-extra-parens, no-unused-vars */\n\t/*\n\t\tEvaluates the given JavaScript code and returns the result, throwing if there were errors.\n\t*/\n\tfunction evalJavaScript(code, output) {\n\t\treturn (function (code, output) {\n\t\t\treturn eval(code);\n\t\t}).call(output ? { output } : null, String(code), output);\n\t}\n\n\t/*\n\t\tEvaluates the given TwineScript code and returns the result, throwing if there were errors.\n\t*/\n\tfunction evalTwineScript(code, output) {\n\t\treturn (function (code, output) {\n\t\t\treturn eval(code);\n\t\t}).call(output ? { output } : null, parse(String(code)), output);\n\t}\n\t/* eslint-enable no-eval, no-extra-parens, no-unused-vars */\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tparse           : { value : parse },\n\t\tevalJavaScript  : { value : evalJavaScript },\n\t\tevalTwineScript : { value : evalTwineScript }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/lexer.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n\nvar { // eslint-disable-line no-var\n\t/* eslint-disable no-unused-vars */\n\tEOF,\n\tLexer\n\t/* eslint-enable no-unused-vars */\n} = (() => {\n\t'use strict';\n\n\t// End of file (string, actually).\n\tconst EOF = -1;\n\n\n\t/*******************************************************************************************************************\n\t\tLexer Class.\n\t*******************************************************************************************************************/\n\tclass Lexer {\n\t\tconstructor(source, initialState) {\n\t\t\tif (arguments.length < 2) {\n\t\t\t\tthrow new Error('Lexer constructor called with too few parameters (source:string , initialState:function)');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tthis.source  → the string to be scanned\n\t\t\t\tthis.initial → initial state\n\t\t\t\tthis.state   → current state\n\t\t\t\tthis.start   → start position of an item\n\t\t\t\tthis.pos     → current position in the source string\n\t\t\t\tthis.depth   → current brace/bracket/parenthesis nesting depth\n\t\t\t\tthis.items   → scanned item queue\n\t\t\t\tthis.data    → lexing data\n\t\t\t*/\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : source\n\t\t\t\t},\n\n\t\t\t\tinitial : {\n\t\t\t\t\tvalue : initialState\n\t\t\t\t},\n\n\t\t\t\tstate : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : initialState\n\t\t\t\t},\n\n\t\t\t\tstart : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\tpos : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\tdepth : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\titems : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : []\n\t\t\t\t},\n\n\t\t\t\tdata : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : {}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treset() {\n\t\t\tthis.state  = this.initial;\n\t\t\tthis.start  = 0;\n\t\t\tthis.pos    = 0;\n\t\t\tthis.depth  = 0;\n\t\t\tthis.items  = [];\n\t\t\tthis.data   = {};\n\t\t}\n\n\t\trun() {\n\t\t\t// scan the source string until no states remain\n\t\t\twhile (this.state !== null) {\n\t\t\t\tthis.state = this.state(this);\n\t\t\t}\n\n\t\t\t// return the array of items\n\t\t\treturn this.items;\n\t\t}\n\n\t\tnextItem() {\n\t\t\t// scan the source string until we have an item or no states remain\n\t\t\twhile (this.items.length === 0 && this.state !== null) {\n\t\t\t\tthis.state = this.state(this);\n\t\t\t}\n\n\t\t\t// return the current item\n\t\t\treturn this.items.shift();\n\t\t}\n\n\t\tnext() {\n\t\t\tif (this.pos >= this.source.length) {\n\t\t\t\treturn EOF;\n\t\t\t}\n\n\t\t\treturn this.source[this.pos++];\n\t\t}\n\n\t\tpeek() {\n\t\t\tif (this.pos >= this.source.length) {\n\t\t\t\treturn EOF;\n\t\t\t}\n\n\t\t\treturn this.source[this.pos];\n\t\t}\n\n\t\tbackup(num) {\n\t\t\t// if (num) {\n\t\t\t// \tthis.pos -= num;\n\t\t\t// }\n\t\t\t// else {\n\t\t\t// \t--this.pos;\n\t\t\t// }\n\t\t\tthis.pos -= num || 1;\n\t\t}\n\n\t\tforward(num) {\n\t\t\t// if (num) {\n\t\t\t// \tthis.pos += num;\n\t\t\t// }\n\t\t\t// else {\n\t\t\t// \t++this.pos;\n\t\t\t// }\n\t\t\tthis.pos += num || 1;\n\t\t}\n\n\t\tignore() {\n\t\t\tthis.start = this.pos;\n\t\t}\n\n\t\taccept(valid) {\n\t\t\tconst ch = this.next();\n\n\t\t\tif (ch === EOF) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (valid.includes(ch)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t\treturn false;\n\t\t}\n\n\t\tacceptRe(validRe) {\n\t\t\tconst ch = this.next();\n\n\t\t\tif (ch === EOF) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (validRe.test(ch)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t\treturn false;\n\t\t}\n\n\t\tacceptRun(valid) {\n\t\t\tfor (;;) {\n\t\t\t\tconst ch = this.next();\n\n\t\t\t\tif (ch === EOF) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!valid.includes(ch)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t}\n\n\t\tacceptRunRe(validRe) {\n\t\t\tfor (;;) {\n\t\t\t\tconst ch = this.next();\n\n\t\t\t\tif (ch === EOF) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!validRe.test(ch)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.backup();\n\t\t}\n\n\t\temit(type) {\n\t\t\tthis.items.push({\n\t\t\t\ttype,\n\t\t\t\ttext  : this.source.slice(this.start, this.pos),\n\t\t\t\tstart : this.start,\n\t\t\t\tpos   : this.pos\n\t\t\t});\n\t\t\tthis.start = this.pos;\n\t\t}\n\n\t\terror(type, message) {\n\t\t\tif (arguments.length < 2) {\n\t\t\t\tthrow new Error('Lexer.prototype.error called with too few parameters (type:number , message:string)');\n\t\t\t}\n\n\t\t\tthis.items.push({\n\t\t\t\ttype,\n\t\t\t\tmessage,\n\t\t\t\ttext  : this.source.slice(this.start, this.pos),\n\t\t\t\tstart : this.start,\n\t\t\t\tpos   : this.pos\n\t\t\t});\n\t\t\treturn null;\n\t\t}\n\n\t\tstatic enumFromNames(names) {\n\t\t\tconst obj = names.reduce((obj, name, i) => {\n\t\t\t\tobj[name] = i; // eslint-disable-line no-param-reassign\n\t\t\t\treturn obj;\n\t\t\t}, {});\n\t\t\treturn Object.freeze(Object.assign(Object.create(null), obj));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn {\n\t\tEOF,\n\t\tLexer\n\t};\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/wikifier.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, EOF, Engine, Lexer, Patterns, Scripting, State, Story, TempState, Util, convertBreaks,\n\t       errorPrologRegExp\n*/\n\n/*\n\tTODO: The Wikifier, and associated code, could stand to receive a serious refactoring.\n*/\n/* eslint-disable max-len */\nvar Wikifier = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Wikifier call depth.\n\tlet _callDepth = 0;\n\n\n\t/*******************************************************************************************************************\n\t\tWikifier Class.\n\t*******************************************************************************************************************/\n\tclass Wikifier {\n\t\tconstructor(destination, source, options) {\n\t\t\tif (Wikifier.Parser.Profile.isEmpty()) {\n\t\t\t\tWikifier.Parser.Profile.compile();\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// General Wikifier properties.\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : String(source)\n\t\t\t\t},\n\n\t\t\t\toptions : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : Object.assign({\n\t\t\t\t\t\tprofile : 'all'\n\t\t\t\t\t}, options)\n\t\t\t\t},\n\n\t\t\t\tnextMatch : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : 0\n\t\t\t\t},\n\n\t\t\t\toutput : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t// Macro parser ('macro') related properties.\n\t\t\t\t_rawArgs : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : ''\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// No destination specified.  Create a fragment to act as the output buffer.\n\t\t\tif (destination == null) { // lazy equality for null\n\t\t\t\tthis.output = document.createDocumentFragment();\n\t\t\t}\n\n\t\t\t// jQuery-wrapped destination.  Grab the first element.\n\t\t\telse if (destination.jquery) { // cannot use `hasOwnProperty()` here as `jquery` is from jQuery's prototype\n\t\t\t\tthis.output = destination[0];\n\t\t\t}\n\n\t\t\t// Normal destination.\n\t\t\telse {\n\t\t\t\tthis.output = destination;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tWikify the source into the output buffer element, possibly converting line\n\t\t\t\tbreaks into paragraphs.\n\n\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\tto ensure that the call depth is properly restored in the event that an\n\t\t\t\tuncaught exception is thrown during the call to `subWikify()`.\n\t\t\t*/\n\t\t\ttry {\n\t\t\t\t++_callDepth;\n\n\t\t\t\tthis.subWikify(this.output);\n\n\t\t\t\t// Limit line break conversion to non-recursive calls.\n\t\t\t\tif (_callDepth === 1 && Config.cleanupWikifierOutput) {\n\t\t\t\t\tconvertBreaks(this.output);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\t--_callDepth;\n\t\t\t}\n\t\t}\n\n\t\tsubWikify(output, terminator, options) {\n\t\t\t// Cache and temporarily replace the current output buffer.\n\t\t\tconst oldOutput = this.output;\n\t\t\tthis.output = output;\n\n\t\t\tlet newOptions;\n\t\t\tlet oldOptions;\n\n\t\t\t// Parser option overrides.\n\t\t\tif (Wikifier.Option.length > 0) {\n\t\t\t\tnewOptions = Object.assign(newOptions || {}, Wikifier.Option.options);\n\t\t\t}\n\t\t\t// Local parameter option overrides.\n\t\t\tif (options !== null && typeof options === 'object') {\n\t\t\t\tnewOptions = Object.assign(newOptions || {}, options);\n\t\t\t}\n\t\t\t// If new options exist, cache and temporarily replace the current options.\n\t\t\tif (newOptions) {\n\t\t\t\toldOptions = this.options;\n\t\t\t\tthis.options = Object.assign({}, this.options, newOptions);\n\t\t\t}\n\n\t\t\tconst parsersProfile   = Wikifier.Parser.Profile.get(this.options.profile);\n\t\t\tconst terminatorRegExp = terminator\n\t\t\t\t? new RegExp(`(?:${terminator})`, this.options.ignoreTerminatorCase ? 'gim' : 'gm')\n\t\t\t\t: null;\n\t\t\tlet terminatorMatch;\n\t\t\tlet parserMatch;\n\n\t\t\tdo {\n\t\t\t\t// Prepare the RegExp match positions.\n\t\t\t\tparsersProfile.parserRegExp.lastIndex = this.nextMatch;\n\n\t\t\t\tif (terminatorRegExp) {\n\t\t\t\t\tterminatorRegExp.lastIndex = this.nextMatch;\n\t\t\t\t}\n\n\t\t\t\t// Get the first matches.\n\t\t\t\tparserMatch     = parsersProfile.parserRegExp.exec(this.source);\n\t\t\t\tterminatorMatch = terminatorRegExp ? terminatorRegExp.exec(this.source) : null;\n\n\t\t\t\t// Try for a terminator match, unless there's a closer parser match.\n\t\t\t\tif (terminatorMatch && (!parserMatch || terminatorMatch.index <= parserMatch.index)) {\n\t\t\t\t\t// Output any text before the match.\n\t\t\t\t\tif (terminatorMatch.index > this.nextMatch) {\n\t\t\t\t\t\tthis.outputText(this.output, this.nextMatch, terminatorMatch.index);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set the match parameters.\n\t\t\t\t\tthis.matchStart  = terminatorMatch.index;\n\t\t\t\t\tthis.matchLength = terminatorMatch[0].length;\n\t\t\t\t\tthis.matchText   = terminatorMatch[0];\n\t\t\t\t\tthis.nextMatch   = terminatorRegExp.lastIndex;\n\n\t\t\t\t\t// Restore the original output buffer and options.\n\t\t\t\t\tthis.output = oldOutput;\n\n\t\t\t\t\tif (oldOptions) {\n\t\t\t\t\t\tthis.options = oldOptions;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Exit.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Try for a parser match.\n\t\t\t\telse if (parserMatch) {\n\t\t\t\t\t// Output any text before the match.\n\t\t\t\t\tif (parserMatch.index > this.nextMatch) {\n\t\t\t\t\t\tthis.outputText(this.output, this.nextMatch, parserMatch.index);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set the match parameters.\n\t\t\t\t\tthis.matchStart  = parserMatch.index;\n\t\t\t\t\tthis.matchLength = parserMatch[0].length;\n\t\t\t\t\tthis.matchText   = parserMatch[0];\n\t\t\t\t\tthis.nextMatch   = parsersProfile.parserRegExp.lastIndex;\n\n\t\t\t\t\t// Figure out which parser matched.\n\t\t\t\t\tlet matchingParser;\n\n\t\t\t\t\tfor (let i = 1, iend = parserMatch.length; i < iend; ++i) {\n\t\t\t\t\t\tif (parserMatch[i]) {\n\t\t\t\t\t\t\tmatchingParser = i - 1;\n\t\t\t\t\t\t\tbreak; // stop once we've found the matching parser\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Call the parser.\n\t\t\t\t\tparsersProfile.parsers[matchingParser].handler(this);\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} while (terminatorMatch || parserMatch);\n\n\t\t\t// Output any text after the last match.\n\t\t\tif (TempState.break == null) { // lazy equality for null\n\t\t\t\tif (this.nextMatch < this.source.length) {\n\t\t\t\t\tthis.outputText(this.output, this.nextMatch, this.source.length);\n\t\t\t\t\tthis.nextMatch = this.source.length;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// In case of <<break>>/<<continue>>, remove the last <br>.\n\t\t\telse if (\n\t\t\t\t   this.output.lastChild\n\t\t\t\t&& this.output.lastChild.nodeType === Node.ELEMENT_NODE\n\t\t\t\t&& this.output.lastChild.nodeName.toUpperCase() === 'BR'\n\t\t\t) {\n\t\t\t\tjQuery(this.output.lastChild).remove();\n\t\t\t}\n\n\t\t\t// Restore the original output buffer and options.\n\t\t\tthis.output = oldOutput;\n\n\t\t\tif (oldOptions) {\n\t\t\t\tthis.options = oldOptions;\n\t\t\t}\n\t\t}\n\n\t\toutputText(destination, startPos, endPos) {\n\t\t\tdestination.appendChild(document.createTextNode(this.source.substring(startPos, endPos)));\n\t\t}\n\n\t\t/*\n\t\t\t[DEPRECATED] Meant to be called by legacy macros, this returns the raw, unprocessed\n\t\t\ttext given to the currently executing macro.\n\t\t*/\n\t\trawArgs() {\n\t\t\treturn this._rawArgs;\n\t\t}\n\n\t\t/*\n\t\t\t[DEPRECATED] Meant to be called by legacy macros, this returns the text given to\n\t\t\tthe currently executing macro after doing TwineScript-to-JavaScript transformations.\n\t\t*/\n\t\tfullArgs() {\n\t\t\treturn Scripting.parse(this._rawArgs);\n\t\t}\n\n\t\t/*\n\t\t\tReturns the output generated by wikifying the given text, throwing if there were errors.\n\t\t*/\n\t\tstatic wikifyEval(text) {\n\t\t\tconst output = document.createDocumentFragment();\n\n\t\t\tnew Wikifier(output, text);\n\n\t\t\tconst errors = output.querySelector('.error');\n\n\t\t\tif (errors !== null) {\n\t\t\t\tthrow new Error(errors.textContent.replace(errorPrologRegExp, ''));\n\t\t\t}\n\n\t\t\treturn output;\n\t\t}\n\n\t\t/*\n\t\t\tCreate and return an internal link.\n\t\t*/\n\t\tstatic createInternalLink(destination, passage, text, callback) {\n\t\t\tconst $link = jQuery(document.createElement('a'));\n\n\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t$link.attr('data-passage', passage);\n\n\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t$link.addClass('link-internal');\n\n\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t$link.addClass('link-visited');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$link.addClass('link-broken');\n\t\t\t\t}\n\n\t\t\t\t$link.ariaClick({ one : true }, () => {\n\t\t\t\t\tif (typeof callback === 'function') {\n\t\t\t\t\t\tcallback();\n\t\t\t\t\t}\n\n\t\t\t\t\tEngine.play(passage);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (text) {\n\t\t\t\t$link.append(document.createTextNode(text));\n\t\t\t}\n\n\t\t\tif (destination) {\n\t\t\t\t$link.appendTo(destination);\n\t\t\t}\n\n\t\t\t// For legacy-compatibility we must return the DOM node.\n\t\t\treturn $link[0];\n\t\t}\n\n\t\t/*\n\t\t\tCreate and return an external link.\n\t\t*/\n\t\tstatic createExternalLink(destination, url, text) {\n\t\t\tconst $link = jQuery(document.createElement('a'))\n\t\t\t\t.attr('target', '_blank')\n\t\t\t\t.addClass('link-external')\n\t\t\t\t.text(text)\n\t\t\t\t.appendTo(destination);\n\n\t\t\tif (url != null) { // lazy equality for null\n\t\t\t\t$link.attr({\n\t\t\t\t\thref     : url,\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// For legacy-compatibility we must return the DOM node.\n\t\t\treturn $link[0];\n\t\t}\n\n\t\t/*\n\t\t\tReturns whether the given link source is external (probably).\n\t\t*/\n\t\tstatic isExternalLink(link) {\n\t\t\tif (Story.has(link)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst urlRegExp = new RegExp(`^${Patterns.url}`, 'gim');\n\t\t\treturn urlRegExp.test(link) || /[/.?#]/.test(link);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tOption Static Object.\n\t*******************************************************************************************************************/\n\tObject.defineProperty(Wikifier, 'Option', {\n\t\tvalue : (() => {\n\t\t\t// Options array (stack).\n\t\t\tlet _optionsStack = [];\n\n\n\t\t\t/*\n\t\t\t\tGlobalOption Functions.\n\t\t\t*/\n\t\t\tfunction optionLength() {\n\t\t\t\treturn _optionsStack.length;\n\t\t\t}\n\n\t\t\tfunction optionGetter() {\n\t\t\t\treturn Object.assign({}, ..._optionsStack);\n\t\t\t}\n\n\t\t\tfunction optionClear() {\n\t\t\t\t_optionsStack = [];\n\t\t\t}\n\n\t\t\tfunction optionGet(idx) {\n\t\t\t\treturn _optionsStack[idx];\n\t\t\t}\n\n\t\t\tfunction optionPop() {\n\t\t\t\treturn _optionsStack.pop();\n\t\t\t}\n\n\t\t\tfunction optionPush(options) {\n\t\t\t\tif (typeof options !== 'object' || options === null) {\n\t\t\t\t\tthrow new TypeError(`Wikifier.Option.push options parameter must be an object (received: ${Util.getType(options)})`);\n\t\t\t\t}\n\n\t\t\t\treturn _optionsStack.push(options);\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tExports.\n\t\t\t*/\n\t\t\treturn Object.freeze(Object.defineProperties({}, {\n\t\t\t\tlength  : { get : optionLength },\n\t\t\t\toptions : { get : optionGetter },\n\t\t\t\tclear   : { value : optionClear },\n\t\t\t\tget     : { value : optionGet },\n\t\t\t\tpop     : { value : optionPop },\n\t\t\t\tpush    : { value : optionPush }\n\t\t\t}));\n\t\t})()\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tParser Static Object.\n\t*******************************************************************************************************************/\n\tObject.defineProperty(Wikifier, 'Parser', {\n\t\tvalue : (() => {\n\t\t\t// Parser definition array.  Ordering matters, so this must be an ordered list.\n\t\t\tconst _parsers = [];\n\n\t\t\t// Parser profiles object.\n\t\t\tlet _profiles;\n\n\n\t\t\t/*\n\t\t\t\tParser Functions.\n\t\t\t*/\n\t\t\tfunction parsersGetter() {\n\t\t\t\treturn _parsers;\n\t\t\t}\n\n\t\t\tfunction parsersAdd(parser) {\n\t\t\t\t// Parser object sanity checks.\n\t\t\t\tif (typeof parser !== 'object') {\n\t\t\t\t\tthrow new Error('Wikifier.Parser.add parser parameter must be an object');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('name')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"name\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.name !== 'string') {\n\t\t\t\t\tthrow new Error('parser object \"name\" property must be a string');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('match')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"match\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.match !== 'string') {\n\t\t\t\t\tthrow new Error('parser object \"match\" property must be a string');\n\t\t\t\t}\n\n\t\t\t\tif (!parser.hasOwnProperty('handler')) {\n\t\t\t\t\tthrow new Error('parser object missing required \"handler\" property');\n\t\t\t\t}\n\t\t\t\telse if (typeof parser.handler !== 'function') {\n\t\t\t\t\tthrow new Error('parser object \"handler\" property must be a function');\n\t\t\t\t}\n\n\t\t\t\tif (parser.hasOwnProperty('profiles') && !Array.isArray(parser.profiles)) {\n\t\t\t\t\tthrow new Error('parser object \"profiles\" property must be an array');\n\t\t\t\t}\n\n\t\t\t\t// Check for an existing parser with the same name.\n\t\t\t\tif (parsersHas(parser.name)) {\n\t\t\t\t\tthrow new Error(`cannot clobber existing parser \"${parser.name}\"`);\n\t\t\t\t}\n\n\t\t\t\t// Add the parser to the end of the array.\n\t\t\t\t_parsers.push(parser);\n\t\t\t}\n\n\t\t\tfunction parsersDelete(name) {\n\t\t\t\tconst parser = _parsers.find(parser => parser.name === name);\n\n\t\t\t\tif (parser) {\n\t\t\t\t\t_parsers.delete(parser);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction parsersIsEmpty() {\n\t\t\t\treturn _parsers.length === 0;\n\t\t\t}\n\n\t\t\tfunction parsersHas(name) {\n\t\t\t\treturn !!_parsers.find(parser => parser.name === name);\n\t\t\t}\n\n\t\t\tfunction parsersGet(name) {\n\t\t\t\treturn _parsers.find(parser => parser.name === name) || null;\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tParser Profile Functions.\n\t\t\t*/\n\t\t\tfunction profilesGetter() {\n\t\t\t\treturn _profiles;\n\t\t\t}\n\n\t\t\tfunction profilesCompile() {\n\t\t\t\tif (DEBUG) { console.log('[Wikifier.Parser/profilesCompile()]'); }\n\n\t\t\t\tconst all  = _parsers;\n\t\t\t\tconst core = all.filter(parser => !Array.isArray(parser.profiles) || parser.profiles.includes('core'));\n\n\t\t\t\t_profiles = Object.freeze({\n\t\t\t\t\tall : {\n\t\t\t\t\t\tparsers      : all,\n\t\t\t\t\t\tparserRegExp : new RegExp(all.map(parser => `(${parser.match})`).join('|'), 'gm')\n\t\t\t\t\t},\n\t\t\t\t\tcore : {\n\t\t\t\t\t\tparsers      : core,\n\t\t\t\t\t\tparserRegExp : new RegExp(core.map(parser => `(${parser.match})`).join('|'), 'gm')\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\treturn _profiles;\n\t\t\t}\n\n\t\t\tfunction profilesIsEmpty() {\n\t\t\t\treturn typeof _profiles !== 'object' || Object.keys(_profiles).length === 0;\n\t\t\t}\n\n\t\t\tfunction profilesGet(profile) {\n\t\t\t\tif (typeof _profiles !== 'object' || !_profiles.hasOwnProperty(profile)) {\n\t\t\t\t\tthrow new Error(`nonexistent parser profile \"${profile}\"`);\n\t\t\t\t}\n\n\t\t\t\treturn _profiles[profile];\n\t\t\t}\n\n\t\t\tfunction profilesHas(profile) {\n\t\t\t\treturn typeof _profiles === 'object' && _profiles.hasOwnProperty(profile);\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t\tExports.\n\t\t\t*/\n\t\t\treturn Object.freeze(Object.defineProperties({}, {\n\t\t\t\t/*\n\t\t\t\t\tParser Containers.\n\t\t\t\t*/\n\t\t\t\tparsers : { get : parsersGetter },\n\n\t\t\t\t/*\n\t\t\t\t\tParser Functions.\n\t\t\t\t*/\n\t\t\t\tadd     : { value : parsersAdd },\n\t\t\t\tdelete  : { value : parsersDelete },\n\t\t\t\tisEmpty : { value : parsersIsEmpty },\n\t\t\t\thas     : { value : parsersHas },\n\t\t\t\tget     : { value : parsersGet },\n\n\t\t\t\t/*\n\t\t\t\t\tParser Profile.\n\t\t\t\t*/\n\t\t\t\tProfile : {\n\t\t\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tProfiles Containers.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tprofiles : { get : profilesGetter },\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tProfiles Functions.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tcompile : { value : profilesCompile },\n\t\t\t\t\t\tisEmpty : { value : profilesIsEmpty },\n\t\t\t\t\t\thas     : { value : profilesHas },\n\t\t\t\t\t\tget     : { value : profilesGet }\n\t\t\t\t\t}))\n\t\t\t\t}\n\t\t\t}));\n\t\t})()\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAdditional Static Properties.\n\t*******************************************************************************************************************/\n\tObject.defineProperties(Wikifier, {\n\t\thelpers : { value : {} },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tgetValue       : { value : State.getVar },              // SEE: `state.js`.\n\t\tsetValue       : { value : State.setVar },              // SEE: `state.js`.\n\t\tparse          : { value : Scripting.parse },           // SEE: `markup/scripting.js`.\n\t\tevalExpression : { value : Scripting.evalTwineScript }, // SEE: `markup/scripting.js`.\n\t\tevalStatements : { value : Scripting.evalTwineScript }, // SEE: `markup/scripting.js`.\n\t\ttextPrimitives : { value : Patterns }                   // SEE: `lib/patterns.js`.\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tHelper Static Methods.\n\t*******************************************************************************************************************/\n\tObject.defineProperties(Wikifier.helpers, {\n\t\tinlineCss : {\n\t\t\tvalue : (() => {\n\t\t\t\tconst lookaheadRe = new RegExp(Patterns.inlineCss, 'gm');\n\t\t\t\tconst idOrClassRe = new RegExp(`(${Patterns.cssIdOrClassSigil})(${Patterns.anyLetter}+)`, 'g');\n\n\t\t\t\tfunction helperInlineCss(w) {\n\t\t\t\t\tconst css = { classes : [], id : '', styles : {} };\n\t\t\t\t\tlet matched;\n\n\t\t\t\t\tdo {\n\t\t\t\t\t\tlookaheadRe.lastIndex = w.nextMatch;\n\n\t\t\t\t\t\tconst match = lookaheadRe.exec(w.source);\n\n\t\t\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\t\t\tif (matched) {\n\t\t\t\t\t\t\tif (match[1]) {\n\t\t\t\t\t\t\t\tcss.styles[Util.fromCssProperty(match[1])] = match[2].trim();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (match[3]) {\n\t\t\t\t\t\t\t\tcss.styles[Util.fromCssProperty(match[3])] = match[4].trim();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (match[5]) {\n\t\t\t\t\t\t\t\tlet subMatch;\n\n\t\t\t\t\t\t\t\tidOrClassRe.lastIndex = 0; // NOTE: Guard against buggy implementations.\n\n\t\t\t\t\t\t\t\twhile ((subMatch = idOrClassRe.exec(match[5])) !== null) {\n\t\t\t\t\t\t\t\t\tif (subMatch[1] === '.') {\n\t\t\t\t\t\t\t\t\t\tcss.classes.push(subMatch[2]);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tcss.id = subMatch[2];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tw.nextMatch = lookaheadRe.lastIndex; // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\t\t\t\t\t} while (matched);\n\n\t\t\t\t\treturn css;\n\t\t\t\t}\n\n\t\t\t\treturn helperInlineCss;\n\t\t\t})()\n\t\t},\n\n\t\tevalText : {\n\t\t\tvalue(text) {\n\t\t\t\tlet result;\n\n\t\t\t\ttry {\n\t\t\t\t\tresult = Scripting.evalTwineScript(text);\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tAttempt to prevent the leakage of auto-globals by enforcing that\n\t\t\t\t\t\tthe resultant value be either a string or a number.\n\n\t\t\t\t\t\tNOTE: This is not a foolproof solution to the problem of auto-global\n\t\t\t\t\t\tleakage.  Various auto-globals, which return strings or numbers, can\n\t\t\t\t\t\tstill leak through—e.g. `window.status` → string.\n\t\t\t\t\t*/\n\t\t\t\t\tswitch (typeof result) {\n\t\t\t\t\tcase 'string':\n\t\t\t\t\t\tif (result.trim() === '') {\n\t\t\t\t\t\t\tresult = text;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'number':\n\t\t\t\t\t\tresult = String(result);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tresult = text;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\tresult = text;\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}\n\t\t},\n\n\t\tevalPassageId : {\n\t\t\tvalue(passage) {\n\t\t\t\tif (passage == null || Story.has(passage)) { // lazy equality for null; `0` is a valid name, so we cannot simply evaluate `passage`\n\t\t\t\t\treturn passage;\n\t\t\t\t}\n\n\t\t\t\treturn Wikifier.helpers.evalText(passage);\n\t\t\t}\n\t\t},\n\n\t\thasBlockContext : {\n\t\t\tvalue(nodes) {\n\t\t\t\tconst hasGCS = typeof window.getComputedStyle === 'function';\n\n\t\t\t\tfor (let i = nodes.length - 1; i >= 0; --i) {\n\t\t\t\t\tconst node = nodes[i];\n\n\t\t\t\t\tswitch (node.nodeType) {\n\t\t\t\t\tcase Node.ELEMENT_NODE:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst tagName = node.nodeName.toUpperCase();\n\n\t\t\t\t\t\t\tif (tagName === 'BR') {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst styles = hasGCS ? window.getComputedStyle(node, null) : node.currentStyle;\n\n\t\t\t\t\t\t\tif (styles && styles.display) {\n\t\t\t\t\t\t\t\tif (styles.display === 'none') {\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn styles.display === 'block';\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tWebKit/Blink-based browsers do not attach any computed style\n\t\t\t\t\t\t\t\tinformation to elements until they're inserted into the DOM\n\t\t\t\t\t\t\t\t(and probably visible), not even the default browser styles\n\t\t\t\t\t\t\t\tand any user styles.  So, we make an assumption based on the\n\t\t\t\t\t\t\t\telement.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tswitch (tagName) {\n\t\t\t\t\t\t\tcase 'ADDRESS':\n\t\t\t\t\t\t\tcase 'ARTICLE':\n\t\t\t\t\t\t\tcase 'ASIDE':\n\t\t\t\t\t\t\tcase 'BLOCKQUOTE':\n\t\t\t\t\t\t\tcase 'CENTER':\n\t\t\t\t\t\t\tcase 'DIV':\n\t\t\t\t\t\t\tcase 'DL':\n\t\t\t\t\t\t\tcase 'FIGURE':\n\t\t\t\t\t\t\tcase 'FOOTER':\n\t\t\t\t\t\t\tcase 'FORM':\n\t\t\t\t\t\t\tcase 'H1':\n\t\t\t\t\t\t\tcase 'H2':\n\t\t\t\t\t\t\tcase 'H3':\n\t\t\t\t\t\t\tcase 'H4':\n\t\t\t\t\t\t\tcase 'H5':\n\t\t\t\t\t\t\tcase 'H6':\n\t\t\t\t\t\t\tcase 'HEADER':\n\t\t\t\t\t\t\tcase 'HR':\n\t\t\t\t\t\t\tcase 'MAIN':\n\t\t\t\t\t\t\tcase 'NAV':\n\t\t\t\t\t\t\tcase 'OL':\n\t\t\t\t\t\t\tcase 'P':\n\t\t\t\t\t\t\tcase 'PRE':\n\t\t\t\t\t\t\tcase 'SECTION':\n\t\t\t\t\t\t\tcase 'TABLE':\n\t\t\t\t\t\t\tcase 'UL':\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn false;\n\n\t\t\t\t\tcase Node.COMMENT_NODE:\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t},\n\n\t\tcreateShadowSetterCallback : {\n\t\t\tvalue : (() => {\n\t\t\t\tlet macroParser = null;\n\n\t\t\t\tfunction cacheMacroParser() {\n\t\t\t\t\tif (!macroParser) {\n\t\t\t\t\t\tmacroParser = Wikifier.Parser.get('macro');\n\n\t\t\t\t\t\tif (!macroParser) {\n\t\t\t\t\t\t\tthrow new Error('cannot find \"macro\" parser');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn macroParser;\n\t\t\t\t}\n\n\t\t\t\tfunction getMacroContextShadowView() {\n\t\t\t\t\tconst macro = macroParser || cacheMacroParser();\n\t\t\t\t\tconst view  = new Set();\n\n\t\t\t\t\tfor (let context = macro.context; context !== null; context = context.parent) {\n\t\t\t\t\t\tif (context._shadows) {\n\t\t\t\t\t\t\tcontext._shadows.forEach(name => view.add(name));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn [...view];\n\t\t\t\t}\n\n\t\t\t\tfunction helperCreateShadowSetterCallback(code) {\n\t\t\t\t\tconst shadowStore = {};\n\n\t\t\t\t\tgetMacroContextShadowView().forEach(varName => {\n\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\t\t\t\t\t});\n\n\t\t\t\t\treturn function () {\n\t\t\t\t\t\tconst shadowNames = Object.keys(shadowStore);\n\t\t\t\t\t\tconst valueCache  = shadowNames.length > 0 ? {} : null;\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t\t\tevaluation.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tCache the existing values of the variables to be shadowed and assign the\n\t\t\t\t\t\t\t\tshadow values.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tstore[varKey] = shadowStore[varName];\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t// Evaluate the JavaScript.\n\t\t\t\t\t\t\treturn Scripting.evalJavaScript(code);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t// Revert the variable shadowing.\n\t\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tUpdate the shadow store with the variable's current value, in case it\n\t\t\t\t\t\t\t\t\twas modified during the callback.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\n\t\t\t\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn helperCreateShadowSetterCallback;\n\t\t\t})()\n\t\t},\n\n\t\tparseSquareBracketedMarkup : {\n\t\t\tvalue : (() => {\n\t\t\t\t/* eslint-disable no-param-reassign */\n\t\t\t\tconst Item = Lexer.enumFromNames([ // lex item types object (pseudo-enumeration)\n\t\t\t\t\t'Error',     // error\n\t\t\t\t\t'DelimLTR',  // '|' or '->'\n\t\t\t\t\t'DelimRTL',  // '<-'\n\t\t\t\t\t'InnerMeta', // ']['\n\t\t\t\t\t'ImageMeta', // '[img[', '[<img[', or '[>img['\n\t\t\t\t\t'LinkMeta',  // '[['\n\t\t\t\t\t'Link',      // link destination\n\t\t\t\t\t'RightMeta', // ']]'\n\t\t\t\t\t'Setter',    // setter expression\n\t\t\t\t\t'Source',    // image source\n\t\t\t\t\t'Text'       // link text or image alt text\n\t\t\t\t]);\n\t\t\t\tconst Delim = Lexer.enumFromNames([ // delimiter state object (pseudo-enumeration)\n\t\t\t\t\t'None', // no delimiter encountered\n\t\t\t\t\t'LTR',  // '|' or '->'\n\t\t\t\t\t'RTL'   // '<-'\n\t\t\t\t]);\n\n\t\t\t\t// Lexing functions.\n\t\t\t\tfunction slurpQuote(lexer, endQuote) {\n\t\t\t\t\tloop: for (;;) {\n\t\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/* falls through */\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn EOF;\n\n\t\t\t\t\t\tcase endQuote:\n\t\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t\t}\n\n\t\t\t\t\treturn lexer.pos;\n\t\t\t\t}\n\n\t\t\t\tfunction lexLeftMeta(lexer) {\n\t\t\t\t\tif (!lexer.accept('[')) {\n\t\t\t\t\t\treturn lexer.error(Item.Error, 'malformed square-bracketed markup');\n\t\t\t\t\t}\n\n\t\t\t\t\t// Is link markup.\n\t\t\t\t\tif (lexer.accept('[')) {\n\t\t\t\t\t\tlexer.data.isLink = true;\n\t\t\t\t\t\tlexer.emit(Item.LinkMeta);\n\t\t\t\t\t}\n\n\t\t\t\t\t// May be image markup.\n\t\t\t\t\telse {\n\t\t\t\t\t\tlexer.accept('<>'); // aligner syntax\n\n\t\t\t\t\t\tif (!lexer.accept('Ii') || !lexer.accept('Mm') || !lexer.accept('Gg') || !lexer.accept('[')) {\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, 'malformed square-bracketed markup');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlexer.data.isLink = false;\n\t\t\t\t\t\tlexer.emit(Item.ImageMeta);\n\t\t\t\t\t}\n\n\t\t\t\t\tlexer.depth = 2; // account for both initial left square brackets\n\t\t\t\t\treturn lexCoreComponents;\n\t\t\t\t}\n\n\t\t\t\tfunction lexCoreComponents(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\t\t\t\t\tlet delim = Delim.None;\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tThis is not entirely reliable within sections that allow raw strings, since\n\t\t\t\t\t\t\t\tit's possible, however unlikely, for a raw string to contain unpaired double\n\t\t\t\t\t\t\t\tquotes.  The likelihood is low enough, however, that I'm deeming the risk as\n\t\t\t\t\t\t\t\tacceptable—for now, at least.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '|': // possible pipe ('|') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None) {\n\t\t\t\t\t\t\t\tdelim = Delim.LTR;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\tlexer.forward();\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimLTR);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '-': // possible right arrow ('->') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None && lexer.peek() === '>') {\n\t\t\t\t\t\t\t\tdelim = Delim.LTR;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimLTR);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '<': // possible left arrow ('<-') delimiter\n\t\t\t\t\t\t\tif (delim === Delim.None && lexer.peek() === '-') {\n\t\t\t\t\t\t\t\tdelim = Delim.RTL;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.DelimRTL);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tswitch (lexer.peek()) {\n\t\t\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\n\t\t\t\t\t\t\t\t\tif (delim === Delim.RTL) {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.InnerMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn lexer.data.isLink ? lexSetter : lexImageLink;\n\n\t\t\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\n\t\t\t\t\t\t\t\t\tif (delim === Delim.RTL) {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(Item.Text);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tlexer.emit(lexer.data.isLink ? Item.Link : Item.Source);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfunction lexImageLink(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tThis is not entirely reliable within sections that allow raw strings, since\n\t\t\t\t\t\t\t\tit's possible, however unlikely, for a raw string to contain unpaired double\n\t\t\t\t\t\t\t\tquotes.  The likelihood is low enough, however, that I'm deeming the risk as\n\t\t\t\t\t\t\t\tacceptable—for now, at least.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup link component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tswitch (lexer.peek()) {\n\t\t\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.Link);\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.InnerMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn lexSetter;\n\n\t\t\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.Link);\n\t\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfunction lexSetter(lexer) {\n\t\t\t\t\tconst what = lexer.data.isLink ? 'link' : 'image';\n\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\t\tcase EOF:\n\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\t\tcase '\"':\n\t\t\t\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated double quoted string in ${what} markup setter component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase \"'\":\n\t\t\t\t\t\t\tif (slurpQuote(lexer, \"'\") === EOF) {\n\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated single quoted string in ${what} markup setter component`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase ']':\n\t\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\t\tif (lexer.peek() !== ']') {\n\t\t\t\t\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t\t\tlexer.emit(Item.Setter);\n\t\t\t\t\t\t\t\tlexer.forward(2);\n\t\t\t\t\t\t\t\tlexer.emit(Item.RightMeta);\n\t\t\t\t\t\t\t\t// lexer.ignore();\n\t\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Parse function.\n\t\t\t\tfunction parseSquareBracketedMarkup(w) {\n\t\t\t\t\t// Initialize the lexer.\n\t\t\t\t\tconst lexer  = new Lexer(w.source, lexLeftMeta);\n\n\t\t\t\t\t// Set the initial positions within the source string.\n\t\t\t\t\tlexer.start = lexer.pos = w.matchStart;\n\n\t\t\t\t\t// Lex the raw argument string.\n\t\t\t\t\tconst markup = {};\n\t\t\t\t\tconst items  = lexer.run();\n\t\t\t\t\tconst last   = items.last();\n\n\t\t\t\t\tif (last && last.type === Item.Error) {\n\t\t\t\t\t\tmarkup.error = last.message;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\titems.forEach(item => {\n\t\t\t\t\t\t\tconst text = item.text.trim();\n\n\t\t\t\t\t\t\tswitch (item.type) {\n\t\t\t\t\t\t\tcase Item.ImageMeta:\n\t\t\t\t\t\t\t\tmarkup.isImage = true;\n\n\t\t\t\t\t\t\t\tif (text[1] === '<') {\n\t\t\t\t\t\t\t\t\tmarkup.align = 'left';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (text[1] === '>') {\n\t\t\t\t\t\t\t\t\tmarkup.align = 'right';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.LinkMeta:\n\t\t\t\t\t\t\t\tmarkup.isLink = true;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Link:\n\t\t\t\t\t\t\t\tif (text[0] === '~') {\n\t\t\t\t\t\t\t\t\tmarkup.forceInternal = true;\n\t\t\t\t\t\t\t\t\tmarkup.link = text.slice(1);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tmarkup.link = text;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Setter:\n\t\t\t\t\t\t\t\tmarkup.setter = text;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Source:\n\t\t\t\t\t\t\t\tmarkup.source = text;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase Item.Text:\n\t\t\t\t\t\t\t\tmarkup.text = text;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tmarkup.pos = lexer.pos;\n\t\t\t\t\treturn markup;\n\t\t\t\t}\n\n\t\t\t\treturn parseSquareBracketedMarkup;\n\t\t\t\t/* eslint-enable no-param-reassign */\n\t\t\t})()\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Wikifier;\n})();\n/* eslint-enable max-len */\n\n/***********************************************************************************************************************\n\n\tmarkup/parserlib.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, DebugView, EOF, Engine, Lexer, Macro, MacroContext, Patterns, Scripting, State, Story, Template,\n\t       Wikifier, toStringOrDefault, throwError\n*/\n/* eslint \"no-param-reassign\": [ 2, { \"props\" : false } ] */\n\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _verbatimTagHandler(w) {\n\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\tconst match = this.lookahead.exec(w.source);\n\n\t\tif (match && match.index === w.matchStart) {\n\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t.append(match[1])\n\t\t\t\t.appendTo(w.output);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tParsers.\n\t*******************************************************************************************************************/\n\tWikifier.Parser.add({\n\t\tname       : 'quoteByBlock',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^<<<\\\\n',\n\t\tterminator : '^<<<\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.subWikify(\n\t\t\t\tjQuery(document.createElement('blockquote'))\n\t\t\t\t\t.appendTo(w.output)\n\t\t\t\t\t.get(0),\n\t\t\t\tthis.terminator\n\t\t\t);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'quoteByLine',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^>+',\n\t\tlookahead  : /^>+/gm,\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst destStack = [w.output];\n\t\t\tlet curLevel = 0;\n\t\t\tlet newLevel = w.matchLength;\n\t\t\tlet matched;\n\t\t\tlet i;\n\n\t\t\tdo {\n\t\t\t\tif (newLevel > curLevel) {\n\t\t\t\t\tfor (i = curLevel; i < newLevel; ++i) {\n\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\tjQuery(document.createElement('blockquote'))\n\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (newLevel < curLevel) {\n\t\t\t\t\tfor (i = curLevel; i > newLevel; --i) {\n\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcurLevel = newLevel;\n\t\t\t\tw.subWikify(destStack[destStack.length - 1], this.terminator);\n\t\t\t\tjQuery(document.createElement('br')).appendTo(destStack[destStack.length - 1]);\n\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tnewLevel = match[0].length;\n\t\t\t\t\tw.nextMatch += match[0].length;\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'macro',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<<',\n\t\tlookahead : new RegExp(`<<(/?${Patterns.macroName})(?:\\\\s*)((?:(?:\\`(?:\\\\\\\\.|[^\\`\\\\\\\\])*\\`)|(?:\"(?:\\\\\\\\.|[^\"\\\\\\\\])*\")|(?:'(?:\\\\\\\\.|[^'\\\\\\\\])*')|(?:\\\\[(?:[<>]?[Ii][Mm][Gg])?\\\\[[^\\\\r\\\\n]*?\\\\]\\\\]+)|[^>]|(?:>(?!>)))*)>>`, 'gm'),\n\t\tworking   : { source : '', name : '', arguments : '', index : 0 }, // the working parse object\n\t\tcontext   : null, // last execution context object (top-level macros, hierarchically, have a null context)\n\n\t\thandler(w) {\n\t\t\tconst matchStart = this.lookahead.lastIndex = w.matchStart;\n\n\t\t\tif (this.parseTag(w)) {\n\t\t\t\t/*\n\t\t\t\t\tIf `parseBody()` is called below, it will modify the current working\n\t\t\t\t\tvalues, so we must cache them now.\n\t\t\t\t*/\n\t\t\t\tconst nextMatch = w.nextMatch;\n\t\t\t\tconst name      = this.working.name;\n\t\t\t\tconst rawArgs   = this.working.arguments;\n\t\t\t\tlet macro;\n\n\t\t\t\ttry {\n\t\t\t\t\tmacro = Macro.get(name);\n\n\t\t\t\t\tif (macro) {\n\t\t\t\t\t\tlet payload = null;\n\n\t\t\t\t\t\tif (macro.hasOwnProperty('tags')) {\n\t\t\t\t\t\t\tpayload = this.parseBody(w, macro);\n\n\t\t\t\t\t\t\tif (!payload) {\n\t\t\t\t\t\t\t\tw.nextMatch = nextMatch; // we must reset `w.nextMatch` here, as `parseBody()` modifies it\n\t\t\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t\t`cannot find a closing tag for macro <<${name}>>`,\n\t\t\t\t\t\t\t\t\t`${w.source.slice(matchStart, w.nextMatch)}\\u2026`\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (typeof macro.handler === 'function') {\n\t\t\t\t\t\t\tconst args = !payload\n\t\t\t\t\t\t\t\t? this.createArgs(rawArgs, this.skipArgs(macro, macro.name))\n\t\t\t\t\t\t\t\t: payload[0].args;\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tNew-style macros.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tif (macro.hasOwnProperty('_MACRO_API')) {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tAdd the macro's execution context to the context chain.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tthis.context = new MacroContext({\n\t\t\t\t\t\t\t\t\tmacro,\n\t\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\t\targs,\n\t\t\t\t\t\t\t\t\tpayload,\n\t\t\t\t\t\t\t\t\tsource : w.source.slice(matchStart, w.nextMatch),\n\t\t\t\t\t\t\t\t\tparent : this.context,\n\t\t\t\t\t\t\t\t\tparser : w\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tCall the handler.\n\n\t\t\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\t\t\t\t\t\tto ensure that the execution context is properly restored in the event\n\t\t\t\t\t\t\t\t\tthat an uncaught exception is thrown during the handler call.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tmacro.handler.call(this.context);\n\t\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\t\tQUESTION: Swap to the following, which passes macro arguments in\n\t\t\t\t\t\t\t\t\t\tas parameters to the handler function, in addition to them being\n\t\t\t\t\t\t\t\t\t\tavailable on its `this`?  If so, it might still be something to\n\t\t\t\t\t\t\t\t\t\thold off on until v3, when the legacy macro API is removed.\n\n\t\t\t\t\t\t\t\t\t\tmacro.handler.apply(this.context, this.context.args);\n\t\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t\tthis.context = this.context.parent;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t[DEPRECATED] Old-style/legacy macros.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tSet up the raw arguments string.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\tconst prevRawArgs = w._rawArgs;\n\t\t\t\t\t\t\t\tw._rawArgs = rawArgs;\n\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tCall the handler.\n\n\t\t\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists solely\n\t\t\t\t\t\t\t\t\tto ensure that the previous raw arguments string is properly restored in\n\t\t\t\t\t\t\t\t\tthe event that an uncaught exception is thrown during the handler call.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tmacro.handler(w.output, name, args, w, payload);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t\tw._rawArgs = prevRawArgs;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t`macro <<${name}>> handler function ${macro.hasOwnProperty('handler') ? 'is not a function' : 'does not exist'}`,\n\t\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (Macro.tags.has(name)) {\n\t\t\t\t\t\tconst tags = Macro.tags.get(name);\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`child tag <<${name}>> was found outside of a call to its parent macro${tags.length === 1 ? '' : 's'} <<${tags.join('>>, <<')}>>`,\n\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`macro <<${name}>> does not exist`,\n\t\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot execute ${macro && macro.isWidget ? 'widget' : 'macro'} <<${name}>>: ${ex.message}`,\n\t\t\t\t\t\tw.source.slice(matchStart, w.nextMatch)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\tthis.working.source    = '';\n\t\t\t\t\tthis.working.name      = '';\n\t\t\t\t\tthis.working.arguments = '';\n\t\t\t\t\tthis.working.index     = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t}\n\t\t},\n\n\t\tparseTag(w) {\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart && match[1]) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tthis.working.source    = w.source.slice(match.index, this.lookahead.lastIndex);\n\t\t\t\tthis.working.name      = match[1];\n\t\t\t\tthis.working.arguments = match[2];\n\t\t\t\tthis.working.index     = match.index;\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t},\n\n\t\tparseBody(w, macro) {\n\t\t\tconst openTag  = this.working.name;\n\t\t\tconst closeTag = `/${openTag}`;\n\t\t\tconst closeAlt = `end${openTag}`;\n\t\t\tconst bodyTags = Array.isArray(macro.tags) ? macro.tags : false;\n\t\t\tconst payload  = [];\n\t\t\tlet end          = -1;\n\t\t\tlet opened       = 1;\n\t\t\tlet curSource    = this.working.source;\n\t\t\tlet curTag       = this.working.name;\n\t\t\tlet curArgument  = this.working.arguments;\n\t\t\tlet contentStart = w.nextMatch;\n\n\t\t\twhile ((w.matchStart = w.source.indexOf(this.match, w.nextMatch)) !== -1) {\n\t\t\t\tif (!this.parseTag(w)) {\n\t\t\t\t\tthis.lookahead.lastIndex = w.nextMatch = w.matchStart + this.match.length;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst tagSource = this.working.source;\n\t\t\t\tconst tagName   = this.working.name;\n\t\t\t\tconst tagArgs   = this.working.arguments;\n\t\t\t\tconst tagBegin  = this.working.index;\n\t\t\t\tconst tagEnd    = w.nextMatch;\n\n\t\t\t\tswitch (tagName) {\n\t\t\t\tcase openTag:\n\t\t\t\t\t++opened;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase closeAlt:\n\t\t\t\tcase closeTag:\n\t\t\t\t\t--opened;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tif (opened === 1 && bodyTags) {\n\t\t\t\t\t\tfor (let i = 0, iend = bodyTags.length; i < iend; ++i) {\n\t\t\t\t\t\t\tif (tagName === bodyTags[i]) {\n\t\t\t\t\t\t\t\tpayload.push({\n\t\t\t\t\t\t\t\t\tsource    : curSource,\n\t\t\t\t\t\t\t\t\tname      : curTag,\n\t\t\t\t\t\t\t\t\targuments : curArgument,\n\t\t\t\t\t\t\t\t\targs      : this.createArgs(curArgument, this.skipArgs(macro, curTag)),\n\t\t\t\t\t\t\t\t\tcontents  : w.source.slice(contentStart, tagBegin)\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tcurSource    = tagSource;\n\t\t\t\t\t\t\t\tcurTag       = tagName;\n\t\t\t\t\t\t\t\tcurArgument  = tagArgs;\n\t\t\t\t\t\t\t\tcontentStart = tagEnd;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (opened === 0) {\n\t\t\t\t\tpayload.push({\n\t\t\t\t\t\tsource    : curSource,\n\t\t\t\t\t\tname      : curTag,\n\t\t\t\t\t\targuments : curArgument,\n\t\t\t\t\t\targs      : this.createArgs(curArgument, this.skipArgs(macro, curTag)),\n\t\t\t\t\t\tcontents  : w.source.slice(contentStart, tagBegin)\n\t\t\t\t\t});\n\t\t\t\t\tend = tagEnd;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (end !== -1) {\n\t\t\t\tw.nextMatch = end;\n\t\t\t\treturn payload;\n\t\t\t}\n\n\t\t\treturn null;\n\t\t},\n\n\t\tcreateArgs(rawArgsString, skipArgs) {\n\t\t\tconst args = skipArgs ? [] : this.parseArgs(rawArgsString);\n\n\t\t\t// Extend the args array with the raw and full argument strings.\n\t\t\tObject.defineProperties(args, {\n\t\t\t\traw : {\n\t\t\t\t\tvalue : rawArgsString\n\t\t\t\t},\n\t\t\t\tfull : {\n\t\t\t\t\tvalue : Scripting.parse(rawArgsString)\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn args;\n\t\t},\n\n\t\tskipArgs(macro, tagName) {\n\t\t\tif (macro.hasOwnProperty('skipArgs')) {\n\t\t\t\tconst sa = macro.skipArgs;\n\n\t\t\t\treturn typeof sa === 'boolean' && sa || Array.isArray(sa) && sa.includes(tagName);\n\t\t\t}\n\t\t\t/* legacy */\n\t\t\telse if (macro.hasOwnProperty('skipArg0')) {\n\t\t\t\treturn macro.skipArg0 && macro.name === tagName;\n\t\t\t}\n\t\t\t/* /legacy */\n\n\t\t\treturn false;\n\t\t},\n\n\t\tparseArgs : (() => {\n\t\t\tconst Item = Lexer.enumFromNames([ // lex item types object (pseudo-enumeration)\n\t\t\t\t'Error',        // error\n\t\t\t\t'Bareword',     // bare identifier\n\t\t\t\t'Expression',   // expression (backquoted)\n\t\t\t\t'String',       // quoted string (single or double)\n\t\t\t\t'SquareBracket' // [[…]] or [img[…]]\n\t\t\t]);\n\t\t\tconst spaceRe    = new RegExp(Patterns.space);\n\t\t\tconst notSpaceRe = new RegExp(Patterns.notSpace);\n\t\t\tconst varTest    = new RegExp(`^${Patterns.variable}`);\n\n\t\t\t// Lexing functions.\n\t\t\tfunction slurpQuote(lexer, endQuote) {\n\t\t\t\tloop: for (;;) {\n\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* falls through */\n\t\t\t\t\tcase EOF:\n\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\treturn EOF;\n\n\t\t\t\t\tcase endQuote:\n\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t}\n\n\t\t\t\treturn lexer.pos;\n\t\t\t}\n\n\t\t\tfunction lexSpace(lexer) {\n\t\t\t\tconst offset = lexer.source.slice(lexer.pos).search(notSpaceRe);\n\n\t\t\t\tif (offset === EOF) {\n\t\t\t\t\t// no non-whitespace characters, so bail\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\telse if (offset !== 0) {\n\t\t\t\t\tlexer.pos += offset;\n\t\t\t\t\tlexer.ignore();\n\t\t\t\t}\n\n\t\t\t\t// determine what the next state is\n\t\t\t\tswitch (lexer.next()) {\n\t\t\t\tcase '`':\n\t\t\t\t\treturn lexExpression;\n\t\t\t\tcase '\"':\n\t\t\t\t\treturn lexDoubleQuote;\n\t\t\t\tcase \"'\":\n\t\t\t\t\treturn lexSingleQuote;\n\t\t\t\tcase '[':\n\t\t\t\t\treturn lexSquareBracket;\n\t\t\t\tdefault:\n\t\t\t\t\treturn lexBareword;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction lexExpression(lexer) {\n\t\t\t\tif (slurpQuote(lexer, '`') === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated backquote expression');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.Expression);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexDoubleQuote(lexer) {\n\t\t\t\tif (slurpQuote(lexer, '\"') === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated double quoted string');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.String);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexSingleQuote(lexer) {\n\t\t\t\tif (slurpQuote(lexer, \"'\") === EOF) {\n\t\t\t\t\treturn lexer.error(Item.Error, 'unterminated single quoted string');\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.String);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexSquareBracket(lexer) {\n\t\t\t\tconst imgMeta = '<>IiMmGg';\n\t\t\t\tlet what;\n\n\t\t\t\tif (lexer.accept(imgMeta)) {\n\t\t\t\t\twhat = 'image';\n\t\t\t\t\tlexer.acceptRun(imgMeta);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\twhat = 'link';\n\t\t\t\t}\n\n\t\t\t\tif (!lexer.accept('[')) {\n\t\t\t\t\treturn lexer.error(Item.Error, `malformed ${what} markup`);\n\t\t\t\t}\n\n\t\t\t\tlexer.depth = 2; // account for both initial left square brackets\n\n\t\t\t\tloop: for (;;) {\n\t\t\t\t\t/* eslint-disable indent */\n\t\t\t\t\tswitch (lexer.next()) {\n\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst ch = lexer.next();\n\n\t\t\t\t\t\t\tif (ch !== EOF && ch !== '\\n') {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* falls through */\n\t\t\t\t\tcase EOF:\n\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\treturn lexer.error(Item.Error, `unterminated ${what} markup`);\n\n\t\t\t\t\tcase '[':\n\t\t\t\t\t\t++lexer.depth;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase ']':\n\t\t\t\t\t\t--lexer.depth;\n\n\t\t\t\t\t\tif (lexer.depth < 0) {\n\t\t\t\t\t\t\treturn lexer.error(Item.Error, \"unexpected right square bracket ']'\");\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (lexer.depth === 1) {\n\t\t\t\t\t\t\tif (lexer.next() === ']') {\n\t\t\t\t\t\t\t\t--lexer.depth;\n\t\t\t\t\t\t\t\tbreak loop;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlexer.backup();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable indent */\n\t\t\t\t}\n\n\t\t\t\tlexer.emit(Item.SquareBracket);\n\t\t\t\treturn lexSpace;\n\t\t\t}\n\n\t\t\tfunction lexBareword(lexer) {\n\t\t\t\tconst offset = lexer.source.slice(lexer.pos).search(spaceRe);\n\t\t\t\tlexer.pos = offset === EOF ? lexer.source.length : lexer.pos + offset;\n\t\t\t\tlexer.emit(Item.Bareword);\n\t\t\t\treturn offset === EOF ? null : lexSpace;\n\t\t\t}\n\n\t\t\t// Parse function.\n\t\t\tfunction parseMacroArgs(rawArgsString) {\n\t\t\t\t// Initialize the lexer.\n\t\t\t\tconst lexer = new Lexer(rawArgsString, lexSpace);\n\t\t\t\tconst args  = [];\n\n\t\t\t\t// Lex the raw argument string.\n\t\t\t\tlexer.run().forEach(item => {\n\t\t\t\t\tlet arg = item.text;\n\n\t\t\t\t\tswitch (item.type) {\n\t\t\t\t\tcase Item.Error:\n\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${item.message}`);\n\n\t\t\t\t\tcase Item.Bareword:\n\t\t\t\t\t\t// A variable, so substitute its value.\n\t\t\t\t\t\tif (varTest.test(arg)) {\n\t\t\t\t\t\t\targ = State.getVar(arg);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Property access on the settings or setup objects, so try to evaluate it.\n\t\t\t\t\t\telse if (/^(?:settings|setup)[.[]/.test(arg)) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\targ = Scripting.evalTwineScript(arg);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Null literal, so convert it into null.\n\t\t\t\t\t\telse if (arg === 'null') {\n\t\t\t\t\t\t\targ = null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Undefined literal, so convert it into undefined.\n\t\t\t\t\t\telse if (arg === 'undefined') {\n\t\t\t\t\t\t\targ = undefined;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Boolean true literal, so convert it into true.\n\t\t\t\t\t\telse if (arg === 'true') {\n\t\t\t\t\t\t\targ = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Boolean false literal, so convert it into false.\n\t\t\t\t\t\telse if (arg === 'false') {\n\t\t\t\t\t\t\targ = false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// NaN literal, so convert it into NaN.\n\t\t\t\t\t\telse if (arg === 'NaN') {\n\t\t\t\t\t\t\targ = NaN;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Attempt to convert it into a number, in case it's a numeric literal.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst argAsNum = Number(arg);\n\n\t\t\t\t\t\t\tif (!Number.isNaN(argAsNum)) {\n\t\t\t\t\t\t\t\targ = argAsNum;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.Expression:\n\t\t\t\t\t\targ = arg.slice(1, -1).trim(); // remove the backquotes and trim the expression\n\n\t\t\t\t\t\t// Empty backquotes.\n\t\t\t\t\t\tif (arg === '') {\n\t\t\t\t\t\t\targ = undefined;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Evaluate the expression.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t\tThe enclosing parenthesis here are necessary to force a code string\n\t\t\t\t\t\t\t\t\tconsisting solely of an object literal to be evaluated as such, rather\n\t\t\t\t\t\t\t\t\tthan as a code block.\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\targ = Scripting.evalTwineScript(`(${arg})`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument expression \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.String:\n\t\t\t\t\t\t// Evaluate the string to handle escaped characters.\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\targ = Scripting.evalJavaScript(arg);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument string \"${arg}\": ${ex.message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Item.SquareBracket:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\t\t\tsource     : arg,\n\t\t\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": ${markup.error}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (markup.pos < arg.length) {\n\t\t\t\t\t\t\t\tthrow new Error(`unable to parse macro argument \"${arg}\": unexpected character(s) \"${arg.slice(markup.pos)}\" (pos: ${markup.pos})`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert to a link or image object.\n\t\t\t\t\t\t\tif (markup.isLink) {\n\t\t\t\t\t\t\t\t// .isLink, [.text], [.forceInternal], .link, [.setter]\n\t\t\t\t\t\t\t\targ = { isLink : true };\n\t\t\t\t\t\t\t\targ.count    = markup.hasOwnProperty('text') ? 2 : 1;\n\t\t\t\t\t\t\t\targ.link     = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\t\t\t\t\t\targ.text     = markup.hasOwnProperty('text') ? Wikifier.helpers.evalText(markup.text) : arg.link;\n\t\t\t\t\t\t\t\targ.external = !markup.forceInternal && Wikifier.isExternalLink(arg.link);\n\t\t\t\t\t\t\t\targ.setFn    = markup.hasOwnProperty('setter')\n\t\t\t\t\t\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (markup.isImage) {\n\t\t\t\t\t\t\t\t// .isImage, [.align], [.title], .source, [.forceInternal], [.link], [.setter]\n\t\t\t\t\t\t\t\targ = (source => {\n\t\t\t\t\t\t\t\t\tconst imgObj = {\n\t\t\t\t\t\t\t\t\t\tsource,\n\t\t\t\t\t\t\t\t\t\tisImage : true\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t\t// Check for Twine 1.4 Base64 image passage transclusion.\n\t\t\t\t\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t\t\t\t\timgObj.source  = passage.text;\n\t\t\t\t\t\t\t\t\t\t\timgObj.passage = passage.title;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturn imgObj;\n\t\t\t\t\t\t\t\t})(Wikifier.helpers.evalPassageId(markup.source));\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('align')) {\n\t\t\t\t\t\t\t\t\targ.align = markup.align;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('text')) {\n\t\t\t\t\t\t\t\t\targ.title = Wikifier.helpers.evalText(markup.text);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (markup.hasOwnProperty('link')) {\n\t\t\t\t\t\t\t\t\targ.link     = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\t\t\t\t\t\t\targ.external = !markup.forceInternal && Wikifier.isExternalLink(arg.link);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\targ.setFn = markup.hasOwnProperty('setter')\n\t\t\t\t\t\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\targs.push(arg);\n\t\t\t\t});\n\n\t\t\t\treturn args;\n\t\t\t}\n\n\t\t\treturn parseMacroArgs;\n\t\t})()\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'link',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\[\\\\[[^[]',\n\n\t\thandler(w) {\n\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup(w);\n\n\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = markup.pos;\n\n\t\t\t// text=(text), forceInternal=(~), link=link, setter=(setter)\n\t\t\tconst link  = Wikifier.helpers.evalPassageId(markup.link);\n\t\t\tconst text  = markup.hasOwnProperty('text') ? Wikifier.helpers.evalText(markup.text) : link;\n\t\t\tconst setFn = markup.hasOwnProperty('setter')\n\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t: null;\n\n\t\t\t// Debug view setup.\n\t\t\tconst output = (Config.debug\n\t\t\t\t? new DebugView(w.output, 'link-markup', '[[link]]', w.source.slice(w.matchStart, w.nextMatch))\n\t\t\t\t: w\n\t\t\t).output;\n\n\t\t\tif (markup.forceInternal || !Wikifier.isExternalLink(link)) {\n\t\t\t\tWikifier.createInternalLink(output, link, text, setFn);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tWikifier.createExternalLink(output, link, text);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'urlLink',\n\t\tprofiles : ['core'],\n\t\tmatch    : Patterns.url,\n\n\t\thandler(w) {\n\t\t\tw.outputText(Wikifier.createExternalLink(w.output, w.matchText), w.matchStart, w.nextMatch);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'image',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\[[<>]?[Ii][Mm][Gg]\\\\[',\n\n\t\thandler(w) {\n\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup(w);\n\n\t\t\tif (markup.hasOwnProperty('error')) {\n\t\t\t\tw.outputText(w.output, w.matchStart, w.nextMatch);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = markup.pos;\n\n\t\t\t// Debug view setup.\n\t\t\tlet debugView;\n\n\t\t\tif (Config.debug) {\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tw.output,\n\t\t\t\t\t'image-markup',\n\t\t\t\t\tmarkup.hasOwnProperty('link') ? '[img[][link]]' : '[img[]]',\n\t\t\t\t\tw.source.slice(w.matchStart, w.nextMatch)\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ block : true });\n\t\t\t}\n\n\t\t\t// align=(left|right), title=(title), source=source, forceInternal=(~), link=(link), setter=(setter)\n\t\t\tconst setFn = markup.hasOwnProperty('setter')\n\t\t\t\t? Wikifier.helpers.createShadowSetterCallback(Scripting.parse(markup.setter))\n\t\t\t\t: null;\n\t\t\tlet el     = (Config.debug ? debugView : w).output;\n\t\t\tlet source;\n\n\t\t\tif (markup.hasOwnProperty('link')) {\n\t\t\t\tconst link = Wikifier.helpers.evalPassageId(markup.link);\n\n\t\t\t\tif (markup.forceInternal || !Wikifier.isExternalLink(link)) {\n\t\t\t\t\tel = Wikifier.createInternalLink(el, link, null, setFn);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tel = Wikifier.createExternalLink(el, link);\n\t\t\t\t}\n\n\t\t\t\tel.classList.add('link-image');\n\t\t\t}\n\n\t\t\tel = jQuery(document.createElement('img'))\n\t\t\t\t.appendTo(el)\n\t\t\t\t.get(0);\n\t\t\tsource = Wikifier.helpers.evalPassageId(markup.source);\n\n\t\t\t// Check for image passage transclusion.\n\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\tel.setAttribute('data-passage', passage.title);\n\t\t\t\t\tsource = passage.text.trim();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tel.src = source;\n\n\t\t\tif (markup.hasOwnProperty('text')) {\n\t\t\t\tel.title = Wikifier.helpers.evalText(markup.text);\n\t\t\t}\n\n\t\t\tif (markup.hasOwnProperty('align')) {\n\t\t\t\tel.align = markup.align;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'monospacedByBlock',\n\t\tprofiles  : ['block'],\n\t\tmatch     : '^\\\\{\\\\{\\\\{\\\\n',\n\t\tlookahead : /^\\{\\{\\{\\n((?:^[^\\n]*\\n)+?)(^\\}\\}\\}$\\n?)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tconst pre = jQuery(document.createElement('pre'));\n\t\t\t\tjQuery(document.createElement('code'))\n\t\t\t\t\t.text(match[1])\n\t\t\t\t\t.appendTo(pre);\n\t\t\t\tpre.appendTo(w.output);\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'formatByChar',\n\t\tprofiles : ['core'],\n\t\tmatch    : \"''|//|__|\\\\^\\\\^|~~|==|\\\\{\\\\{\\\\{\",\n\n\t\thandler(w) {\n\t\t\tswitch (w.matchText) {\n\t\t\tcase \"''\":\n\t\t\t\tw.subWikify(jQuery(document.createElement('strong')).appendTo(w.output).get(0), \"''\");\n\t\t\t\tbreak;\n\n\t\t\tcase '//':\n\t\t\t\tw.subWikify(jQuery(document.createElement('em')).appendTo(w.output).get(0), '//');\n\t\t\t\tbreak;\n\n\t\t\tcase '__':\n\t\t\t\tw.subWikify(jQuery(document.createElement('u')).appendTo(w.output).get(0), '__');\n\t\t\t\tbreak;\n\n\t\t\tcase '^^':\n\t\t\t\tw.subWikify(jQuery(document.createElement('sup')).appendTo(w.output).get(0), '\\\\^\\\\^');\n\t\t\t\tbreak;\n\n\t\t\tcase '~~':\n\t\t\t\tw.subWikify(jQuery(document.createElement('sub')).appendTo(w.output).get(0), '~~');\n\t\t\t\tbreak;\n\n\t\t\tcase '==':\n\t\t\t\tw.subWikify(jQuery(document.createElement('s')).appendTo(w.output).get(0), '==');\n\t\t\t\tbreak;\n\n\t\t\tcase '{{{':\n\t\t\t\t{\n\t\t\t\t\tconst lookahead = /\\{\\{\\{((?:.|\\n)*?)\\}\\}\\}/gm;\n\n\t\t\t\t\tlookahead.lastIndex = w.matchStart;\n\n\t\t\t\t\tconst match = lookahead.exec(w.source);\n\n\t\t\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\t\t\tjQuery(document.createElement('code'))\n\t\t\t\t\t\t\t.text(match[1])\n\t\t\t\t\t\t\t.appendTo(w.output);\n\t\t\t\t\t\tw.nextMatch = lookahead.lastIndex;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'customStyle',\n\t\tprofiles   : ['core'],\n\t\tmatch      : '@@',\n\t\tterminator : '@@',\n\t\tblockRe    : /\\s*\\n/gm,\n\n\t\thandler(w) {\n\t\t\tconst css = Wikifier.helpers.inlineCss(w);\n\n\t\t\tthis.blockRe.lastIndex = w.nextMatch; // must follow the call to `inlineCss()`\n\n\t\t\tconst blockMatch = this.blockRe.exec(w.source);\n\t\t\tconst blockLevel = blockMatch && blockMatch.index === w.nextMatch;\n\t\t\tconst $el        = jQuery(document.createElement(blockLevel ? 'div' : 'span'))\n\t\t\t\t.appendTo(w.output);\n\n\t\t\tif (css.classes.length === 0 && css.id === '' && Object.keys(css.styles).length === 0) {\n\t\t\t\t$el.addClass('marked');\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcss.classes.forEach(className => $el.addClass(className));\n\n\t\t\t\tif (css.id !== '') {\n\t\t\t\t\t$el.attr('id', css.id);\n\t\t\t\t}\n\n\t\t\t\t$el.css(css.styles);\n\t\t\t}\n\n\t\t\tif (blockLevel) {\n\t\t\t\t// Skip the leading and, if it exists, trailing newlines.\n\t\t\t\tw.nextMatch += blockMatch[0].length;\n\t\t\t\tw.subWikify($el[0], `\\\\n?${this.terminator}`);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tw.subWikify($el[0], this.terminator);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimText',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '\"{3}|<[Nn][Oo][Ww][Ii][Kk][Ii]>',\n\t\tlookahead : /(?:\"{3}((?:.|\\n)*?)\"{3})|(?:<[Nn][Oo][Ww][Ii][Kk][Ii]>((?:.|\\n)*?)<\\/[Nn][Oo][Ww][Ii][Kk][Ii]>)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tjQuery(document.createElement('span'))\n\t\t\t\t\t.addClass('verbatim')\n\t\t\t\t\t.text(match[1] || match[2])\n\t\t\t\t\t.appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'horizontalRule',\n\t\tprofiles : ['core'],\n\t\tmatch    : '^----+$\\\\n?|<[Hh][Rr]\\\\s*/?>\\\\n?',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createElement('hr')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'emdash',\n\t\tprofiles : ['core'],\n\t\tmatch    : '--',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createTextNode('\\u2014')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'doubleDollarSign',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\${2}', // eslint-disable-line no-template-curly-in-string\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createTextNode('$')).appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\t/*\n\t\t\tSupported syntax:\n\t\t\t\t$variable\n\t\t\t\t$variable.property\n\t\t\t\t$variable[numericIndex]\n\t\t\t\t$variable[\"property\"]\n\t\t\t\t$variable['property']\n\t\t\t\t$variable[$indexOrPropertyVariable]\n\t\t*/\n\t\tname     : 'nakedVariable',\n\t\tprofiles : ['core'],\n\t\tmatch    : `${Patterns.variable}(?:(?:\\\\.${Patterns.identifier})|(?:\\\\[\\\\d+\\\\])|(?:\\\\[\"(?:\\\\\\\\.|[^\"\\\\\\\\])+\"\\\\])|(?:\\\\['(?:\\\\\\\\.|[^'\\\\\\\\])+'\\\\])|(?:\\\\[${Patterns.variable}\\\\]))*`,\n\n\t\thandler(w) {\n\t\t\tconst result = toStringOrDefault(State.getVar(w.matchText), null);\n\n\t\t\tif (result === null) {\n\t\t\t\tjQuery(document.createTextNode(w.matchText)).appendTo(w.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnew Wikifier(\n\t\t\t\t\t(Config.debug\n\t\t\t\t\t\t? new DebugView(w.output, 'variable', w.matchText, w.matchText) // Debug view setup.\n\t\t\t\t\t\t: w\n\t\t\t\t\t).output,\n\t\t\t\t\tresult\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'template',\n\t\tprofiles : ['core'],\n\t\tmatch    : `\\\\?${Patterns.templateName}`,\n\n\t\thandler(w) {\n\t\t\tconst name = w.matchText.slice(1);\n\t\t\tlet template = Template.get(name);\n\t\t\tlet result   = null;\n\n\t\t\t// If we have an array of templates, randomly choose one.\n\t\t\tif (template instanceof Array) {\n\t\t\t\ttemplate = template.random();\n\t\t\t}\n\n\t\t\tswitch (typeof template) {\n\t\t\tcase 'function':\n\t\t\t\ttry {\n\t\t\t\t\tresult = toStringOrDefault(template.call({ name }), null);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot execute function template ?${name}: ${ex.message}`,\n\t\t\t\t\t\tw.source.slice(w.matchStart, w.nextMatch)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'string':\n\t\t\t\tresult = template;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (result === null) {\n\t\t\t\tjQuery(document.createTextNode(w.matchText)).appendTo(w.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnew Wikifier(\n\t\t\t\t\t(Config.debug\n\t\t\t\t\t\t? new DebugView(w.output, 'template', w.matchText, w.matchText) // Debug view setup.\n\t\t\t\t\t\t: w\n\t\t\t\t\t).output,\n\t\t\t\t\tresult\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'heading',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^!{1,6}',\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.subWikify(\n\t\t\t\tjQuery(document.createElement(`h${w.matchLength}`)).appendTo(w.output).get(0),\n\t\t\t\tthis.terminator\n\t\t\t);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname           : 'table',\n\t\tprofiles       : ['block'],\n\t\tmatch          : '^\\\\|(?:[^\\\\n]*)\\\\|(?:[fhck]?)$',\n\t\tlookahead      : /^\\|([^\\n]*)\\|([fhck]?)$/gm,\n\t\trowTerminator  : '\\\\|(?:[cfhk]?)$\\\\n?',\n\t\tcellPattern    : '(?:\\\\|([^\\\\n\\\\|]*)\\\\|)|(\\\\|[cfhk]?$\\\\n?)',\n\t\tcellTerminator : '(?:\\\\u0020*)\\\\|',\n\t\trowTypes       : { c : 'caption', f : 'tfoot', h : 'thead', '' : 'tbody' }, // eslint-disable-line id-length\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst table       = jQuery(document.createElement('table')).appendTo(w.output).get(0);\n\t\t\tconst prevColumns = [];\n\t\t\tlet curRowType    = null;\n\t\t\tlet $rowContainer = null;\n\t\t\tlet rowCount      = 0;\n\t\t\tlet matched;\n\n\t\t\tw.nextMatch = w.matchStart;\n\n\t\t\tdo {\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tconst nextRowType = match[2];\n\n\t\t\t\t\tif (nextRowType === 'k') {\n\t\t\t\t\t\ttable.className = match[1];\n\t\t\t\t\t\tw.nextMatch += match[0].length + 1;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (nextRowType !== curRowType) {\n\t\t\t\t\t\t\tcurRowType = nextRowType;\n\t\t\t\t\t\t\t$rowContainer = jQuery(document.createElement(this.rowTypes[nextRowType]))\n\t\t\t\t\t\t\t\t.appendTo(table);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (curRowType === 'c') {\n\t\t\t\t\t\t\t$rowContainer.css('caption-side', rowCount === 0 ? 'top' : 'bottom');\n\t\t\t\t\t\t\tw.nextMatch += 1;\n\t\t\t\t\t\t\tw.subWikify($rowContainer[0], this.rowTerminator);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tthis.rowHandler(\n\t\t\t\t\t\t\t\tw,\n\t\t\t\t\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t\t\t\t\t.appendTo($rowContainer)\n\t\t\t\t\t\t\t\t\t.get(0),\n\t\t\t\t\t\t\t\tprevColumns\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t++rowCount;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t},\n\n\t\trowHandler(w, rowEl, prevColumns) {\n\t\t\tconst cellRe = new RegExp(this.cellPattern, 'gm');\n\t\t\tlet col         = 0;\n\t\t\tlet curColCount = 1;\n\t\t\tlet matched;\n\n\t\t\tdo {\n\t\t\t\tcellRe.lastIndex = w.nextMatch;\n\n\t\t\t\tconst cellMatch = cellRe.exec(w.source);\n\n\t\t\t\tmatched = cellMatch && cellMatch.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tif (cellMatch[1] === '~') {\n\t\t\t\t\t\tconst last = prevColumns[col];\n\n\t\t\t\t\t\tif (last) {\n\t\t\t\t\t\t\t++last.rowCount;\n\t\t\t\t\t\t\tlast.$element\n\t\t\t\t\t\t\t\t.attr('rowspan', last.rowCount)\n\t\t\t\t\t\t\t\t.css('vertical-align', 'middle');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length - 1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (cellMatch[1] === '>') {\n\t\t\t\t\t\t++curColCount;\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length - 1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (cellMatch[2]) {\n\t\t\t\t\t\tw.nextMatch = cellMatch.index + cellMatch[0].length;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t++w.nextMatch;\n\n\t\t\t\t\t\tconst css = Wikifier.helpers.inlineCss(w);\n\t\t\t\t\t\tlet spaceLeft  = false;\n\t\t\t\t\t\tlet spaceRight = false;\n\t\t\t\t\t\tlet $cell;\n\n\t\t\t\t\t\twhile (w.source.substr(w.nextMatch, 1) === ' ') {\n\t\t\t\t\t\t\tspaceLeft = true;\n\t\t\t\t\t\t\t++w.nextMatch;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (w.source.substr(w.nextMatch, 1) === '!') {\n\t\t\t\t\t\t\t$cell = jQuery(document.createElement('th')).appendTo(rowEl);\n\t\t\t\t\t\t\t++w.nextMatch;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t$cell = jQuery(document.createElement('td')).appendTo(rowEl);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tprevColumns[col] = {\n\t\t\t\t\t\t\trowCount : 1,\n\t\t\t\t\t\t\t$element : $cell\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (curColCount > 1) {\n\t\t\t\t\t\t\t$cell.attr('colspan', curColCount);\n\t\t\t\t\t\t\tcurColCount = 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tw.subWikify($cell[0], this.cellTerminator);\n\n\t\t\t\t\t\tif (w.matchText.substr(w.matchText.length - 2, 1) === ' ') {\n\t\t\t\t\t\t\tspaceRight = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcss.classes.forEach(className => $cell.addClass(className));\n\n\t\t\t\t\t\tif (css.id !== '') {\n\t\t\t\t\t\t\t$cell.attr('id', css.id);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (spaceLeft && spaceRight) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'center';\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (spaceLeft) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'right';\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (spaceRight) {\n\t\t\t\t\t\t\tcss.styles['text-align'] = 'left';\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$cell.css(css.styles);\n\n\t\t\t\t\t\tw.nextMatch = w.nextMatch - 1;\n\t\t\t\t\t}\n\n\t\t\t\t\t++col;\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname       : 'list',\n\t\tprofiles   : ['block'],\n\t\tmatch      : '^(?:(?:\\\\*+)|(?:#+))',\n\t\tlookahead  : /^(?:(\\*+)|(#+))/gm,\n\t\tterminator : '\\\\n',\n\n\t\thandler(w) {\n\t\t\tif (!Wikifier.helpers.hasBlockContext(w.output.childNodes)) {\n\t\t\t\tjQuery(w.output).append(document.createTextNode(w.matchText));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.nextMatch = w.matchStart;\n\n\t\t\tconst destStack = [w.output];\n\t\t\tlet curType  = null;\n\t\t\tlet curLevel = 0;\n\t\t\tlet matched;\n\t\t\tlet i;\n\n\t\t\tdo {\n\t\t\t\tthis.lookahead.lastIndex = w.nextMatch;\n\n\t\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\t\tmatched = match && match.index === w.nextMatch;\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tconst newType  = match[2] ? 'ol' : 'ul';\n\t\t\t\t\tconst newLevel = match[0].length;\n\n\t\t\t\t\tw.nextMatch += match[0].length;\n\n\t\t\t\t\tif (newLevel > curLevel) {\n\t\t\t\t\t\tfor (i = curLevel; i < newLevel; ++i) {\n\t\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\t\tjQuery(document.createElement(newType))\n\t\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (newLevel < curLevel) {\n\t\t\t\t\t\tfor (i = curLevel; i > newLevel; --i) {\n\t\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (newLevel === curLevel && newType !== curType) {\n\t\t\t\t\t\tdestStack.pop();\n\t\t\t\t\t\tdestStack.push(\n\t\t\t\t\t\t\tjQuery(document.createElement(newType))\n\t\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tcurLevel = newLevel;\n\t\t\t\t\tcurType = newType;\n\t\t\t\t\tw.subWikify(\n\t\t\t\t\t\tjQuery(document.createElement('li'))\n\t\t\t\t\t\t\t.appendTo(destStack[destStack.length - 1])\n\t\t\t\t\t\t\t.get(0),\n\t\t\t\t\t\tthis.terminator\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} while (matched);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'commentByBlock',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '(?:/(?:%|\\\\*))|(?:<!--)',\n\t\tlookahead : /(?:\\/(%|\\*)(?:(?:.|\\n)*?)\\1\\/)|(?:<!--(?:(?:.|\\n)*?)-->)/gm,\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'lineContinuation',\n\t\tprofiles : ['core'],\n\n\t\t// WARNING: The ordering here is important: end-of-line, start-of-line, end-of-string, start-of-string.\n\t\tmatch : `\\\\\\\\${Patterns.spaceNoTerminator}*\\\\n|\\\\n${Patterns.spaceNoTerminator}*\\\\\\\\|\\\\n?\\\\\\\\${Patterns.spaceNoTerminator}*$|^${Patterns.spaceNoTerminator}*\\\\\\\\\\\\n?`,\n\n\t\thandler(w) {\n\t\t\tw.nextMatch = w.matchStart + w.matchLength;\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'lineBreak',\n\t\tprofiles : ['core'],\n\t\tmatch    : '\\\\n|<[Bb][Rr]\\\\s*/?>',\n\n\t\thandler(w) {\n\t\t\tif (!w.options.nobr) {\n\t\t\t\tjQuery(document.createElement('br')).appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'htmlCharacterReference',\n\t\tprofiles : ['core'],\n\t\tmatch    : '(?:(?:&#?[0-9A-Za-z]{2,8};|.)(?:&#?(?:x0*(?:3[0-6][0-9A-Fa-f]|1D[C-Fc-f][0-9A-Fa-f]|20[D-Fd-f][0-9A-Fa-f]|FE2[0-9A-Fa-f])|0*(?:76[89]|7[7-9][0-9]|8[0-7][0-9]|761[6-9]|76[2-7][0-9]|84[0-3][0-9]|844[0-7]|6505[6-9]|6506[0-9]|6507[0-1]));)+|&#?[0-9A-Za-z]{2,8};)',\n\n\t\thandler(w) {\n\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t.append(w.matchText)\n\t\t\t\t.appendTo(w.output);\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname     : 'xmlProlog',\n\t\tprofiles : ['core'],\n\t\tmatch    : '<\\\\?[Xx][Mm][Ll][^>]*\\\\?>',\n\n\t\thandler(w) {\n\t\t\tw.nextMatch = w.matchStart + w.matchLength;\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimHtml',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Hh][Tt][Mm][Ll]>',\n\t\tlookahead : /<[Hh][Tt][Mm][Ll]>((?:.|\\n)*?)<\\/[Hh][Tt][Mm][Ll]>/gm,\n\t\thandler   : _verbatimTagHandler\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'verbatimScriptTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Ss][Cc][Rr][Ii][Pp][Tt][^>]*>',\n\t\tlookahead : /(<[Ss][Cc][Rr][Ii][Pp][Tt]*>(?:.|\\n)*?<\\/[Ss][Cc][Rr][Ii][Pp][Tt]>)/gm,\n\t\thandler   : _verbatimTagHandler\n\t});\n\n\tWikifier.Parser.add({\n\t\tname           : 'styleTag',\n\t\tprofiles       : ['core'],\n\t\tmatch          : '<[Ss][Tt][Yy][Ll][Ee][^>]*>',\n\t\tlookahead      : /(<[Ss][Tt][Yy][Ll][Ee]*>)((?:.|\\n)*?)(<\\/[Ss][Tt][Yy][Ll][Ee]>)/gm,\n\t\timageMarkup    : new RegExp(Patterns.cssImage, 'g'),\n\t\thasImageMarkup : new RegExp(Patterns.cssImage),\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tlet css = match[2];\n\n\t\t\t\t// Check for wiki image transclusion.\n\t\t\t\tif (this.hasImageMarkup.test(css)) {\n\t\t\t\t\tthis.imageMarkup.lastIndex = 0;\n\n\t\t\t\t\tcss = css.replace(this.imageMarkup, wikiImage => {\n\t\t\t\t\t\tconst markup = Wikifier.helpers.parseSquareBracketedMarkup({\n\t\t\t\t\t\t\tsource     : wikiImage,\n\t\t\t\t\t\t\tmatchStart : 0\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (markup.hasOwnProperty('error') || markup.pos < wikiImage.length) {\n\t\t\t\t\t\t\treturn wikiImage;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet source = markup.source;\n\n\t\t\t\t\t\t// Handle image passage transclusion.\n\t\t\t\t\t\tif (source.slice(0, 5) !== 'data:' && Story.has(source)) {\n\t\t\t\t\t\t\tconst passage = Story.get(source);\n\n\t\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t\tsource = passage.text;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tThe source may be URI- or Base64-encoded, so we cannot use `encodeURIComponent()`\n\t\t\t\t\t\t\there.  Instead, we simply encode any double quotes, since the URI will be\n\t\t\t\t\t\t\tdelimited by them.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\treturn `url(\"${source.replace(/\"/g, '%22')}\")`;\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createDocumentFragment())\n\t\t\t\t\t.append(match[1] + css + match[3])\n\t\t\t\t\t.appendTo(w.output);\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\tname      : 'svgTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<[Ss][Vv][Gg][^>]*>',\n\t\tlookahead : /(<[Ss][Vv][Gg][^>]*>(?:.|\\n)*?<\\/[Ss][Vv][Gg]>)/gm,\n\t\tnamespace : 'http://www.w3.org/2000/svg',\n\n\t\thandler(w) {\n\t\t\tthis.lookahead.lastIndex = w.matchStart;\n\n\t\t\tconst match = this.lookahead.exec(w.source);\n\n\t\t\tif (match && match.index === w.matchStart) {\n\t\t\t\tw.nextMatch = this.lookahead.lastIndex;\n\n\t\t\t\tconst $frag = jQuery(document.createDocumentFragment()).append(match[1]);\n\n\t\t\t\t// Postprocess the relevant SVG element nodes.\n\t\t\t\t$frag.find('a[data-passage],image[data-passage]').each((_, el) => {\n\t\t\t\t\tconst tagName = el.tagName.toLowerCase();\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.processAttributeDirectives(el);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`svg|<${tagName}>: ${ex.message}`,\n\t\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (el.hasAttribute('data-passage')) {\n\t\t\t\t\t\tthis.processDataAttributes(el, tagName);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\t$frag.appendTo(w.output);\n\t\t\t}\n\t\t},\n\n\t\tprocessAttributeDirectives(el) {\n\t\t\t// NOTE: The `.attributes` property yields a live collection, so we\n\t\t\t// must make a non-live copy of it as we will be adding and removing\n\t\t\t// members of said collection if any directives are found.\n\t\t\t[...el.attributes].forEach(({ name, value }) => {\n\t\t\t\tconst evalShorthand = name[0] === '@';\n\n\t\t\t\tif (evalShorthand || name.startsWith('sc-eval:')) {\n\t\t\t\t\tconst newName = name.slice(evalShorthand ? 1 : 8); // Remove eval directive prefix.\n\n\t\t\t\t\tif (newName === 'data-setter') {\n\t\t\t\t\t\tthrow new Error(`evaluation directive is not allowed on the data-setter attribute: \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\t// Evaluate the value as TwineScript.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = Scripting.evalTwineScript(value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`bad evaluation from attribute directive \"${name}\": ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Assign the result to the new attribute and remove the old one.\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: Most browsers (ca. Nov 2017) have broken `setAttribute()`\n\t\t\t\t\t\t\tmethod implementations that throw on attribute names that start\n\t\t\t\t\t\t\twith, or contain, various symbols that are completely valid per\n\t\t\t\t\t\t\tthe specification.  Thus this code could fail if the user chooses\n\t\t\t\t\t\t\tattribute names that, after removing the directive prefix, are\n\t\t\t\t\t\t\tunpalatable to `setAttribute()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tel.setAttribute(newName, result);\n\t\t\t\t\t\tel.removeAttribute(name);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`cannot transform attribute directive \"${name}\" into attribute \"${newName}\"`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tprocessDataAttributes(el, tagName) {\n\t\t\tlet passage = el.getAttribute('data-passage');\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst evaluated = Wikifier.helpers.evalPassageId(passage);\n\n\t\t\tif (evaluated !== passage) {\n\t\t\t\tpassage = evaluated;\n\t\t\t\tel.setAttribute('data-passage', evaluated);\n\t\t\t}\n\n\t\t\tif (passage !== '') {\n\t\t\t\t// '<image>' element, so attempt media passage transclusion.\n\t\t\t\tif (tagName === 'image') {\n\t\t\t\t\tif (passage.slice(0, 5) !== 'data:' && Story.has(passage)) {\n\t\t\t\t\t\tpassage = Story.get(passage);\n\n\t\t\t\t\t\tif (passage.tags.includes('Twine.image')) {\n\t\t\t\t\t\t\t// NOTE: SVG `.href` IDL attribute is read-only,\n\t\t\t\t\t\t\t// so set its `href` content attribute instead.\n\t\t\t\t\t\t\tel.setAttribute('href', passage.text.trim());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Elsewise, assume a link element of some type—e.g., '<a>'.\n\t\t\t\telse {\n\t\t\t\t\tlet setter = el.getAttribute('data-setter');\n\t\t\t\t\tlet setFn;\n\n\t\t\t\t\tif (setter != null) { // lazy equality for null\n\t\t\t\t\t\tsetter = String(setter).trim();\n\n\t\t\t\t\t\tif (setter !== '') {\n\t\t\t\t\t\t\tsetFn = Wikifier.helpers.createShadowSetterCallback(Scripting.parse(setter));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tel.classList.add('link-internal');\n\n\t\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t\tel.classList.add('link-visited');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tel.classList.add('link-broken');\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery(el).ariaClick({ one : true }, function () {\n\t\t\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\t\t\tsetFn.call(this);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\tWikifier.Parser.add({\n\t\t/*\n\t\t\tNOTE: This parser MUST come after any parser which handles HTML tag-\n\t\t\tlike constructs—e.g. 'verbatimText', 'horizontalRule', 'lineBreak',\n\t\t\t'xmlProlog', 'verbatimHtml', 'verbatimSvgTag', 'verbatimScriptTag',\n\t\t\tand 'styleTag'.\n\t\t*/\n\t\tname      : 'htmlTag',\n\t\tprofiles  : ['core'],\n\t\tmatch     : '<\\\\w+(?:\\\\s+[^\\\\u0000-\\\\u001F\\\\u007F-\\\\u009F\\\\s\"\\'>\\\\/=]+(?:\\\\s*=\\\\s*(?:\"[^\"]*?\"|\\'[^\\']*?\\'|[^\\\\s\"\\'=<>`]+))?)*\\\\s*\\\\/?>',\n\t\ttagRe     : /^<(\\w+)/,\n\t\tmediaTags : ['audio', 'img', 'source', 'track', 'video'], // NOTE: The `<picture>` element should not be in this list.\n\t\tnobrTags  : ['audio', 'colgroup', 'datalist', 'dl', 'figure', 'meter', 'ol', 'optgroup', 'picture', 'progress', 'ruby', 'select', 'table', 'tbody', 'tfoot', 'thead', 'tr', 'ul', 'video'],\n\t\tvoidTags  : ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'],\n\n\t\thandler(w) {\n\t\t\tconst tagMatch = this.tagRe.exec(w.matchText);\n\t\t\tconst tag      = tagMatch && tagMatch[1];\n\t\t\tconst tagName  = tag && tag.toLowerCase();\n\n\t\t\tif (tagName) {\n\t\t\t\tconst isVoid = this.voidTags.includes(tagName) || w.matchText.endsWith('/>');\n\t\t\t\tconst isNobr = this.nobrTags.includes(tagName);\n\t\t\t\tlet terminator;\n\t\t\t\tlet terminatorMatch;\n\n\t\t\t\tif (!isVoid) {\n\t\t\t\t\tterminator = `<\\\\/${tagName}\\\\s*>`;\n\n\t\t\t\t\tconst terminatorRe = new RegExp(terminator, 'gim'); // ignore case during match\n\n\t\t\t\t\tterminatorRe.lastIndex = w.matchStart;\n\t\t\t\t\tterminatorMatch = terminatorRe.exec(w.source);\n\t\t\t\t}\n\n\t\t\t\tif (isVoid || terminatorMatch) {\n\t\t\t\t\tlet output    = w.output;\n\t\t\t\t\tlet el        = document.createElement(w.output.tagName);\n\t\t\t\t\tlet debugView;\n\n\t\t\t\t\tel.innerHTML = w.matchText;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tNOTE: The use of a `while` statement here is curious, however,\n\t\t\t\t\t\tI'm hesitant to change it for fear of breaking some edge case.\n\t\t\t\t\t*/\n\t\t\t\t\twhile (el.firstChild) {\n\t\t\t\t\t\tel = el.firstChild;\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.processAttributeDirectives(el);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn throwError(\n\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t`<${tagName}>: ${ex.message}`,\n\t\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (el.hasAttribute('data-passage')) {\n\t\t\t\t\t\tthis.processDataAttributes(el, tagName);\n\n\t\t\t\t\t\t// Debug view setup.\n\t\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t\t\t`html-${tagName}`,\n\t\t\t\t\t\t\t\ttagName,\n\t\t\t\t\t\t\t\tw.matchText\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tdebugView.modes({\n\t\t\t\t\t\t\t\tblock   : tagName === 'img',\n\t\t\t\t\t\t\t\tnonvoid : terminatorMatch\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\toutput = debugView.output;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (terminatorMatch) {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: There's no catch clause here because this try/finally exists\n\t\t\t\t\t\t\tsolely to ensure that the options stack is properly restored in\n\t\t\t\t\t\t\tthe event that an uncaught exception is thrown during the call to\n\t\t\t\t\t\t\t`subWikify()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tWikifier.Option.push({ nobr : isNobr });\n\t\t\t\t\t\t\tw.subWikify(el, terminator, { ignoreTerminatorCase : true });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\tWikifier.Option.pop();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tDebug view modification.  If the current element has any debug\n\t\t\t\t\t\t\tview descendants who have \"block\" mode set, then set its debug\n\t\t\t\t\t\t\tview to the same.  It just makes things look a bit nicer.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tif (debugView && jQuery(el).find('.debug.block').length > 0) {\n\t\t\t\t\t\t\tdebugView.modes({ block : true });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tNOTE: The use of `cloneNode(true)` here for `<track>` elements\n\t\t\t\t\t\tis necessary to workaround a poorly understood rehoming issue.\n\t\t\t\t\t*/\n\t\t\t\t\toutput.appendChild(tagName === 'track' ? el.cloneNode(true) : el);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn throwError(\n\t\t\t\t\t\tw.output,\n\t\t\t\t\t\t`cannot find a closing tag for HTML <${tag}>`,\n\t\t\t\t\t\t`${w.matchText}\\u2026`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tprocessAttributeDirectives(el) {\n\t\t\t// NOTE: The `.attributes` property yields a live collection, so we\n\t\t\t// must make a non-live copy of it as we will be adding and removing\n\t\t\t// members of said collection if any directives are found.\n\t\t\t[...el.attributes].forEach(({ name, value }) => {\n\t\t\t\tconst evalShorthand = name[0] === '@';\n\n\t\t\t\tif (evalShorthand || name.startsWith('sc-eval:')) {\n\t\t\t\t\tconst newName = name.slice(evalShorthand ? 1 : 8); // Remove eval directive prefix.\n\n\t\t\t\t\tif (newName === 'data-setter') {\n\t\t\t\t\t\tthrow new Error(`evaluation directive is not allowed on the data-setter attribute: \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\t// Evaluate the value as TwineScript.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = Scripting.evalTwineScript(value);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`bad evaluation from attribute directive \"${name}\": ${ex.message}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Assign the result to the new attribute and remove the old one.\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: Most browsers (ca. Nov 2017) have broken `setAttribute()`\n\t\t\t\t\t\t\tmethod implementations that throw on attribute names that start\n\t\t\t\t\t\t\twith, or contain, various symbols that are completely valid per\n\t\t\t\t\t\t\tthe specification.  Thus this code could fail if the user chooses\n\t\t\t\t\t\t\tattribute names that, after removing the directive prefix, are\n\t\t\t\t\t\t\tunpalatable to `setAttribute()`.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tel.setAttribute(newName, result);\n\t\t\t\t\t\tel.removeAttribute(name);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\tthrow new Error(`cannot transform attribute directive \"${name}\" into attribute \"${newName}\"`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tprocessDataAttributes(el, tagName) {\n\t\t\tlet passage = el.getAttribute('data-passage');\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst evaluated = Wikifier.helpers.evalPassageId(passage);\n\n\t\t\tif (evaluated !== passage) {\n\t\t\t\tpassage = evaluated;\n\t\t\t\tel.setAttribute('data-passage', evaluated);\n\t\t\t}\n\n\t\t\tif (passage !== '') {\n\t\t\t\t// Media element, so attempt media passage transclusion.\n\t\t\t\tif (this.mediaTags.includes(tagName)) {\n\t\t\t\t\tif (passage.slice(0, 5) !== 'data:' && Story.has(passage)) {\n\t\t\t\t\t\tpassage = Story.get(passage);\n\n\t\t\t\t\t\tlet parentName;\n\t\t\t\t\t\tlet twineTag;\n\n\t\t\t\t\t\tswitch (tagName) {\n\t\t\t\t\t\tcase 'audio':\n\t\t\t\t\t\tcase 'video':\n\t\t\t\t\t\t\ttwineTag = `Twine.${tagName}`;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'img':\n\t\t\t\t\t\t\ttwineTag = 'Twine.image';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'track':\n\t\t\t\t\t\t\ttwineTag = 'Twine.vtt';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'source':\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst $parent = $(el).closest('audio,picture,video');\n\n\t\t\t\t\t\t\t\tif ($parent.length) {\n\t\t\t\t\t\t\t\t\tparentName = $parent.get(0).tagName.toLowerCase();\n\t\t\t\t\t\t\t\t\ttwineTag = `Twine.${parentName === 'picture' ? 'image' : parentName}`;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (passage.tags.includes(twineTag)) {\n\t\t\t\t\t\t\tel[parentName === 'picture' ? 'srcset' : 'src'] = passage.text.trim();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Elsewise, assume a link element of some type—e.g., '<a>', '<area>', '<button>', etc.\n\t\t\t\telse {\n\t\t\t\t\tlet setter = el.getAttribute('data-setter');\n\t\t\t\t\tlet setFn;\n\n\t\t\t\t\tif (setter != null) { // lazy equality for null\n\t\t\t\t\t\tsetter = String(setter).trim();\n\n\t\t\t\t\t\tif (setter !== '') {\n\t\t\t\t\t\t\tsetFn = Wikifier.helpers.createShadowSetterCallback(Scripting.parse(setter));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tel.classList.add('link-internal');\n\n\t\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t\tel.classList.add('link-visited');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tel.classList.add('link-broken');\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery(el).ariaClick({ one : true }, function () {\n\t\t\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\t\t\tsetFn.call(this);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tmarkup/template.js\n\n\tCopyright © 2019–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns */\n\nvar Template = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Template definitions.\n\tconst _templates = new Map();\n\n\t// Valid template name regular expression.\n\tconst _validNameRe = new RegExp(`^(?:${Patterns.templateName})$`);\n\n\t// Valid template type predicate.\n\tconst _validType = template => {\n\t\tconst templateType = typeof template;\n\t\treturn templateType === 'function' || templateType === 'string';\n\t};\n\n\n\t/*******************************************************************************\n\t\tTemplate Functions.\n\t*******************************************************************************/\n\n\tfunction templateAdd(name, template) {\n\t\tif (\n\t\t\t   !_validType(template)\n\t\t\t&& !(template instanceof Array && template.length > 0 && template.every(_validType))\n\t\t) {\n\t\t\tthrow new TypeError(`invalid template type (${name}); templates must be: functions, strings, or an array of either`);\n\t\t}\n\n\t\t(name instanceof Array ? name : [name]).forEach(name => {\n\t\t\tif (!_validNameRe.test(name)) {\n\t\t\t\tthrow new Error(`invalid template name \"${name}\"`);\n\t\t\t}\n\t\t\tif (_templates.has(name)) {\n\t\t\t\tthrow new Error(`cannot clobber existing template ?${name}`);\n\t\t\t}\n\n\t\t\t_templates.set(name, template);\n\t\t});\n\t}\n\n\tfunction templateDelete(name) {\n\t\t(name instanceof Array ? name : [name]).forEach(name => _templates.delete(name));\n\t}\n\n\tfunction templateGet(name) {\n\t\treturn _templates.has(name) ? _templates.get(name) : null;\n\t}\n\n\tfunction templateHas(name) {\n\t\treturn _templates.has(name);\n\t}\n\n\tfunction templateSize() {\n\t\treturn _templates.size;\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tadd    : { value : templateAdd },\n\t\tdelete : { value : templateDelete },\n\t\tget    : { value : templateGet },\n\t\thas    : { value : templateHas },\n\t\tsize   : { get : templateSize }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macro.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Patterns, Scripting, clone, macros */\n\nvar Macro = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Macro definitions.\n\tconst _macros = {};\n\n\t// Map of all macro tags and their parents (key: 'tag name' => value: ['list of parent names']).\n\tconst _tags = {};\n\n\t// Valid macro name regular expression.\n\tconst _validNameRe = new RegExp(`^(?:${Patterns.macroName})$`);\n\n\n\t/*******************************************************************************************************************\n\t\tMacros Functions.\n\t*******************************************************************************************************************/\n\tfunction macrosAdd(name, def, deep) {\n\t\tif (Array.isArray(name)) {\n\t\t\tname.forEach(name => macrosAdd(name, def, deep));\n\t\t\treturn;\n\t\t}\n\n\t\tif (!_validNameRe.test(name)) {\n\t\t\tthrow new Error(`invalid macro name \"${name}\"`);\n\t\t}\n\n\t\tif (macrosHas(name)) {\n\t\t\tthrow new Error(`cannot clobber existing macro <<${name}>>`);\n\t\t}\n\t\telse if (tagsHas(name)) {\n\t\t\tthrow new Error(`cannot clobber child tag <<${name}>> of parent macro${_tags[name].length === 1 ? '' : 's'} <<${_tags[name].join('>>, <<')}>>`);\n\t\t}\n\n\t\ttry {\n\t\t\tif (typeof def === 'object') {\n\t\t\t\t// Add the macro definition.\n\t\t\t\t_macros[name] = deep ? clone(def) : def;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Add the macro alias.\n\t\t\t\tif (macrosHas(def)) {\n\t\t\t\t\t_macros[name] = deep ? clone(_macros[def]) : _macros[def];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new Error(`cannot create alias of nonexistent macro <<${def}>>`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tObject.defineProperty(_macros, name, { writable : false });\n\n\t\t\t/* legacy */\n\t\t\t/*\n\t\t\t\tSince `macrosGet()` may return legacy macros, we have to add a flag to (modern)\n\t\t\t\tAPI macros, so that the macro formatter will know how to call the macro.\n\t\t\t*/\n\t\t\t_macros[name]._MACRO_API = true;\n\t\t\t/* /legacy */\n\t\t}\n\t\tcatch (ex) {\n\t\t\tif (ex.name === 'TypeError') {\n\t\t\t\tthrow new Error(`cannot clobber protected macro <<${name}>>`);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error(`unknown error when attempting to add macro <<${name}>>: [${ex.name}] ${ex.message}`);\n\t\t\t}\n\t\t}\n\n\t\t// Tags post-processing.\n\t\tif (_macros[name].hasOwnProperty('tags')) {\n\t\t\tif (_macros[name].tags == null) { // lazy equality for null\n\t\t\t\ttagsRegister(name);\n\t\t\t}\n\t\t\telse if (Array.isArray(_macros[name].tags)) {\n\t\t\t\ttagsRegister(name, _macros[name].tags);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error(`bad value for \"tags\" property of macro <<${name}>>`);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction macrosDelete(name) {\n\t\tif (Array.isArray(name)) {\n\t\t\tname.forEach(name => macrosDelete(name));\n\t\t\treturn;\n\t\t}\n\n\t\tif (macrosHas(name)) {\n\t\t\t// Tags pre-processing.\n\t\t\tif (_macros[name].hasOwnProperty('tags')) {\n\t\t\t\ttagsUnregister(name);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t// Remove the macro definition.\n\t\t\t\tObject.defineProperty(_macros, name, { writable : true });\n\t\t\t\tdelete _macros[name];\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tthrow new Error(`unknown error removing macro <<${name}>>: ${ex.message}`);\n\t\t\t}\n\t\t}\n\t\telse if (tagsHas(name)) {\n\t\t\tthrow new Error(`cannot remove child tag <<${name}>> of parent macro <<${_tags[name]}>>`);\n\t\t}\n\t}\n\n\tfunction macrosIsEmpty() {\n\t\treturn Object.keys(_macros).length === 0;\n\t}\n\n\tfunction macrosHas(name) {\n\t\treturn _macros.hasOwnProperty(name);\n\t}\n\n\tfunction macrosGet(name) {\n\t\tlet macro = null;\n\n\t\tif (macrosHas(name) && typeof _macros[name].handler === 'function') {\n\t\t\tmacro = _macros[name];\n\t\t}\n\t\t/* legacy macro support */\n\t\telse if (macros.hasOwnProperty(name) && typeof macros[name].handler === 'function') {\n\t\t\tmacro = macros[name];\n\t\t}\n\t\t/* /legacy macro support */\n\n\t\treturn macro;\n\t}\n\n\tfunction macrosInit(handler = 'init') { // eslint-disable-line no-unused-vars\n\t\tObject.keys(_macros).forEach(name => {\n\t\t\tif (typeof _macros[name][handler] === 'function') {\n\t\t\t\t_macros[name][handler](name);\n\t\t\t}\n\t\t});\n\n\t\t/* legacy macro support */\n\t\tObject.keys(macros).forEach(name => {\n\t\t\tif (typeof macros[name][handler] === 'function') {\n\t\t\t\tmacros[name][handler](name);\n\t\t\t}\n\t\t});\n\t\t/* /legacy macro support */\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tTags Functions.\n\t*******************************************************************************************************************/\n\tfunction tagsRegister(parent, bodyTags) {\n\t\tif (!parent) {\n\t\t\tthrow new Error('no parent specified');\n\t\t}\n\n\t\tconst endTags = [`/${parent}`, `end${parent}`]; // automatically create the closing tags\n\t\tconst allTags = [].concat(endTags, Array.isArray(bodyTags) ? bodyTags : []);\n\n\t\tfor (let i = 0; i < allTags.length; ++i) {\n\t\t\tconst tag = allTags[i];\n\n\t\t\tif (macrosHas(tag)) {\n\t\t\t\tthrow new Error('cannot register tag for an existing macro');\n\t\t\t}\n\n\t\t\tif (tagsHas(tag)) {\n\t\t\t\tif (!_tags[tag].includes(parent)) {\n\t\t\t\t\t_tags[tag].push(parent);\n\t\t\t\t\t_tags[tag].sort();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_tags[tag] = [parent];\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction tagsUnregister(parent) {\n\t\tif (!parent) {\n\t\t\tthrow new Error('no parent specified');\n\t\t}\n\n\t\tObject.keys(_tags).forEach(tag => {\n\t\t\tconst i = _tags[tag].indexOf(parent);\n\n\t\t\tif (i !== -1) {\n\t\t\t\tif (_tags[tag].length === 1) {\n\t\t\t\t\tdelete _tags[tag];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_tags[tag].splice(i, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction tagsHas(name) {\n\t\treturn _tags.hasOwnProperty(name);\n\t}\n\n\tfunction tagsGet(name) {\n\t\treturn tagsHas(name) ? _tags[name] : null;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tMacro Functions.\n\t\t*/\n\t\tadd     : { value : macrosAdd },\n\t\tdelete  : { value : macrosDelete },\n\t\tisEmpty : { value : macrosIsEmpty },\n\t\thas     : { value : macrosHas },\n\t\tget     : { value : macrosGet },\n\t\tinit    : { value : macrosInit },\n\n\t\t/*\n\t\t\tTags Functions.\n\t\t*/\n\t\ttags : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tregister   : { value : tagsRegister },\n\t\t\t\tunregister : { value : tagsUnregister },\n\t\t\t\thas        : { value : tagsHas },\n\t\t\t\tget        : { value : tagsGet }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\tevalStatements : { value : (...args) => Scripting.evalJavaScript(...args) } // SEE: `markup/scripting.js`.\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macrocontext.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, DebugView, Patterns, State, Wikifier, throwError */\n\nvar MacroContext = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tMacroContext Class.\n\t*******************************************************************************************************************/\n\tclass MacroContext {\n\t\tconstructor(contextData) {\n\t\t\tconst context = Object.assign({\n\t\t\t\tparent  : null,\n\t\t\t\tmacro   : null,\n\t\t\t\tname    : '',\n\t\t\t\targs    : null,\n\t\t\t\tpayload : null,\n\t\t\t\tparser  : null,\n\t\t\t\tsource  : ''\n\t\t\t}, contextData);\n\n\t\t\tif (context.macro === null || context.name === '' || context.parser === null) {\n\t\t\t\tthrow new TypeError('context object missing required properties');\n\t\t\t}\n\n\t\t\tObject.defineProperties(this, {\n\t\t\t\tself : {\n\t\t\t\t\tvalue : context.macro\n\t\t\t\t},\n\n\t\t\t\tname : {\n\t\t\t\t\tvalue : context.name\n\t\t\t\t},\n\n\t\t\t\targs : {\n\t\t\t\t\tvalue : context.args\n\t\t\t\t},\n\n\t\t\t\tpayload : {\n\t\t\t\t\tvalue : context.payload\n\t\t\t\t},\n\n\t\t\t\tsource : {\n\t\t\t\t\tvalue : context.source\n\t\t\t\t},\n\n\t\t\t\tparent : {\n\t\t\t\t\tvalue : context.parent\n\t\t\t\t},\n\n\t\t\t\tparser : {\n\t\t\t\t\tvalue : context.parser\n\t\t\t\t},\n\n\t\t\t\t_output : {\n\t\t\t\t\tvalue : context.parser.output\n\t\t\t\t},\n\n\t\t\t\t_shadows : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_debugView : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t},\n\n\t\t\t\t_debugViewEnabled : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : Config.debug\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tget output() {\n\t\t\treturn this._debugViewEnabled ? this.debugView.output : this._output;\n\t\t}\n\n\t\tget shadows() {\n\t\t\treturn [...this._shadows];\n\t\t}\n\n\t\tget shadowView() {\n\t\t\tconst view = new Set();\n\t\t\tthis.contextSelectAll(ctx => ctx._shadows)\n\t\t\t\t.forEach(ctx => ctx._shadows.forEach(name => view.add(name)));\n\t\t\treturn [...view];\n\t\t}\n\n\t\tget debugView() {\n\t\t\tif (this._debugViewEnabled) {\n\t\t\t\treturn this._debugView !== null ? this._debugView : this.createDebugView();\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tcontextHas(filter) {\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tcontextSelect(filter) {\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\treturn context;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tcontextSelectAll(filter) {\n\t\t\tconst result = [];\n\t\t\tlet context = this;\n\n\t\t\twhile ((context = context.parent) !== null) {\n\t\t\t\tif (filter(context)) {\n\t\t\t\t\tresult.push(context);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\taddShadow(...names) {\n\t\t\tif (!this._shadows) {\n\t\t\t\tthis._shadows = new Set();\n\t\t\t}\n\n\t\t\tconst varRe = new RegExp(`^${Patterns.variable}$`);\n\n\t\t\tnames\n\t\t\t\t.flat(Infinity)\n\t\t\t\t.forEach(name => {\n\t\t\t\t\tif (typeof name !== 'string') {\n\t\t\t\t\t\tthrow new TypeError(`variable name must be a string; type: ${typeof name}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!varRe.test(name)) {\n\t\t\t\t\t\tthrow new Error(`invalid variable name \"${name}\"`);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._shadows.add(name);\n\t\t\t\t});\n\t\t}\n\n\t\tcreateShadowWrapper(callback, doneCallback, startCallback) {\n\t\t\tconst shadowContext = this;\n\t\t\tlet shadowStore;\n\n\t\t\tif (typeof callback === 'function') {\n\t\t\t\tshadowStore = {};\n\t\t\t\tthis.shadowView.forEach(varName => {\n\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\t\t\tshadowStore[varName] = store[varKey];\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn function (...args) {\n\t\t\t\tif (typeof startCallback === 'function') {\n\t\t\t\t\tstartCallback.apply(this, args);\n\t\t\t\t}\n\n\t\t\t\tif (typeof callback === 'function') {\n\t\t\t\t\tconst shadowNames = Object.keys(shadowStore);\n\t\t\t\t\tconst valueCache  = shadowNames.length > 0 ? {} : null;\n\t\t\t\t\tconst macroParser = Wikifier.Parser.get('macro');\n\t\t\t\t\tlet contextCache;\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t\tcallback.\n\t\t\t\t\t*/\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tCache the existing values of the variables to be shadowed and assign the\n\t\t\t\t\t\t\tshadow values.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tstore[varKey] = shadowStore[varName];\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Cache the existing macro execution context and assign the shadow context.\n\t\t\t\t\t\tcontextCache = macroParser.context;\n\t\t\t\t\t\tmacroParser.context = shadowContext;\n\n\t\t\t\t\t\t// Call the callback function.\n\t\t\t\t\t\tcallback.apply(this, args);\n\t\t\t\t\t}\n\t\t\t\t\tfinally {\n\t\t\t\t\t\t// Revert the macro execution context shadowing.\n\t\t\t\t\t\tif (contextCache !== undefined) {\n\t\t\t\t\t\t\tmacroParser.context = contextCache;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Revert the variable shadowing.\n\t\t\t\t\t\tshadowNames.forEach(varName => {\n\t\t\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\tUpdate the shadow store with the variable's current value, in case it\n\t\t\t\t\t\t\t\twas modified during the callback.\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tshadowStore[varName] = store[varKey];\n\n\t\t\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (typeof doneCallback === 'function') {\n\t\t\t\t\tdoneCallback.apply(this, args);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tcreateDebugView(name, title) {\n\t\t\tthis._debugView = new DebugView(\n\t\t\t\tthis._output,\n\t\t\t\t'macro',\n\t\t\t\tname ? name : this.name,\n\t\t\t\ttitle ? title : this.source\n\t\t\t);\n\n\t\t\tif (this.payload !== null && this.payload.length > 0) {\n\t\t\t\tthis._debugView.modes({ nonvoid : true });\n\t\t\t}\n\n\t\t\tthis._debugViewEnabled = true;\n\t\t\treturn this._debugView;\n\t\t}\n\n\t\tremoveDebugView() {\n\t\t\tif (this._debugView !== null) {\n\t\t\t\tthis._debugView.remove();\n\t\t\t\tthis._debugView = null;\n\t\t\t}\n\n\t\t\tthis._debugViewEnabled = false;\n\t\t}\n\n\t\terror(message, source, stack) {\n\t\t\treturn throwError(this._output, `<<${this.name}>>: ${message}`, source ? source : this.source, stack);\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn MacroContext;\n})();\n\n/***********************************************************************************************************************\n\n\tmacros/macrolib.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Config, DebugView, Engine, Has, L10n, Macro, Patterns, Scripting, SimpleAudio, State, Story,\n\t       TempState, Util, Wikifier, postdisplay, prehistory, storage, toStringOrDefault\n*/\n\n(() => {\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tVariables Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<capture>>\n\t*/\n\tMacro.add('capture', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tif (this.args.raw.length === 0) {\n\t\t\t\treturn this.error('no story/temporary variable list specified');\n\t\t\t}\n\n\t\t\tconst valueCache = {};\n\n\t\t\t/*\n\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t`Wikifier` call.\n\t\t\t*/\n\t\t\ttry {\n\t\t\t\tconst varRe = new RegExp(`(${Patterns.variable})`,'g');\n\t\t\t\tlet match;\n\n\t\t\t\t/*\n\t\t\t\t\tCache the existing values of the variables and add a shadow.\n\t\t\t\t*/\n\t\t\t\twhile ((match = varRe.exec(this.args.raw)) !== null) {\n\t\t\t\t\tconst varName = match[1];\n\t\t\t\t\tconst varKey  = varName.slice(1);\n\t\t\t\t\tconst store   = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\tif (store.hasOwnProperty(varKey)) {\n\t\t\t\t\t\tvalueCache[varKey] = store[varKey];\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.addShadow(varName);\n\t\t\t\t}\n\n\t\t\t\tnew Wikifier(this.output, this.payload[0].contents);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\t// Revert the variable shadowing.\n\t\t\t\tthis.shadows.forEach(varName => {\n\t\t\t\t\tconst varKey = varName.slice(1);\n\t\t\t\t\tconst store  = varName[0] === '$' ? State.variables : State.temporary;\n\n\t\t\t\t\tif (valueCache.hasOwnProperty(varKey)) {\n\t\t\t\t\t\tstore[varKey] = valueCache[varKey];\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdelete store[varKey];\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<set>>\n\t*/\n\tMacro.add('set', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<unset>>\n\t*/\n\tMacro.add('unset', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no story/temporary variable list specified');\n\t\t\t}\n\n\t\t\tconst re = new RegExp(\n\t\t\t\t`State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})`,\n\t\t\t\t'g'\n\t\t\t);\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst store = State[match[1]];\n\t\t\t\tconst name  = match[2];\n\n\t\t\t\tif (store.hasOwnProperty(name)) {\n\t\t\t\t\tdelete store[name];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<remember>>\n\t*/\n\tMacro.add('remember', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\tconst remember = storage.get('remember') || {};\n\t\t\tconst re       = new RegExp(`State\\\\.variables\\\\.(${Patterns.identifier})`, 'g');\n\t\t\tlet match;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst name = match[1];\n\t\t\t\tremember[name] = State.variables[name];\n\t\t\t}\n\n\t\t\tif (!storage.set('remember', remember)) {\n\t\t\t\treturn this.error(`unknown error, cannot remember: ${this.args.raw}`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t},\n\n\t\tinit() {\n\t\t\tconst remember = storage.get('remember');\n\n\t\t\tif (remember) {\n\t\t\t\tObject.keys(remember).forEach(name => State.variables[name] = remember[name]);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<forget>>\n\t*/\n\tMacro.add('forget', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no story variable list specified');\n\t\t\t}\n\n\t\t\tconst remember = storage.get('remember');\n\t\t\tconst re       = new RegExp(`State\\\\.variables\\\\.(${Patterns.identifier})`, 'g');\n\t\t\tlet match;\n\t\t\tlet needStore = false;\n\n\t\t\twhile ((match = re.exec(this.args.full)) !== null) {\n\t\t\t\tconst name = match[1];\n\n\t\t\t\tif (State.variables.hasOwnProperty(name)) {\n\t\t\t\t\tdelete State.variables[name];\n\t\t\t\t}\n\n\t\t\t\tif (remember && remember.hasOwnProperty(name)) {\n\t\t\t\t\tneedStore = true;\n\t\t\t\t\tdelete remember[name];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (needStore) {\n\t\t\t\tif (Object.keys(remember).length === 0) {\n\t\t\t\t\tif (!storage.delete('remember')) {\n\t\t\t\t\t\treturn this.error('unknown error, cannot update remember store');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (!storage.set('remember', remember)) {\n\t\t\t\t\treturn this.error('unknown error, cannot update remember store');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tScripting Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<run>>\n\t*/\n\tMacro.add('run', 'set'); // add <<run>> as an alias of <<set>>\n\n\t/*\n\t\t<<script>>\n\t*/\n\tMacro.add('script', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tconst output = document.createDocumentFragment();\n\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(this.payload[0].contents, output);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.createDebugView();\n\t\t\t}\n\n\t\t\tif (output.hasChildNodes()) {\n\t\t\t\tthis.output.appendChild(output);\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tDisplay Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<include>>\n\t*/\n\tMacro.add('include', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = this.args[0].link;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the passage name.\n\t\t\t\tpassage = this.args[0];\n\t\t\t}\n\n\t\t\tif (!Story.has(passage)) {\n\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tpassage = Story.get(passage);\n\t\t\tlet $el;\n\n\t\t\tif (this.args[1]) {\n\t\t\t\t$el = jQuery(document.createElement(this.args[1]))\n\t\t\t\t\t.addClass(`${passage.domId} macro-${this.name}`)\n\t\t\t\t\t.attr('data-passage', passage.title)\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$el = jQuery(this.output);\n\t\t\t}\n\n\t\t\t$el.wiki(passage.processText());\n\t\t}\n\t});\n\n\t/*\n\t\t<<nobr>>\n\t*/\n\tMacro.add('nobr', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\t/*\n\t\t\t\tWikify the contents, after removing all leading & trailing newlines and compacting\n\t\t\t\tall internal sequences of newlines into single spaces.\n\t\t\t*/\n\t\t\tnew Wikifier(this.output, this.payload[0].contents.replace(/^\\n+|\\n+$/g, '').replace(/\\n+/g, ' '));\n\t\t}\n\t});\n\n\t/*\n\t\t<<print>>, <<=>>, & <<->>\n\t*/\n\tMacro.add(['print', '=', '-'], {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = toStringOrDefault(Scripting.evalJavaScript(this.args.full), null);\n\n\t\t\t\tif (result !== null) {\n\t\t\t\t\tnew Wikifier(this.output, this.name === '-' ? Util.escape(result) : result);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<silently>>\n\t*/\n\tMacro.add('silently', {\n\t\tskipArgs : true,\n\t\ttags     : null,\n\n\t\thandler() {\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, this.payload[0].contents.trim());\n\n\t\t\tif (Config.debug) {\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tthis.debugView.modes({ block : true, hidden : true });\n\t\t\t\tthis.output.appendChild(frag);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Discard the output, unless there were errors.\n\t\t\t\tconst errList = [...frag.querySelectorAll('.error')].map(errEl => errEl.textContent);\n\n\t\t\t\tif (errList.length > 0) {\n\t\t\t\t\treturn this.error(`error${errList.length === 1 ? '' : 's'} within contents (${errList.join('; ')})`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] <<display>>\n\t*/\n\tMacro.add('display', 'include'); // add <<display>> as an alias of <<include>>\n\n\n\t/*******************************************************************************************************************\n\t\tControl Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<if>>, <<elseif>>, & <<else>>\n\t*/\n\tMacro.add('if', {\n\t\tskipArgs : true,\n\t\ttags     : ['elseif', 'else'],\n\n\t\thandler() {\n\t\t\tlet i;\n\n\t\t\ttry {\n\t\t\t\tconst len = this.payload.length;\n\n\t\t\t\t// Sanity checks.\n\t\t\t\tfor (/* declared previously */ i = 0; i < len; ++i) {\n\t\t\t\t\t/* eslint-disable prefer-template */\n\t\t\t\t\tswitch (this.payload[i].name) {\n\t\t\t\t\tcase 'else':\n\t\t\t\t\t\tif (this.payload[i].args.raw.length > 0) {\n\t\t\t\t\t\t\tif (/^\\s*if\\b/i.test(this.payload[i].args.raw)) {\n\t\t\t\t\t\t\t\treturn this.error(`whitespace is not allowed between the \"else\" and \"if\" in <<elseif>> clause${i > 0 ? ' (#' + i + ')' : ''}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn this.error(`<<else>> does not accept a conditional expression (perhaps you meant to use <<elseif>>), invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (i + 1 !== len) {\n\t\t\t\t\t\t\treturn this.error('<<else>> must be the final clause');\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif (this.payload[i].args.full.length === 0) {\n\t\t\t\t\t\t\treturn this.error(`no conditional expression specified for <<${this.payload[i].name}>> clause${i > 0 ? ' (#' + i + ')' : ''}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (\n\t\t\t\t\t\t\t   Config.macros.ifAssignmentError\n\t\t\t\t\t\t\t&& /[^!=&^|<>*/%+-]=[^=>]/.test(this.payload[i].args.full)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn this.error(`assignment operator found within <<${this.payload[i].name}>> clause${i > 0 ? ' (#' + i + ')' : ''} (perhaps you meant to use an equality operator: ==, ===, eq, is), invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t/* eslint-enable prefer-template */\n\t\t\t\t}\n\n\t\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\t\tlet success = false;\n\n\t\t\t\t// Evaluate the clauses.\n\t\t\t\tfor (/* declared previously */ i = 0; i < len; ++i) {\n\t\t\t\t\t// Custom debug view setup for the current clause.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({ nonvoid : false });\n\t\t\t\t\t}\n\n\t\t\t\t\t// Conditional test.\n\t\t\t\t\tif (this.payload[i].name === 'else' || !!evalJavaScript(this.payload[i].args.full)) {\n\t\t\t\t\t\tsuccess = true;\n\t\t\t\t\t\tnew Wikifier(this.output, this.payload[i].contents);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse if (Config.debug) {\n\t\t\t\t\t\t// Custom debug view setup for a failed conditional.\n\t\t\t\t\t\tthis.debugView.modes({\n\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup for the remaining clauses.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tfor (++i; i < len; ++i) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t\tFake a debug view for `<</if>>`.  We do this to aid the checking of nesting\n\t\t\t\t\t\tand as a quick indicator of if any of the clauses matched.\n\t\t\t\t\t*/\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : !success,\n\t\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad conditional expression in <<${i === 0 ? 'if' : 'elseif'}>> clause${i > 0 ? ' (#' + i + ')' : ''}: ${typeof ex === 'object' ? `${ex.name}: ${ex.message}` : ex}`, null, ex.stack); // eslint-disable-line prefer-template\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<switch>>, <<case>>, & <<default>>\n\t*/\n\tMacro.add('switch', {\n\t\tskipArgs : ['switch'],\n\t\ttags     : ['case', 'default'],\n\n\t\thandler() {\n\t\t\tif (this.args.full.length === 0) {\n\t\t\t\treturn this.error('no expression specified');\n\t\t\t}\n\n\t\t\tconst len = this.payload.length;\n\n\t\t\t// if (len === 1 || !this.payload.some(p => p.name === 'case')) {\n\t\t\tif (len === 1) {\n\t\t\t\treturn this.error('no cases specified');\n\t\t\t}\n\n\t\t\tlet i;\n\n\t\t\t// Sanity checks.\n\t\t\tfor (/* declared previously */ i = 1; i < len; ++i) {\n\t\t\t\tswitch (this.payload[i].name) {\n\t\t\t\tcase 'default':\n\t\t\t\t\tif (this.payload[i].args.length > 0) {\n\t\t\t\t\t\treturn this.error(`<<default>> does not accept values, invalid: ${this.payload[i].args.raw}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (i + 1 !== len) {\n\t\t\t\t\t\treturn this.error('<<default>> must be the final case');\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tif (this.payload[i].args.length === 0) {\n\t\t\t\t\t\treturn this.error(`no value(s) specified for <<${this.payload[i].name}>> (#${i})`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet result;\n\n\t\t\ttry {\n\t\t\t\tresult = Scripting.evalJavaScript(this.args.full);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\n\t\t\tconst debugView = this.debugView; // cache it now, to be modified later\n\t\t\tlet success = false;\n\n\t\t\t// Initial debug view setup for `<<switch>>`.\n\t\t\tif (Config.debug) {\n\t\t\t\tdebugView\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true\n\t\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Evaluate the clauses.\n\t\t\tfor (/* declared previously */ i = 1; i < len; ++i) {\n\t\t\t\t// Custom debug view setup for the current case.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t.modes({ nonvoid : false });\n\t\t\t\t}\n\n\t\t\t\t// Case test(s).\n\t\t\t\tif (this.payload[i].name === 'default' || this.payload[i].args.some(val => val === result)) {\n\t\t\t\t\tsuccess = true;\n\t\t\t\t\tnew Wikifier(this.output, this.payload[i].contents);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (Config.debug) {\n\t\t\t\t\t// Custom debug view setup for a failed case.\n\t\t\t\t\tthis.debugView.modes({\n\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup for the remaining cases.\n\t\t\tif (Config.debug) {\n\t\t\t\tfor (++i; i < len; ++i) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true,\n\t\t\t\t\t\t\tinvalid : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t/*\n\t\t\t\t\tFinalize the debug view for `<<switch>>` and fake a debug view for `<</switch>>`.\n\t\t\t\t\tWe do both as a quick indicator of if any of the cases matched and the latter\n\t\t\t\t\tto aid the checking of nesting.\n\t\t\t\t*/\n\t\t\t\tdebugView\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true, // !success,\n\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t});\n\t\t\t\tthis\n\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t.modes({\n\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\thidden  : true, // !success,\n\t\t\t\t\t\tinvalid : !success\n\t\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<for>>, <<break>>, & <<continue>>\n\t*/\n\tMacro.add('for', {\n\t\t/* eslint-disable max-len */\n\t\tskipArgs    : true,\n\t\ttags        : null,\n\t\t_hasRangeRe : new RegExp(`^\\\\S${Patterns.anyChar}*?\\\\s+range\\\\s+\\\\S${Patterns.anyChar}*?$`),\n\t\t_rangeRe    : new RegExp(`^(?:State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})\\\\s*,\\\\s*)?State\\\\.(variables|temporary)\\\\.(${Patterns.identifier})\\\\s+range\\\\s+(\\\\S${Patterns.anyChar}*?)$`),\n\t\t_3PartRe    : /^([^;]*?)\\s*;\\s*([^;]*?)\\s*;\\s*([^;]*?)$/,\n\t\t/* eslint-enable max-len */\n\n\t\thandler() {\n\t\t\tconst argsStr = this.args.full.trim();\n\t\t\tconst payload = this.payload[0].contents.replace(/\\n$/, '');\n\n\t\t\t// Empty form.\n\t\t\tif (argsStr.length === 0) {\n\t\t\t\tthis.self._handleFor.call(this, payload, null, true, null);\n\t\t\t}\n\n\t\t\t// Range form.\n\t\t\telse if (this.self._hasRangeRe.test(argsStr)) {\n\t\t\t\tconst parts = argsStr.match(this.self._rangeRe);\n\n\t\t\t\tif (parts === null) {\n\t\t\t\t\treturn this.error('invalid range form syntax, format: [index ,] value range collection');\n\t\t\t\t}\n\n\t\t\t\tthis.self._handleForRange.call(\n\t\t\t\t\tthis,\n\t\t\t\t\tpayload,\n\t\t\t\t\t{ type : parts[1], name : parts[2] },\n\t\t\t\t\t{ type : parts[3], name : parts[4] },\n\t\t\t\t\tparts[5]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Conditional forms.\n\t\t\telse {\n\t\t\t\tlet init;\n\t\t\t\tlet condition;\n\t\t\t\tlet post;\n\n\t\t\t\t// Conditional-only form.\n\t\t\t\tif (argsStr.indexOf(';') === -1) {\n\t\t\t\t\t// Sanity checks.\n\t\t\t\t\tif (/^\\S+\\s+in\\s+\\S+/i.test(argsStr)) {\n\t\t\t\t\t\treturn this.error('invalid syntax, for…in is not supported; see: for…range');\n\t\t\t\t\t}\n\t\t\t\t\telse if (/^\\S+\\s+of\\s+\\S+/i.test(argsStr)) {\n\t\t\t\t\t\treturn this.error('invalid syntax, for…of is not supported; see: for…range');\n\t\t\t\t\t}\n\n\t\t\t\t\tcondition = argsStr;\n\t\t\t\t}\n\n\t\t\t\t// 3-part conditional form.\n\t\t\t\telse {\n\t\t\t\t\tconst parts = argsStr.match(this.self._3PartRe);\n\n\t\t\t\t\tif (parts === null) {\n\t\t\t\t\t\treturn this.error('invalid 3-part conditional form syntax, format: [init] ; [condition] ; [post]');\n\t\t\t\t\t}\n\n\t\t\t\t\tinit      = parts[1];\n\t\t\t\t\tcondition = parts[2].trim();\n\t\t\t\t\tpost      = parts[3];\n\n\t\t\t\t\tif (condition.length === 0) {\n\t\t\t\t\t\tcondition = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis.self._handleFor.call(this, payload, init, condition, post);\n\t\t\t}\n\t\t},\n\n\t\t_handleFor(payload, init, condition, post) {\n\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\tlet first  = true;\n\t\t\tlet safety = Config.macros.maxLoopIterations;\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tTempState.break = null;\n\n\t\t\t\tif (init) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tevalJavaScript(init);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn this.error(`bad init expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\twhile (evalJavaScript(condition)) {\n\t\t\t\t\tif (--safety < 0) {\n\t\t\t\t\t\treturn this.error(`exceeded configured maximum loop iterations (${Config.macros.maxLoopIterations})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tnew Wikifier(this.output, first ? payload.replace(/^\\n/, '') : payload);\n\n\t\t\t\t\tif (first) {\n\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tif (TempState.break === 1) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (TempState.break === 2) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (post) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tevalJavaScript(post);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\treturn this.error(`bad post expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`bad conditional expression: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tTempState.break = null;\n\t\t\t}\n\t\t},\n\n\t\t_handleForRange(payload, indexVar, valueVar, rangeExp) {\n\t\t\tlet first     = true;\n\t\t\tlet rangeList;\n\n\t\t\ttry {\n\t\t\t\trangeList = this.self._toRangeList(rangeExp);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(ex.message);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tTempState.break = null;\n\n\t\t\t\tfor (let i = 0; i < rangeList.length; ++i) {\n\t\t\t\t\tif (indexVar.name) {\n\t\t\t\t\t\tState[indexVar.type][indexVar.name] = rangeList[i][0];\n\t\t\t\t\t}\n\n\t\t\t\t\tState[valueVar.type][valueVar.name] = rangeList[i][1];\n\n\t\t\t\t\tnew Wikifier(this.output, first ? payload.replace(/^\\n/, '') : payload);\n\n\t\t\t\t\tif (first) {\n\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (TempState.break != null) { // lazy equality for null\n\t\t\t\t\t\tif (TempState.break === 1) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (TempState.break === 2) {\n\t\t\t\t\t\t\tTempState.break = null;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tTempState.break = null;\n\t\t\t}\n\t\t},\n\n\t\t_toRangeList(rangeExp) {\n\t\t\tconst evalJavaScript = Scripting.evalJavaScript;\n\t\t\tlet value;\n\n\t\t\ttry {\n\t\t\t\t/*\n\t\t\t\t\tNOTE: If the first character is the left curly brace, then we\n\t\t\t\t\tassume that it's part of an object literal and wrap it within\n\t\t\t\t\tparenthesis to ensure that it is not mistaken for a block\n\t\t\t\t\tduring evaluation—which would cause an error.\n\t\t\t\t*/\n\t\t\t\tvalue = evalJavaScript(rangeExp[0] === '{' ? `(${rangeExp})` : rangeExp);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tif (typeof ex !== 'object') {\n\t\t\t\t\tthrow new Error(`bad range expression: ${ex}`);\n\t\t\t\t}\n\n\t\t\t\tex.message = `bad range expression: ${ex.message}`;\n\t\t\t\tthrow ex;\n\t\t\t}\n\n\t\t\tlet list;\n\n\t\t\tswitch (typeof value) {\n\t\t\tcase 'string':\n\t\t\t\tlist = [];\n\t\t\t\tfor (let i = 0; i < value.length; /* empty */) {\n\t\t\t\t\tconst obj = Util.charAndPosAt(value, i);\n\t\t\t\t\tlist.push([i, obj.char]);\n\t\t\t\t\ti = 1 + obj.end;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'object':\n\t\t\t\tif (Array.isArray(value)) {\n\t\t\t\t\tlist = value.map((val, i) => [i, val]);\n\t\t\t\t}\n\t\t\t\telse if (value instanceof Set) {\n\t\t\t\t\tlist = [...value].map((val, i) => [i, val]);\n\t\t\t\t}\n\t\t\t\telse if (value instanceof Map) {\n\t\t\t\t\tlist = [...value.entries()];\n\t\t\t\t}\n\t\t\t\telse if (Util.toStringTag(value) === 'Object') {\n\t\t\t\t\tlist = Object.keys(value).map(key => [key, value[key]]);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new Error(`unsupported range expression type: ${Util.toStringTag(value)}`);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unsupported range expression type: ${typeof value}`);\n\t\t\t}\n\n\t\t\treturn list;\n\t\t}\n\t});\n\tMacro.add(['break', 'continue'], {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (this.contextHas(ctx => ctx.name === 'for')) {\n\t\t\t\tTempState.break = this.name === 'continue' ? 1 : 2;\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn this.error('must only be used in conjunction with its parent macro <<for>>');\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tInteractive Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<button>> & <<link>>\n\t*/\n\tMacro.add(['button', 'link'], {\n\t\tisAsync : true,\n\t\ttags    : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error(`no ${this.name === 'button' ? 'button' : 'link'} text specified`);\n\t\t\t}\n\n\t\t\tconst $link = jQuery(document.createElement(this.name === 'button' ? 'button' : 'a'));\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\tconst $image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t.attr('src', this.args[0].source)\n\t\t\t\t\t\t.appendTo($link);\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t}\n\n\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t$link.append(document.createTextNode(this.args[0].text));\n\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the link text.\n\t\t\t\t$link.wikiWithOptions({ profile : 'core' }, this.args[0]);\n\t\t\t\tpassage = this.args.length > 1 ? this.args[1] : undefined;\n\t\t\t}\n\n\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t$link.attr('data-passage', passage);\n\n\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t$link.addClass('link-internal');\n\n\t\t\t\t\tif (Config.addVisitedLinkClass && State.hasPlayed(passage)) {\n\t\t\t\t\t\t$link.addClass('link-visited');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$link.addClass('link-broken');\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$link.addClass('link-internal');\n\t\t\t}\n\n\t\t\t$link\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tnamespace : '.macros',\n\t\t\t\t\tone       : passage != null // lazy equality for null\n\t\t\t\t}, this.createShadowWrapper(\n\t\t\t\t\tthis.payload[0].contents !== ''\n\t\t\t\t\t\t? () => Wikifier.wikifyEval(this.payload[0].contents.trim())\n\t\t\t\t\t\t: null,\n\t\t\t\t\tpassage != null // lazy equality for null\n\t\t\t\t\t\t? () => Engine.play(passage)\n\t\t\t\t\t\t: null\n\t\t\t\t))\n\t\t\t\t.appendTo(this.output);\n\t\t}\n\t});\n\n\t/*\n\t\t<<checkbox>>\n\t*/\n\tMacro.add('checkbox', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 3) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('unchecked value'); }\n\t\t\t\tif (this.args.length < 3) { errors.push('checked value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst uncheckValue = this.args[1];\n\t\t\tconst checkValue   = this.args[2];\n\t\t\tconst el           = document.createElement('input');\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'checkbox',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.checked ? checkValue : uncheckValue);\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and input element to the appropriate value and state, as requested.\n\t\t\t*/\n\t\t\tif (this.args.length > 3 && this.args[3] === 'checked') {\n\t\t\t\tel.checked = true;\n\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tState.setVar(varName, uncheckValue);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<cycle>>, <<listbox>>, <<option>>, & <<optionsfrom>>\n\t*/\n\tMacro.add(['cycle', 'listbox'], {\n\t\tisAsync  : true,\n\t\tskipArgs : ['optionsfrom'],\n\t\ttags     : ['option', 'optionsfrom'],\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no variable name specified');\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId = Util.slugify(varName);\n\t\t\tconst len   = this.payload.length;\n\n\t\t\tif (len === 1) {\n\t\t\t\treturn this.error('no options specified');\n\t\t\t}\n\n\t\t\tconst autoselect = this.args.length > 1 && this.args[1] === 'autoselect';\n\t\t\tconst options    = [];\n\t\t\tconst tagCount   = { option : 0, optionsfrom : 0 };\n\t\t\tlet selectedIdx = -1;\n\n\t\t\t// Get the options and selected index, if any.\n\t\t\tfor (let i = 1; i < len; ++i) {\n\t\t\t\tconst payload = this.payload[i];\n\n\t\t\t\t// <<option label value [selected]>>\n\t\t\t\tif (payload.name === 'option') {\n\t\t\t\t\t++tagCount.option;\n\n\t\t\t\t\tif (payload.args.length === 0) {\n\t\t\t\t\t\treturn this.error(`no arguments specified for <<${payload.name}>> (#${tagCount.option})`);\n\t\t\t\t\t}\n\n\t\t\t\t\toptions.push({\n\t\t\t\t\t\tlabel : String(payload.args[0]),\n\t\t\t\t\t\tvalue : payload.args.length === 1 ? payload.args[0] : payload.args[1]\n\t\t\t\t\t});\n\n\t\t\t\t\tif (payload.args.length > 2 && payload.args[2] === 'selected') {\n\t\t\t\t\t\tif (autoselect) {\n\t\t\t\t\t\t\treturn this.error('cannot specify both the autoselect and selected keywords');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (selectedIdx !== -1) {\n\t\t\t\t\t\t\treturn this.error(`multiple selected keywords specified for <<${payload.name}>> (#${selectedIdx + 1} & #${tagCount.option})`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tselectedIdx = options.length - 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// <<optionsfrom expression>>\n\t\t\t\telse {\n\t\t\t\t\t++tagCount.optionsfrom;\n\n\t\t\t\t\tif (payload.args.full.length === 0) {\n\t\t\t\t\t\treturn this.error(`no expression specified for <<${payload.name}>> (#${tagCount.optionsfrom})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet result;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tNOTE: If the first character is the left curly brace, then we\n\t\t\t\t\t\t\tassume that it's part of an object literal and wrap it within\n\t\t\t\t\t\t\tparenthesis to ensure that it is not mistaken for a block\n\t\t\t\t\t\t\tduring evaluation—which would cause an error.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tconst exp = payload.args.full;\n\t\t\t\t\t\tresult = Scripting.evalJavaScript(exp[0] === '{' ? `(${exp})` : exp);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\treturn this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (typeof result !== 'object' || result === null) {\n\t\t\t\t\t\treturn this.error(`expression must yield a supported collection or generic object (type: ${result === null ? 'null' : typeof result})`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (result instanceof Array || result instanceof Set) {\n\t\t\t\t\t\tresult.forEach(val => options.push({ label : String(val), value : val }));\n\t\t\t\t\t}\n\t\t\t\t\telse if (result instanceof Map) {\n\t\t\t\t\t\tresult.forEach((val, key) => options.push({ label : String(key), value : val }));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tconst oType = Util.toStringTag(result);\n\n\t\t\t\t\t\tif (oType !== 'Object') {\n\t\t\t\t\t\t\treturn this.error(`expression must yield a supported collection or generic object (object type: ${oType})`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tObject.keys(result).forEach(key => options.push({ label : key, value : result[key] }));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// No options were selected by the user, so we must select one.\n\t\t\tif (selectedIdx === -1) {\n\t\t\t\t// Attempt to automatically select an option by matching the variable's current value.\n\t\t\t\tif (autoselect) {\n\t\t\t\t\t// NOTE: This will usually fail for objects due to a variety of reasons.\n\t\t\t\t\tconst sameValueZero = Util.sameValueZero;\n\t\t\t\t\tconst curValue      = State.getVar(varName);\n\t\t\t\t\tconst curValueIdx   = options.findIndex(opt => sameValueZero(opt.value, curValue));\n\t\t\t\t\tselectedIdx = curValueIdx === -1 ? 0 : curValueIdx;\n\t\t\t\t}\n\n\t\t\t\t// Simply select the first option.\n\t\t\t\telse {\n\t\t\t\t\tselectedIdx = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set up and append the appropriate element to the output buffer.\n\t\t\tif (this.name === 'cycle') {\n\t\t\t\tlet cycleIdx = selectedIdx;\n\t\t\t\tjQuery(document.createElement('a'))\n\t\t\t\t\t.wikiWithOptions({ profile : 'core' }, options[selectedIdx].label)\n\t\t\t\t\t.attr('id', `${this.name}-${varId}`)\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.ariaClick({ namespace : '.macros' }, this.createShadowWrapper(function () {\n\t\t\t\t\t\tcycleIdx = (cycleIdx + 1) % options.length;\n\t\t\t\t\t\t$(this).empty().wikiWithOptions({ profile : 'core' }, options[cycleIdx].label);\n\t\t\t\t\t\tState.setVar(varName, options[cycleIdx].value);\n\t\t\t\t\t}))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\t\t\telse { // this.name === 'listbox'\n\t\t\t\tconst $select = jQuery(document.createElement('select'));\n\n\t\t\t\toptions.forEach((opt, i) => {\n\t\t\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t\t\t.val(i)\n\t\t\t\t\t\t.text(opt.label)\n\t\t\t\t\t\t.appendTo($select);\n\t\t\t\t});\n\n\t\t\t\t$select\n\t\t\t\t\t.attr({\n\t\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t\t})\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.val(selectedIdx)\n\t\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\t\tState.setVar(varName, options[Number(this.value)].value);\n\t\t\t\t\t}))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t}\n\n\t\t\t// Set the variable to the appropriate value, as requested.\n\t\t\tState.setVar(varName, options[selectedIdx].value);\n\t\t}\n\t});\n\n\t/*\n\t\t<<linkappend>>, <<linkprepend>>, & <<linkreplace>>\n\t*/\n\tMacro.add(['linkappend', 'linkprepend', 'linkreplace'], {\n\t\tisAsync : true,\n\t\ttags    : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no link text specified');\n\t\t\t}\n\n\t\t\tconst $link      = jQuery(document.createElement('a'));\n\t\t\tconst $insert    = jQuery(document.createElement('span'));\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\n\t\t\t$link\n\t\t\t\t.wikiWithOptions({ profile : 'core' }, this.args[0])\n\t\t\t\t.addClass(`link-internal macro-${this.name}`)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tnamespace : '.macros',\n\t\t\t\t\tone       : true\n\t\t\t\t}, this.createShadowWrapper(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tif (this.name === 'linkreplace') {\n\t\t\t\t\t\t\t$link.remove();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t$link\n\t\t\t\t\t\t\t\t.wrap(`<span class=\"macro-${this.name}\"></span>`)\n\t\t\t\t\t\t\t\t.replaceWith(() => $link.html());\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.payload[0].contents !== '') {\n\t\t\t\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\t\t\t\tnew Wikifier(frag, this.payload[0].contents);\n\t\t\t\t\t\t\t$insert.append(frag);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (transition) {\n\t\t\t\t\t\t\tsetTimeout(() => $insert.removeClass(`macro-${this.name}-in`), Engine.minDomActionDelay);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t$insert.addClass(`macro-${this.name}-insert`);\n\n\t\t\tif (transition) {\n\t\t\t\t$insert.addClass(`macro-${this.name}-in`);\n\t\t\t}\n\n\t\t\tif (this.name === 'linkprepend') {\n\t\t\t\t$insert.insertBefore($link);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$insert.insertAfter($link);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<radiobutton>>\n\t*/\n\tMacro.add('radiobutton', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('checked value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\tconst varId      = Util.slugify(varName);\n\t\t\tconst checkValue = this.args[1];\n\t\t\tconst el         = document.createElement('input');\n\n\t\t\t/*\n\t\t\t\tSet up and initialize the group counter.\n\t\t\t*/\n\t\t\tif (!TempState.hasOwnProperty(this.name)) {\n\t\t\t\tTempState[this.name] = {};\n\t\t\t}\n\n\t\t\tif (!TempState[this.name].hasOwnProperty(varId)) {\n\t\t\t\tTempState[this.name][varId] = 0;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}-${TempState[this.name][varId]++}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'radio',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tif (this.checked) {\n\t\t\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable to the checked value and the input element to checked, if requested.\n\t\t\t*/\n\t\t\tif (this.args.length > 2 && this.args[2] === 'checked') {\n\t\t\t\tel.checked = true;\n\t\t\t\tState.setVar(varName, checkValue);\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<textarea>>\n\t*/\n\tMacro.add('textarea', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('default value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst defaultValue = this.args[1];\n\t\t\tconst autofocus    = this.args[2] === 'autofocus';\n\t\t\tconst el           = document.createElement('textarea');\n\n\t\t\t/*\n\t\t\t\tSet up and append the textarea element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\trows     : 4,\n\t\t\t\t\t// cols     : 68, // instead of setting \"cols\" we set the `min-width` in CSS\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.value);\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and textarea element to the default value.\n\t\t\t*/\n\t\t\tState.setVar(varName, defaultValue);\n\t\t\t// Ideally, we should be setting `.defaultValue` here, but IE doesn't support it,\n\t\t\t// so we have to use `.textContent`, which is equivalent.\n\t\t\tel.textContent = defaultValue;\n\n\t\t\t/*\n\t\t\t\tAutofocus the textarea element, if requested.\n\t\t\t*/\n\t\t\tif (autofocus) {\n\t\t\t\t// Set the element's \"autofocus\" attribute.\n\t\t\t\tel.setAttribute('autofocus', 'autofocus');\n\n\t\t\t\t// Set up a single-use post-display task to autofocus the element.\n\t\t\t\tpostdisplay[`#autofocus:${el.id}`] = task => {\n\t\t\t\t\tdelete postdisplay[task]; // single-use task\n\t\t\t\t\tsetTimeout(() => el.focus(), Engine.minDomActionDelay);\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<textbox>>\n\t*/\n\tMacro.add('textbox', {\n\t\tisAsync : true,\n\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('variable name'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('default value'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\t// Ensure that the variable name argument is a string.\n\t\t\tif (typeof this.args[0] !== 'string') {\n\t\t\t\treturn this.error('variable name argument is not a string');\n\t\t\t}\n\n\t\t\tconst varName = this.args[0].trim();\n\n\t\t\t// Try to ensure that we receive the variable's name (incl. sigil), not its value.\n\t\t\tif (varName[0] !== '$' && varName[0] !== '_') {\n\t\t\t\treturn this.error(`variable name \"${this.args[0]}\" is missing its sigil ($ or _)`);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst varId        = Util.slugify(varName);\n\t\t\tconst defaultValue = this.args[1];\n\t\t\tconst el           = document.createElement('input');\n\t\t\tlet autofocus = false;\n\t\t\tlet passage;\n\n\t\t\tif (this.args.length > 3) {\n\t\t\t\tpassage   = this.args[2];\n\t\t\t\tautofocus = this.args[3] === 'autofocus';\n\t\t\t}\n\t\t\telse if (this.args.length > 2) {\n\t\t\t\tif (this.args[2] === 'autofocus') {\n\t\t\t\t\tautofocus = true;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tpassage = this.args[2];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (typeof passage === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = passage.link;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet up and append the input element to the output buffer.\n\t\t\t*/\n\t\t\tjQuery(el)\n\t\t\t\t.attr({\n\t\t\t\t\tid       : `${this.name}-${varId}`,\n\t\t\t\t\tname     : `${this.name}-${varId}`,\n\t\t\t\t\ttype     : 'text',\n\t\t\t\t\ttabindex : 0 // for accessiblity\n\t\t\t\t})\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.on('change.macros', this.createShadowWrapper(function () {\n\t\t\t\t\tState.setVar(varName, this.value);\n\t\t\t\t}))\n\t\t\t\t.on('keypress.macros', this.createShadowWrapper(function (ev) {\n\t\t\t\t\t// If Return/Enter is pressed, set the variable and, optionally, forward to another passage.\n\t\t\t\t\tif (ev.which === 13) { // 13 is Return/Enter\n\t\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t\tState.setVar(varName, this.value);\n\n\t\t\t\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t/*\n\t\t\t\tSet the variable and input element to the default value.\n\t\t\t*/\n\t\t\tState.setVar(varName, defaultValue);\n\t\t\tel.value = defaultValue;\n\n\t\t\t/*\n\t\t\t\tAutofocus the input element, if requested.\n\t\t\t*/\n\t\t\tif (autofocus) {\n\t\t\t\t// Set the element's \"autofocus\" attribute.\n\t\t\t\tel.setAttribute('autofocus', 'autofocus');\n\n\t\t\t\t// Set up a single-use post-display task to autofocus the element.\n\t\t\t\tpostdisplay[`#autofocus:${el.id}`] = task => {\n\t\t\t\t\tdelete postdisplay[task]; // single-use task\n\t\t\t\t\tsetTimeout(() => el.focus(), Engine.minDomActionDelay);\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t[DEPRECATED] <<click>>\n\t*/\n\tMacro.add('click', 'link'); // add <<click>> as an alias of <<link>>\n\n\n\t/*******************************************************************************************************************\n\t\tLinks Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<actions>>\n\t*/\n\tMacro.add('actions', {\n\t\thandler() {\n\t\t\tconst $list = jQuery(document.createElement('ul'))\n\t\t\t\t.addClass(this.name)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\tfor (let i = 0; i < this.args.length; ++i) {\n\t\t\t\tlet passage;\n\t\t\t\tlet text;\n\t\t\t\tlet $image;\n\t\t\t\tlet setFn;\n\n\t\t\t\tif (typeof this.args[i] === 'object') {\n\t\t\t\t\tif (this.args[i].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[i].source);\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[i].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[i].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[i].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[i].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tpassage = this.args[i].link;\n\t\t\t\t\t\tsetFn   = this.args[i].setFn;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\ttext    = this.args[i].text;\n\t\t\t\t\t\tpassage = this.args[i].link;\n\t\t\t\t\t\tsetFn   = this.args[i].setFn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\ttext = passage = this.args[i];\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\t   State.variables.hasOwnProperty('#actions')\n\t\t\t\t\t&& State.variables['#actions'].hasOwnProperty(passage)\n\t\t\t\t\t&& State.variables['#actions'][passage]\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tjQuery(Wikifier.createInternalLink(\n\t\t\t\t\tjQuery(document.createElement('li')).appendTo($list),\n\t\t\t\t\tpassage,\n\t\t\t\t\tnull,\n\t\t\t\t\t((passage, fn) => () => {\n\t\t\t\t\t\tif (!State.variables.hasOwnProperty('#actions')) {\n\t\t\t\t\t\t\tState.variables['#actions'] = {};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tState.variables['#actions'][passage] = true;\n\n\t\t\t\t\t\tif (typeof fn === 'function') {\n\t\t\t\t\t\t\tfn();\n\t\t\t\t\t\t}\n\t\t\t\t\t})(passage, setFn)\n\t\t\t\t))\n\t\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t\t.append($image || document.createTextNode(text));\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<back>> & <<return>>\n\t*/\n\tMacro.add(['back', 'return'], {\n\t\thandler() {\n\t\t\t/* legacy */\n\t\t\tif (this.args.length > 1) {\n\t\t\t\treturn this.error('too many arguments specified, check the documentation for details');\n\t\t\t}\n\t\t\t/* /legacy */\n\n\t\t\tlet momentIndex = -1;\n\t\t\tlet passage;\n\t\t\tlet text;\n\t\t\tlet $image;\n\n\t\t\tif (this.args.length === 1) {\n\t\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[0].source);\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('link')) {\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\tif (this.args[0].count === 1) {\n\t\t\t\t\t\t\t// Simple link syntax: `[[...]]`.\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Pretty link syntax: `[[...|...]]`.\n\t\t\t\t\t\t\ttext    = this.args[0].text;\n\t\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (this.args.length === 1) {\n\t\t\t\t\t// Argument was simply the link text.\n\t\t\t\t\ttext = this.args[0];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\t/*\n\t\t\t\t\tFind the index and title of the most recent moment whose title does not match\n\t\t\t\t\tthat of the active (present) moment's.\n\t\t\t\t*/\n\t\t\t\tfor (let i = State.length - 2; i >= 0; --i) {\n\t\t\t\t\tif (State.history[i].title !== State.passage) {\n\t\t\t\t\t\tmomentIndex = i;\n\t\t\t\t\t\tpassage = State.history[i].title;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If we failed to find a passage and we're `<<return>>`, fallback to `State.expired`.\n\t\t\t\tif (passage == null && this.name === 'return') { // lazy equality for null\n\t\t\t\t\tfor (let i = State.expired.length - 1; i >= 0; --i) {\n\t\t\t\t\t\tif (State.expired[i] !== State.passage) {\n\t\t\t\t\t\t\tpassage = State.expired[i];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (!Story.has(passage)) {\n\t\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tif (this.name === 'back') {\n\t\t\t\t\t/*\n\t\t\t\t\t\tFind the index of the most recent moment whose title matches that of the\n\t\t\t\t\t\tspecified passage.\n\t\t\t\t\t*/\n\t\t\t\t\tfor (let i = State.length - 2; i >= 0; --i) {\n\t\t\t\t\t\tif (State.history[i].title === passage) {\n\t\t\t\t\t\t\tmomentIndex = i;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (momentIndex === -1) {\n\t\t\t\t\t\treturn this.error(`cannot find passage \"${passage}\" in the current story history`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (passage == null) { // lazy equality for null\n\t\t\t\treturn this.error('cannot find passage');\n\t\t\t}\n\n\t\t\t// if (this.name === \"back\" && momentIndex === -1) {\n\t\t\t// \t// no-op; we're already at the first passage in the current story history\n\t\t\t// \treturn;\n\t\t\t// }\n\n\t\t\tlet $el;\n\n\t\t\tif (this.name !== 'back' || momentIndex !== -1) {\n\t\t\t\t$el = jQuery(document.createElement('a'))\n\t\t\t\t\t.addClass('link-internal')\n\t\t\t\t\t.ariaClick(\n\t\t\t\t\t\t{ one : true },\n\t\t\t\t\t\tthis.name === 'return'\n\t\t\t\t\t\t\t? () => Engine.play(passage)\n\t\t\t\t\t\t\t: () => Engine.goTo(momentIndex)\n\t\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$el = jQuery(document.createElement('span'))\n\t\t\t\t\t.addClass('link-disabled');\n\t\t\t}\n\n\t\t\t$el\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.append($image || document.createTextNode(text || L10n.get(`macro${this.name.toUpperFirst()}Text`)))\n\t\t\t\t.appendTo(this.output);\n\t\t}\n\t});\n\n\t/*\n\t\t<<choice>>\n\t*/\n\tMacro.add('choice', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tconst choiceId = State.passage;\n\t\t\tlet passage;\n\t\t\tlet text;\n\t\t\tlet $image;\n\t\t\tlet setFn;\n\n\t\t\tif (this.args.length === 1) {\n\t\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t\tif (this.args[0].isImage) {\n\t\t\t\t\t\t// Argument was in wiki image syntax.\n\t\t\t\t\t\t$image = jQuery(document.createElement('img'))\n\t\t\t\t\t\t\t.attr('src', this.args[0].source);\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('passage')) {\n\t\t\t\t\t\t\t$image.attr('data-passage', this.args[0].passage);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('title')) {\n\t\t\t\t\t\t\t$image.attr('title', this.args[0].title);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (this.args[0].hasOwnProperty('align')) {\n\t\t\t\t\t\t\t$image.attr('align', this.args[0].align);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\tsetFn   = this.args[0].setFn;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\ttext    = this.args[0].text;\n\t\t\t\t\t\tpassage = this.args[0].link;\n\t\t\t\t\t\tsetFn   = this.args[0].setFn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\ttext = passage = this.args[0];\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// NOTE: The arguments here are backwards.\n\t\t\t\tpassage = this.args[0];\n\t\t\t\ttext    = this.args[1];\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t   State.variables.hasOwnProperty('#choice')\n\t\t\t\t&& State.variables['#choice'].hasOwnProperty(choiceId)\n\t\t\t\t&& State.variables['#choice'][choiceId]\n\t\t\t) {\n\t\t\t\tjQuery(document.createElement('span'))\n\t\t\t\t\t.addClass(`link-disabled macro-${this.name}`)\n\t\t\t\t\t.attr('tabindex', -1)\n\t\t\t\t\t.append($image || document.createTextNode(text))\n\t\t\t\t\t.appendTo(this.output);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tjQuery(Wikifier.createInternalLink(this.output, passage, null, () => {\n\t\t\t\tif (!State.variables.hasOwnProperty('#choice')) {\n\t\t\t\t\tState.variables['#choice'] = {};\n\t\t\t\t}\n\n\t\t\t\tState.variables['#choice'][choiceId] = true;\n\n\t\t\t\tif (typeof setFn === 'function') {\n\t\t\t\t\tsetFn();\n\t\t\t\t}\n\t\t\t}))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.append($image || document.createTextNode(text));\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tDOM Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<addclass>> & <<toggleclass>>\n\t*/\n\tMacro.add(['addclass', 'toggleclass'], {\n\t\thandler() {\n\t\t\tif (this.args.length < 2) {\n\t\t\t\tconst errors = [];\n\t\t\t\tif (this.args.length < 1) { errors.push('selector'); }\n\t\t\t\tif (this.args.length < 2) { errors.push('class names'); }\n\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tswitch (this.name) {\n\t\t\tcase 'addclass':\n\t\t\t\t$targets.addClass(this.args[1].trim());\n\t\t\t\tbreak;\n\n\t\t\tcase 'toggleclass':\n\t\t\t\t$targets.toggleClass(this.args[1].trim());\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<removeclass>>\n\t*/\n\tMacro.add('removeclass', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tif (this.args.length > 1) {\n\t\t\t\t$targets.removeClass(this.args[1].trim());\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$targets.removeClass();\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<copy>>\n\t*/\n\tMacro.add('copy', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tjQuery(this.output).append($targets.html());\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<append>>, <<prepend>>, & <<replace>>\n\t*/\n\tMacro.add(['append', 'prepend', 'replace'], {\n\t\ttags : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\tif (this.payload[0].contents !== '') {\n\t\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\t\tlet $insert;\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$insert = jQuery(document.createElement('span'));\n\t\t\t\t\t$insert.addClass(`macro-${this.name}-insert macro-${this.name}-in`);\n\t\t\t\t\tsetTimeout(() => $insert.removeClass(`macro-${this.name}-in`), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$insert = jQuery(document.createDocumentFragment());\n\t\t\t\t}\n\n\t\t\t\t$insert.wiki(this.payload[0].contents);\n\n\t\t\t\tswitch (this.name) {\n\t\t\t\tcase 'replace':\n\t\t\t\t\t$targets.empty();\n\t\t\t\t\t/* falls through */\n\n\t\t\t\tcase 'append':\n\t\t\t\t\t$targets.append($insert);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'prepend':\n\t\t\t\t\t$targets.prepend($insert);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (this.name === 'replace') {\n\t\t\t\t$targets.empty();\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<remove>>\n\t*/\n\tMacro.add('remove', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no selector specified');\n\t\t\t}\n\n\t\t\tconst $targets = jQuery(this.args[0]);\n\n\t\t\tif ($targets.length === 0) {\n\t\t\t\treturn this.error(`no elements matched the selector \"${this.args[0]}\"`);\n\t\t\t}\n\n\t\t\t$targets.remove();\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\n\t/*******************************************************************************************************************\n\t\tAudio Macros.\n\t*******************************************************************************************************************/\n\tif (Has.audio) {\n\t\tconst errorOnePlaybackAction = (cur, prev) => `only one playback action allowed per invocation, \"${cur}\" cannot be combined with \"${prev}\"`;\n\n\t\t/*\n\t\t\t<<audio>>\n\t\t*/\n\t\tMacro.add('audio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\tconst errors = [];\n\t\t\t\t\tif (this.args.length < 1) { errors.push('track and/or group IDs'); }\n\t\t\t\t\tif (this.args.length < 2) { errors.push('actions'); }\n\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t}\n\n\t\t\t\tlet selected;\n\n\t\t\t\t// Process the track and/or group IDs.\n\t\t\t\ttry {\n\t\t\t\t\tselected = SimpleAudio.select(this.args[0]);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\tconst args = this.args.slice(1);\n\t\t\t\tlet action;\n\t\t\t\tlet fadeOver = 5;\n\t\t\t\tlet fadeTo;\n\t\t\t\tlet loop;\n\t\t\t\tlet mute;\n\t\t\t\tlet passage;\n\t\t\t\tlet time;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\tcase 'play':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadein':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 1;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeout':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 0;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('fadeto missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeoverto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length < 2) {\n\t\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\t\tif (args.length < 1) { errors.push('seconds'); }\n\t\t\t\t\t\t\tif (args.length < 2) { errors.push('level'); }\n\t\t\t\t\t\t\treturn this.error(`fadeoverto missing required ${errors.join(' and ')} value${errors.length > 1 ? 's' : ''}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeOver = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeOver) || !Number.isFinite(fadeOver)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'time':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('time missing required seconds value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\ttime = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(time) || !Number.isFinite(time)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse time: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'loop':\n\t\t\t\t\tcase 'unloop':\n\t\t\t\t\t\tloop = arg === 'loop';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'goto':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('goto missing required passage title');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\n\t\t\t\t\t\tif (typeof raw === 'object') {\n\t\t\t\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\t\t\t\tpassage = raw.link;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Argument was simply the passage name.\n\t\t\t\t\t\t\tpassage = raw;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!Story.has(passage)) {\n\t\t\t\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tselected.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (time != null) { // lazy equality for null\n\t\t\t\t\t\tselected.time(time);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tselected.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (loop != null) { // lazy equality for null\n\t\t\t\t\t\tselected.loop(loop);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (passage != null) { // lazy equality for null\n\t\t\t\t\t\tconst nsEnded = `ended.macros.macro-${this.name}_goto`;\n\t\t\t\t\t\tselected\n\t\t\t\t\t\t\t.off(nsEnded)\n\t\t\t\t\t\t\t.one(nsEnded, () => {\n\t\t\t\t\t\t\t\tselected.off(nsEnded);\n\t\t\t\t\t\t\t\tEngine.play(passage);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'fade':\n\t\t\t\t\t\tselected.fade(fadeOver, fadeTo);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tselected.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\t\tselected.pause();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'play':\n\t\t\t\t\t\tselected.playWhenAllowed();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tselected.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tselected.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<cacheaudio track_id source_list>>\n\t\t*/\n\t\tMacro.add('cacheaudio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\tconst errors = [];\n\t\t\t\t\tif (this.args.length < 1) { errors.push('track ID'); }\n\t\t\t\t\tif (this.args.length < 2) { errors.push('sources'); }\n\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t}\n\n\t\t\t\tconst id       = String(this.args[0]).trim();\n\t\t\t\tconst oldFmtRe = /^format:\\s*([\\w-]+)\\s*;\\s*/i;\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.tracks.add(id, this.args.slice(1).map(source => {\n\t\t\t\t\t\t/* legacy */\n\t\t\t\t\t\t// Transform an old format specifier into the new style.\n\t\t\t\t\t\tif (oldFmtRe.test(source)) {\n\t\t\t\t\t\t\t// If in Test Mode, return an error.\n\t\t\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\t\t\treturn this.error(`track ID \"${id}\": format specifier migration required, \"format:formatId;\" \\u2192 \"formatId|\"`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tsource = source.replace(oldFmtRe, '$1|'); // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn source;\n\t\t\t\t\t\t/* /legacy */\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// If in Test Mode and no supported sources were specified, return an error.\n\t\t\t\tif (Config.debug && !SimpleAudio.tracks.get(id).hasSource()) {\n\t\t\t\t\treturn this.error(`track ID \"${id}\": no supported audio sources found`);\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<createaudiogroup group_id>>\n\t\t\t\t<<track track_id>>\n\t\t\t\t…\n\t\t\t<</createaudiogroup>>\n\t\t*/\n\t\tMacro.add('createaudiogroup', {\n\t\t\ttags : ['track'],\n\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no group ID specified');\n\t\t\t\t}\n\n\t\t\t\tif (this.payload.length === 1) {\n\t\t\t\t\treturn this.error('no tracks defined via <<track>>');\n\t\t\t\t}\n\n\t\t\t\t// Initial debug view setup for `<<createaudiogroup>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst groupId  = String(this.args[0]).trim();\n\t\t\t\tconst trackIds = [];\n\n\t\t\t\tfor (let i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\tif (this.payload[i].args.length < 1) {\n\t\t\t\t\t\treturn this.error('no track ID specified');\n\t\t\t\t\t}\n\n\t\t\t\t\ttrackIds.push(String(this.payload[i].args[0]).trim());\n\n\t\t\t\t\t// Custom debug view setup for the current `<<track>>`.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.groups.add(groupId, trackIds);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Custom fake debug view setup for `<</createaudiogroup>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<createplaylist list_id>>\n\t\t\t\t<<track track_id action_list>>\n\t\t\t\t…\n\t\t\t<</createplaylist>>\n\t\t*/\n\t\tMacro.add('createplaylist', {\n\t\t\ttags : ['track'],\n\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no list ID specified');\n\t\t\t\t}\n\n\t\t\t\tif (this.payload.length === 1) {\n\t\t\t\t\treturn this.error('no tracks defined via <<track>>');\n\t\t\t\t}\n\n\t\t\t\tconst playlist = Macro.get('playlist');\n\n\t\t\t\tif (playlist.from !== null && playlist.from !== 'createplaylist') {\n\t\t\t\t\treturn this.error('a playlist has already been defined with <<setplaylist>>');\n\t\t\t\t}\n\n\t\t\t\t// Initial debug view setup for `<<createplaylist>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst listId    = String(this.args[0]).trim();\n\t\t\t\tconst trackObjs = [];\n\n\t\t\t\tfor (let i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\tif (this.payload[i].args.length === 0) {\n\t\t\t\t\t\treturn this.error('no track ID specified');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst trackObj = { id : String(this.payload[i].args[0]).trim() };\n\t\t\t\t\tconst args     = this.payload[i].args.slice(1);\n\n\t\t\t\t\t// Process arguments.\n\t\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\t\tlet raw;\n\t\t\t\t\t\tlet parsed;\n\n\t\t\t\t\t\tswitch (arg) {\n\t\t\t\t\t\tcase 'copy': // [DEPRECATED]\n\t\t\t\t\t\tcase 'own':\n\t\t\t\t\t\t\ttrackObj.own = true;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'rate':\n\t\t\t\t\t\t\t// if (args.length === 0) {\n\t\t\t\t\t\t\t// \treturn this.error('rate missing required speed value');\n\t\t\t\t\t\t\t// }\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// raw = args.shift();\n\t\t\t\t\t\t\t// parsed = Number.parseFloat(raw);\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// if (Number.isNaN(parsed) || !Number.isFinite(parsed)) {\n\t\t\t\t\t\t\t// \treturn this.error(`cannot parse rate: ${raw}`);\n\t\t\t\t\t\t\t// }\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// trackObj.rate = parsed;\n\t\t\t\t\t\t\tif (args.length > 0) {\n\t\t\t\t\t\t\t\targs.shift();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\t\tparsed = Number.parseFloat(raw);\n\n\t\t\t\t\t\t\tif (Number.isNaN(parsed) || !Number.isFinite(parsed)) {\n\t\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ttrackObj.volume = parsed;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\ttrackObjs.push(trackObj);\n\n\t\t\t\t\t// Custom debug view setup for the current `<<track>>`.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t.createDebugView(this.payload[i].name, this.payload[i].source)\n\t\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.lists.add(listId, trackObjs);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Lock `<<playlist>>` into our syntax.\n\t\t\t\tif (playlist.from === null) {\n\t\t\t\t\tplaylist.from = 'createplaylist';\n\t\t\t\t}\n\n\t\t\t\t// Custom fake debug view setup for `<</createplaylist>>`.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis\n\t\t\t\t\t\t.createDebugView(`/${this.name}`, `<</${this.name}>>`)\n\t\t\t\t\t\t.modes({\n\t\t\t\t\t\t\tnonvoid : false,\n\t\t\t\t\t\t\thidden  : true\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<masteraudio action_list>>\n\t\t*/\n\t\tMacro.add('masteraudio', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no actions specified');\n\t\t\t\t}\n\n\t\t\t\tconst args = this.args.slice(0);\n\t\t\t\tlet action;\n\t\t\t\tlet mute;\n\t\t\t\tlet muteOnHide;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'muteonhide':\n\t\t\t\t\tcase 'nomuteonhide':\n\t\t\t\t\t\tmuteOnHide = arg === 'muteonhide';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (muteOnHide != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.muteOnHidden(muteOnHide);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tSimpleAudio.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tSimpleAudio.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tSimpleAudio.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tSimpleAudio.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<playlist list_id action_list>>  ← <<createplaylist>> syntax\n\t\t\t<<playlist action_list>>          ← <<setplaylist>> syntax\n\t\t*/\n\t\tMacro.add('playlist', {\n\t\t\tfrom : null,\n\n\t\t\thandler() {\n\t\t\t\tconst from = this.self.from;\n\n\t\t\t\tif (from === null) {\n\t\t\t\t\treturn this.error('no playlists have been created');\n\t\t\t\t}\n\n\t\t\t\tlet list;\n\t\t\t\tlet args;\n\n\t\t\t\tif (from === 'createplaylist') {\n\t\t\t\t\tif (this.args.length < 2) {\n\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\tif (this.args.length < 1) { errors.push('list ID'); }\n\t\t\t\t\t\tif (this.args.length < 2) { errors.push('actions'); }\n\t\t\t\t\t\treturn this.error(`no ${errors.join(' or ')} specified`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\t\tif (!SimpleAudio.lists.has(id)) {\n\t\t\t\t\t\treturn this.error(`playlist \"${id}\" does not exist`);\n\t\t\t\t\t}\n\n\t\t\t\t\tlist = SimpleAudio.lists.get(id);\n\t\t\t\t\targs = this.args.slice(1);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\t\treturn this.error('no actions specified');\n\t\t\t\t\t}\n\n\t\t\t\t\tlist = SimpleAudio.lists.get('setplaylist');\n\t\t\t\t\targs = this.args.slice(0);\n\t\t\t\t}\n\n\t\t\t\tlet action;\n\t\t\t\tlet fadeOver = 5;\n\t\t\t\tlet fadeTo;\n\t\t\t\tlet loop;\n\t\t\t\tlet mute;\n\t\t\t\tlet shuffle;\n\t\t\t\tlet volume;\n\n\t\t\t\t// Process arguments.\n\t\t\t\twhile (args.length > 0) {\n\t\t\t\t\tconst arg = args.shift();\n\t\t\t\t\tlet raw;\n\n\t\t\t\t\tswitch (arg) {\n\t\t\t\t\tcase 'load':\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\tcase 'play':\n\t\t\t\t\tcase 'skip':\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = arg;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadein':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 1;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeout':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\tfadeTo = 0;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('fadeto missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'fadeoverto':\n\t\t\t\t\t\tif (action) {\n\t\t\t\t\t\t\treturn this.error(errorOnePlaybackAction(arg, action));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (args.length < 2) {\n\t\t\t\t\t\t\tconst errors = [];\n\t\t\t\t\t\t\tif (args.length < 1) { errors.push('seconds'); }\n\t\t\t\t\t\t\tif (args.length < 2) { errors.push('level'); }\n\t\t\t\t\t\t\treturn this.error(`fadeoverto missing required ${errors.join(' and ')} value${errors.length > 1 ? 's' : ''}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taction = 'fade';\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeOver = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeOver) || !Number.isFinite(fadeOver)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tfadeTo = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(fadeTo) || !Number.isFinite(fadeTo)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse fadeoverto: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'volume':\n\t\t\t\t\t\tif (args.length === 0) {\n\t\t\t\t\t\t\treturn this.error('volume missing required level value');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\traw = args.shift();\n\t\t\t\t\t\tvolume = Number.parseFloat(raw);\n\n\t\t\t\t\t\tif (Number.isNaN(volume) || !Number.isFinite(volume)) {\n\t\t\t\t\t\t\treturn this.error(`cannot parse volume: ${raw}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mute':\n\t\t\t\t\tcase 'unmute':\n\t\t\t\t\t\tmute = arg === 'mute';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'loop':\n\t\t\t\t\tcase 'unloop':\n\t\t\t\t\t\tloop = arg === 'loop';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'shuffle':\n\t\t\t\t\tcase 'unshuffle':\n\t\t\t\t\t\tshuffle = arg === 'shuffle';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn this.error(`unknown action: ${arg}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tif (volume != null) { // lazy equality for null\n\t\t\t\t\t\tlist.volume(volume);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (mute != null) { // lazy equality for null\n\t\t\t\t\t\tlist.mute(mute);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (loop != null) { // lazy equality for null\n\t\t\t\t\t\tlist.loop(loop);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (shuffle != null) { // lazy equality for null\n\t\t\t\t\t\tlist.shuffle(shuffle);\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (action) {\n\t\t\t\t\tcase 'fade':\n\t\t\t\t\t\tlist.fade(fadeOver, fadeTo);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'load':\n\t\t\t\t\t\tlist.load();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'pause':\n\t\t\t\t\t\tlist.pause();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'play':\n\t\t\t\t\t\tlist.playWhenAllowed();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'skip':\n\t\t\t\t\t\tlist.skip();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\tlist.stop();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'unload':\n\t\t\t\t\t\tlist.unload();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Custom debug view setup.\n\t\t\t\t\tif (Config.debug) {\n\t\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`error executing action: ${ex.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<removeaudiogroup group_id>>\n\t\t*/\n\t\tMacro.add('removeaudiogroup', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no group ID specified');\n\t\t\t\t}\n\n\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\tif (!SimpleAudio.groups.has(id)) {\n\t\t\t\t\treturn this.error(`group \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tSimpleAudio.groups.delete(id);\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<removeplaylist list_id>>\n\t\t*/\n\t\tMacro.add('removeplaylist', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no list ID specified');\n\t\t\t\t}\n\n\t\t\t\tconst id = String(this.args[0]).trim();\n\n\t\t\t\tif (!SimpleAudio.lists.has(id)) {\n\t\t\t\t\treturn this.error(`playlist \"${id}\" does not exist`);\n\t\t\t\t}\n\n\t\t\t\tSimpleAudio.lists.delete(id);\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t<<waitforaudio>>\n\t\t*/\n\t\tMacro.add('waitforaudio', {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\tSimpleAudio.loadWithScreen();\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t[DEPRECATED] <<setplaylist track_id_list>>\n\t\t*/\n\t\tMacro.add('setplaylist', {\n\t\t\thandler() {\n\t\t\t\tif (this.args.length === 0) {\n\t\t\t\t\treturn this.error('no track ID(s) specified');\n\t\t\t\t}\n\n\t\t\t\tconst playlist = Macro.get('playlist');\n\n\t\t\t\tif (playlist.from !== null && playlist.from !== 'setplaylist') {\n\t\t\t\t\treturn this.error('playlists have already been defined with <<createplaylist>>');\n\t\t\t\t}\n\n\t\t\t\t// Create the new playlist.\n\t\t\t\ttry {\n\t\t\t\t\tSimpleAudio.lists.add('setplaylist', this.args.slice(0));\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(ex.message);\n\t\t\t\t}\n\n\t\t\t\t// Lock `<<playlist>>` into our syntax.\n\t\t\t\tif (playlist.from === null) {\n\t\t\t\t\tplaylist.from = 'setplaylist';\n\t\t\t\t}\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t\t[DEPRECATED] <<stopallaudio>>\n\t\t*/\n\t\tMacro.add('stopallaudio', {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\tSimpleAudio.select(':all').stop();\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\telse {\n\t\t/* The HTML5 <audio> API appears to be missing or disabled, set up no-op macros. */\n\t\tMacro.add([\n\t\t\t'audio',\n\t\t\t'cacheaudio',\n\t\t\t'createaudiogroup',\n\t\t\t'createplaylist',\n\t\t\t'masteraudio',\n\t\t\t'playlist',\n\t\t\t'removeaudiogroup',\n\t\t\t'removeplaylist',\n\t\t\t'waitforaudio',\n\n\t\t\t// Deprecated.\n\t\t\t'setplaylist',\n\t\t\t'stopallaudio'\n\t\t], {\n\t\t\tskipArgs : true,\n\n\t\t\thandler() {\n\t\t\t\t/* no-op */\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tMiscellaneous Macros.\n\t*******************************************************************************************************************/\n\t/*\n\t\t<<goto>>\n\t*/\n\tMacro.add('goto', {\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no passage specified');\n\t\t\t}\n\n\t\t\tlet passage;\n\n\t\t\tif (typeof this.args[0] === 'object') {\n\t\t\t\t// Argument was in wiki link syntax.\n\t\t\t\tpassage = this.args[0].link;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Argument was simply the passage name.\n\t\t\t\tpassage = this.args[0];\n\t\t\t}\n\n\t\t\tif (!Story.has(passage)) {\n\t\t\t\treturn this.error(`passage \"${passage}\" does not exist`);\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tCall `Engine.play()` asynchronously.\n\n\t\t\t\tNOTE: This does not terminate the current Wikifier call chain,\n\t\t\t\tthough, ideally, it should.  Doing so would not be trivial, however,\n\t\t\t\tand there's also the question of whether that behavior would be\n\t\t\t\tunwanted by users, who are used to the current behavior from\n\t\t\t\tsimilar macros and constructs.\n\t\t\t*/\n\t\t\tsetTimeout(() => Engine.play(passage), Engine.minDomActionDelay);\n\t\t}\n\t});\n\n\t/*\n\t\t<<repeat>> & <<stop>>\n\t*/\n\tMacro.add('repeat', {\n\t\tisAsync : true,\n\t\ttags    : null,\n\t\ttimers  : new Set(),\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no time value specified');\n\t\t\t}\n\n\t\t\tlet delay;\n\n\t\t\ttry {\n\t\t\t\tdelay = Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.args[0]));\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(ex.message);\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\tconst $wrapper   = jQuery(document.createElement('span'))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t// Register the timer.\n\t\t\tthis.self.registerInterval(this.createShadowWrapper(() => {\n\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(frag, this.payload[0].contents);\n\n\t\t\t\tlet $output = $wrapper;\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$output = jQuery(document.createElement('span'))\n\t\t\t\t\t\t.addClass('macro-repeat-insert macro-repeat-in')\n\t\t\t\t\t\t.appendTo($output);\n\t\t\t\t}\n\n\t\t\t\t$output.append(frag);\n\n\t\t\t\tif (transition) {\n\t\t\t\t\tsetTimeout(() => $output.removeClass('macro-repeat-in'), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t}), delay);\n\t\t},\n\n\t\tregisterInterval(callback, delay) {\n\t\t\tif (typeof callback !== 'function') {\n\t\t\t\tthrow new TypeError('callback parameter must be a function');\n\t\t\t}\n\n\t\t\tconst turnId = State.turns;\n\t\t\tconst timers = this.timers;\n\t\t\tlet timerId = null;\n\n\t\t\t// Set up the interval.\n\t\t\ttimerId = setInterval(() => {\n\t\t\t\t// Terminate the timer if the turn IDs do not match.\n\t\t\t\tif (turnId !== State.turns) {\n\t\t\t\t\tclearInterval(timerId);\n\t\t\t\t\ttimers.delete(timerId);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet timerIdCache;\n\t\t\t\t/*\n\t\t\t\t\tThere's no catch clause because this try/finally is here simply to ensure that\n\t\t\t\t\tproper cleanup is done in the event that an exception is thrown during the\n\t\t\t\t\t`Wikifier` call.\n\t\t\t\t*/\n\t\t\t\ttry {\n\t\t\t\t\tTempState.break = null;\n\n\t\t\t\t\t// Set up the `repeatTimerId` value, caching the existing value, if necessary.\n\t\t\t\t\tif (TempState.hasOwnProperty('repeatTimerId')) {\n\t\t\t\t\t\ttimerIdCache = TempState.repeatTimerId;\n\t\t\t\t\t}\n\n\t\t\t\t\tTempState.repeatTimerId = timerId;\n\n\t\t\t\t\t// Execute the callback.\n\t\t\t\t\tcallback.call(this);\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\t// Teardown the `repeatTimerId` property, restoring the cached value, if necessary.\n\t\t\t\t\tif (typeof timerIdCache !== 'undefined') {\n\t\t\t\t\t\tTempState.repeatTimerId = timerIdCache;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tdelete TempState.repeatTimerId;\n\t\t\t\t\t}\n\n\t\t\t\t\tTempState.break = null;\n\t\t\t\t}\n\t\t\t}, delay);\n\t\t\ttimers.add(timerId);\n\n\t\t\t// Set up a single-use `prehistory` task to remove pending timers.\n\t\t\tif (!prehistory.hasOwnProperty('#repeat-timers-cleanup')) {\n\t\t\t\tprehistory['#repeat-timers-cleanup'] = task => {\n\t\t\t\t\tdelete prehistory[task]; // single-use task\n\t\t\t\t\ttimers.forEach(timerId => clearInterval(timerId));\n\t\t\t\t\ttimers.clear();\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\tMacro.add('stop', {\n\t\tskipArgs : true,\n\n\t\thandler() {\n\t\t\tif (!TempState.hasOwnProperty('repeatTimerId')) {\n\t\t\t\treturn this.error('must only be used in conjunction with its parent macro <<repeat>>');\n\t\t\t}\n\n\t\t\tconst timers  = Macro.get('repeat').timers;\n\t\t\tconst timerId = TempState.repeatTimerId;\n\t\t\tclearInterval(timerId);\n\t\t\ttimers.delete(timerId);\n\t\t\tTempState.break = 2;\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<timed>> & <<next>>\n\t*/\n\tMacro.add('timed', {\n\t\tisAsync : true,\n\t\ttags    : ['next'],\n\t\ttimers  : new Set(),\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no time value specified in <<timed>>');\n\t\t\t}\n\n\t\t\tconst items = [];\n\n\t\t\ttry {\n\t\t\t\titems.push({\n\t\t\t\t\tname    : this.name,\n\t\t\t\t\tsource  : this.source,\n\t\t\t\t\tdelay   : Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.args[0])),\n\t\t\t\t\tcontent : this.payload[0].contents\n\t\t\t\t});\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`${ex.message} in <<timed>>`);\n\t\t\t}\n\n\t\t\tif (this.payload.length > 1) {\n\t\t\t\tlet i;\n\n\t\t\t\ttry {\n\t\t\t\t\tlet len;\n\n\t\t\t\t\tfor (i = 1, len = this.payload.length; i < len; ++i) {\n\t\t\t\t\t\titems.push({\n\t\t\t\t\t\t\tname   : this.payload[i].name,\n\t\t\t\t\t\t\tsource : this.payload[i].source,\n\t\t\t\t\t\t\tdelay  : this.payload[i].args.length === 0\n\t\t\t\t\t\t\t\t? items[items.length - 1].delay\n\t\t\t\t\t\t\t\t: Math.max(Engine.minDomActionDelay, Util.fromCssTime(this.payload[i].args[0])),\n\t\t\t\t\t\t\tcontent : this.payload[i].contents\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\treturn this.error(`${ex.message} in <<next>> (#${i})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Custom debug view setup.\n\t\t\tif (Config.debug) {\n\t\t\t\tthis.debugView.modes({ block : true });\n\t\t\t}\n\n\t\t\tconst transition = this.args.length > 1 && /^(?:transition|t8n)$/.test(this.args[1]);\n\t\t\tconst $wrapper   = jQuery(document.createElement('span'))\n\t\t\t\t.addClass(`macro-${this.name}`)\n\t\t\t\t.appendTo(this.output);\n\n\t\t\t// Register the timer.\n\t\t\tthis.self.registerTimeout(this.createShadowWrapper(item => {\n\t\t\t\tconst frag = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(frag, item.content);\n\n\t\t\t\t// Output.\n\t\t\t\tlet $output = $wrapper;\n\n\t\t\t\t// Custom debug view setup for `<<next>>`.\n\t\t\t\tif (Config.debug && item.name === 'next') {\n\t\t\t\t\t$output = jQuery((new DebugView( // eslint-disable-line no-param-reassign\n\t\t\t\t\t\t$output[0],\n\t\t\t\t\t\t'macro',\n\t\t\t\t\t\titem.name,\n\t\t\t\t\t\titem.source\n\t\t\t\t\t)).output);\n\t\t\t\t}\n\n\t\t\t\tif (transition) {\n\t\t\t\t\t$output = jQuery(document.createElement('span'))\n\t\t\t\t\t\t.addClass('macro-timed-insert macro-timed-in')\n\t\t\t\t\t\t.appendTo($output);\n\t\t\t\t}\n\n\t\t\t\t$output.append(frag);\n\n\t\t\t\tif (transition) {\n\t\t\t\t\tsetTimeout(() => $output.removeClass('macro-timed-in'), Engine.minDomActionDelay);\n\t\t\t\t}\n\t\t\t}), items);\n\t\t},\n\n\t\tregisterTimeout(callback, items) {\n\t\t\tif (typeof callback !== 'function') {\n\t\t\t\tthrow new TypeError('callback parameter must be a function');\n\t\t\t}\n\n\t\t\tconst turnId = State.turns;\n\t\t\tconst timers = this.timers;\n\t\t\tlet timerId  = null;\n\t\t\tlet nextItem = items.shift();\n\n\t\t\tconst worker = function () {\n\t\t\t\t// Bookkeeping.\n\t\t\t\ttimers.delete(timerId);\n\n\t\t\t\tif (turnId !== State.turns) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Set the current item and set up the next worker, if any.\n\t\t\t\tconst curItem = nextItem;\n\n\t\t\t\tif ((nextItem = items.shift()) != null) { // lazy equality for null\n\t\t\t\t\ttimerId = setTimeout(worker, nextItem.delay);\n\t\t\t\t\ttimers.add(timerId);\n\t\t\t\t}\n\n\t\t\t\t// Execute the callback.\n\t\t\t\tcallback.call(this, curItem);\n\t\t\t};\n\n\t\t\t// Setup the timeout.\n\t\t\ttimerId = setTimeout(worker, nextItem.delay);\n\t\t\ttimers.add(timerId);\n\n\t\t\t// Set up a single-use `prehistory` task to remove pending timers.\n\t\t\tif (!prehistory.hasOwnProperty('#timed-timers-cleanup')) {\n\t\t\t\tprehistory['#timed-timers-cleanup'] = task => {\n\t\t\t\t\tdelete prehistory[task]; // single-use task\n\t\t\t\t\ttimers.forEach(timerId => clearTimeout(timerId)); // eslint-disable-line no-shadow\n\t\t\t\t\ttimers.clear();\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n\n\t/*\n\t\t<<widget>>\n\t*/\n\tMacro.add('widget', {\n\t\ttags : null,\n\n\t\thandler() {\n\t\t\tif (this.args.length === 0) {\n\t\t\t\treturn this.error('no widget name specified');\n\t\t\t}\n\n\t\t\tconst widgetName = this.args[0];\n\n\t\t\tif (Macro.has(widgetName)) {\n\t\t\t\tif (!Macro.get(widgetName).isWidget) {\n\t\t\t\t\treturn this.error(`cannot clobber existing macro \"${widgetName}\"`);\n\t\t\t\t}\n\n\t\t\t\t// Delete the existing widget.\n\t\t\t\tMacro.delete(widgetName);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tMacro.add(widgetName, {\n\t\t\t\t\tisWidget : true,\n\t\t\t\t\thandler  : (function (contents) {\n\t\t\t\t\t\treturn function () {\n\t\t\t\t\t\t\tlet argsCache;\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t// Cache the existing value of the `$args` variable, if necessary.\n\t\t\t\t\t\t\t\tif (State.variables.hasOwnProperty('args')) {\n\t\t\t\t\t\t\t\t\targsCache = State.variables.args;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Set up the widget `$args` variable and add a shadow.\n\t\t\t\t\t\t\t\tState.variables.args = [...this.args];\n\t\t\t\t\t\t\t\tState.variables.args.raw = this.args.raw;\n\t\t\t\t\t\t\t\tState.variables.args.full = this.args.full;\n\t\t\t\t\t\t\t\tthis.addShadow('$args');\n\n\t\t\t\t\t\t\t\t// Set up the error trapping variables.\n\t\t\t\t\t\t\t\tconst resFrag = document.createDocumentFragment();\n\t\t\t\t\t\t\t\tconst errList = [];\n\n\t\t\t\t\t\t\t\t// Wikify the widget contents.\n\t\t\t\t\t\t\t\tnew Wikifier(resFrag, contents);\n\n\t\t\t\t\t\t\t\t// Carry over the output, unless there were errors.\n\t\t\t\t\t\t\t\tArray.from(resFrag.querySelectorAll('.error')).forEach(errEl => {\n\t\t\t\t\t\t\t\t\terrList.push(errEl.textContent);\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tif (errList.length === 0) {\n\t\t\t\t\t\t\t\t\tthis.output.appendChild(resFrag);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\treturn this.error(`error${errList.length > 1 ? 's' : ''} within widget contents (${errList.join('; ')})`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ex) {\n\t\t\t\t\t\t\t\treturn this.error(`cannot execute widget: ${ex.message}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfinally {\n\t\t\t\t\t\t\t\t// Revert the `$args` variable shadowing.\n\t\t\t\t\t\t\t\tif (typeof argsCache !== 'undefined') {\n\t\t\t\t\t\t\t\t\tState.variables.args = argsCache;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tdelete State.variables.args;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t})(this.payload[0].contents)\n\t\t\t\t});\n\n\t\t\t\t// Custom debug view setup.\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tthis.debugView.modes({ hidden : true });\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn this.error(`cannot create widget macro \"${widgetName}\": ${ex.message}`);\n\t\t\t}\n\t\t}\n\t});\n})();\n\n/***********************************************************************************************************************\n\n\tdialog.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Has, L10n, safeActiveElement */\n\nvar Dialog = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Dialog element caches.\n\tlet _$overlay       = null;\n\tlet _$dialog        = null;\n\tlet _$dialogTitle   = null;\n\tlet _$dialogBody    = null;\n\n\t// The last active/focused non-dialog element.\n\tlet _lastActive     = null;\n\n\t// The width of the browser's scrollbars.\n\tlet _scrollbarWidth = 0;\n\n\t// Dialog mutation resize handler.\n\tlet _dialogObserver = null;\n\n\n\t/*******************************************************************************\n\t\tDialog Functions.\n\t*******************************************************************************/\n\n\t/*\n\t\t[DEPRECATED] Adds a click hander to the target element(s) which opens the dialog modal.\n\t*/\n\tfunction dialogAddClickHandler(targets, options, startFn, doneFn, closeFn) {\n\t\treturn jQuery(targets).ariaClick(ev => {\n\t\t\tev.preventDefault();\n\n\t\t\t// Call the start function.\n\t\t\tif (typeof startFn === 'function') {\n\t\t\t\tstartFn(ev);\n\t\t\t}\n\n\t\t\t// Open the dialog.\n\t\t\tdialogOpen(options, closeFn);\n\n\t\t\t// Call the done function.\n\t\t\tif (typeof doneFn === 'function') {\n\t\t\t\tdoneFn(ev);\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction dialogBodyAppend(...args) {\n\t\t_$dialogBody.append(...args);\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogBody() {\n\t\treturn _$dialogBody.get(0);\n\t}\n\n\tfunction dialogClose(ev) {\n\t\t// Trigger a `:dialogclosing` event on the dialog body.\n\t\t_$dialogBody.trigger(':dialogclosing');\n\n\t\t// Largely reverse the actions taken in `dialogOpen()`.\n\t\tjQuery(document)\n\t\t\t.off('.dialog-close');\n\t\tif (_dialogObserver) {\n\t\t\t_dialogObserver.disconnect();\n\t\t\t_dialogObserver = null;\n\t\t}\n\t\telse {\n\t\t\t_$dialogBody\n\t\t\t\t.off('.dialog-resize');\n\t\t}\n\t\tjQuery(window)\n\t\t\t.off('.dialog-resize');\n\t\t_$dialog\n\t\t\t.removeClass('open')\n\t\t\t.css({ left : '', right : '', top : '', bottom : '' });\n\n\t\tjQuery('#ui-bar,#story')\n\t\t\t.find('[tabindex=-2]')\n\t\t\t.removeAttr('aria-hidden')\n\t\t\t.attr('tabindex', 0);\n\t\tjQuery('body>[tabindex=-3]')\n\t\t\t.removeAttr('aria-hidden')\n\t\t\t.removeAttr('tabindex');\n\n\t\t_$overlay\n\t\t\t.removeClass('open');\n\t\tjQuery(document.documentElement)\n\t\t\t.removeAttr('data-dialog');\n\n\t\t// Clear the dialog's content.\n\t\t_$dialogTitle\n\t\t\t.empty();\n\t\t_$dialogBody\n\t\t\t.empty()\n\t\t\t.removeClass();\n\n\t\t// Attempt to restore focus to whichever element had it prior to opening the dialog.\n\t\tif (_lastActive !== null) {\n\t\t\tjQuery(_lastActive).focus();\n\t\t\t_lastActive = null;\n\t\t}\n\n\t\t// Call the given \"on close\" callback function, if any.\n\t\tif (ev && ev.data && typeof ev.data.closeFn === 'function') {\n\t\t\tev.data.closeFn(ev);\n\t\t}\n\n\t\t// Trigger a `:dialogclosed` event on the dialog body.\n\t\t/* legacy */\n\t\t_$dialogBody.trigger(':dialogclose');\n\t\t/* /legacy */\n\t\t_$dialogBody.trigger(':dialogclosed');\n\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogInit() {\n\t\tif (DEBUG) { console.log('[Dialog/dialogInit()]'); }\n\n\t\tif (document.getElementById('ui-dialog')) {\n\t\t\treturn;\n\t\t}\n\n\t\t/*\n\t\t\tCalculate and cache the width of scrollbars.\n\t\t*/\n\t\t_scrollbarWidth = (() => {\n\t\t\tlet scrollbarWidth;\n\n\t\t\ttry {\n\t\t\t\tconst inner = document.createElement('p');\n\t\t\t\tconst outer = document.createElement('div');\n\n\t\t\t\tinner.style.width      = '100%';\n\t\t\t\tinner.style.height     = '200px';\n\t\t\t\touter.style.position   = 'absolute';\n\t\t\t\touter.style.left       = '0px';\n\t\t\t\touter.style.top        = '0px';\n\t\t\t\touter.style.width      = '100px';\n\t\t\t\touter.style.height     = '100px';\n\t\t\t\touter.style.visibility = 'hidden';\n\t\t\t\touter.style.overflow   = 'hidden';\n\n\t\t\t\touter.appendChild(inner);\n\t\t\t\tdocument.body.appendChild(outer);\n\n\t\t\t\tconst w1 = inner.offsetWidth;\n\t\t\t\t/*\n\t\t\t\t\tThe `overflow: scroll` style property value does not work consistently\n\t\t\t\t\twith scrollbars which are styled with `::-webkit-scrollbar`, so we use\n\t\t\t\t\t`overflow: auto` with dimensions guaranteed to force a scrollbar.\n\t\t\t\t*/\n\t\t\t\touter.style.overflow = 'auto';\n\t\t\t\tlet w2 = inner.offsetWidth;\n\n\t\t\t\tif (w1 === w2) {\n\t\t\t\t\tw2 = outer.clientWidth;\n\t\t\t\t}\n\n\t\t\t\tdocument.body.removeChild(outer);\n\n\t\t\t\tscrollbarWidth = w1 - w2;\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\n\t\t\treturn scrollbarWidth || 17; // 17px is a reasonable failover\n\t\t})();\n\n\t\t/*\n\t\t\tGenerate the dialog elements.\n\t\t*/\n\t\tconst $elems = jQuery(document.createDocumentFragment())\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  '<div id=\"ui-overlay\" class=\"ui-close\"></div>'\n\t\t\t\t+ '<div id=\"ui-dialog\" tabindex=\"0\" role=\"dialog\" aria-labelledby=\"ui-dialog-title\">'\n\t\t\t\t+     '<div id=\"ui-dialog-titlebar\">'\n\t\t\t\t+         '<h1 id=\"ui-dialog-title\"></h1>'\n\t\t\t\t+         `<button id=\"ui-dialog-close\" class=\"ui-close\" tabindex=\"0\" aria-label=\"${L10n.get('close')}\">\\uE804</button>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div id=\"ui-dialog-body\"></div>'\n\t\t\t\t+ '</div>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t);\n\n\t\t/*\n\t\t\tCache the dialog elements, since they're going to be used often.\n\n\t\t\tNOTE: We rewrap the elements themselves, rather than simply using\n\t\t\tthe results of `find()`, so that we cache uncluttered jQuery-wrappers\n\t\t\t(i.e. `context` refers to the elements and there is no `prevObject`).\n\t\t*/\n\t\t_$overlay     = jQuery($elems.find('#ui-overlay').get(0));\n\t\t_$dialog      = jQuery($elems.find('#ui-dialog').get(0));\n\t\t_$dialogTitle = jQuery($elems.find('#ui-dialog-title').get(0));\n\t\t_$dialogBody  = jQuery($elems.find('#ui-dialog-body').get(0));\n\n\t\t/*\n\t\t\tInsert the dialog elements into the page before the main script.\n\t\t*/\n\t\t$elems.insertBefore('body>script#script-sugarcube');\n\t}\n\n\tfunction dialogIsOpen(classNames) {\n\t\treturn _$dialog.hasClass('open')\n\t\t\t&& (classNames ? classNames.splitOrEmpty(/\\s+/).every(cn => _$dialogBody.hasClass(cn)) : true);\n\t}\n\n\tfunction dialogOpen(options, closeFn) {\n\t\t// Trigger a `:dialogopening` event on the dialog body.\n\t\t_$dialogBody.trigger(':dialogopening');\n\n\t\t// Grab the options we care about.\n\t\tconst { top } = jQuery.extend({ top : 50 }, options);\n\n\t\t// Record the last active/focused non-dialog element.\n\t\tif (!dialogIsOpen()) {\n\t\t\t_lastActive = safeActiveElement();\n\t\t}\n\n\t\t// Add the `data-dialog` attribute to <html> (mostly used to style <body>).\n\t\tjQuery(document.documentElement)\n\t\t\t.attr('data-dialog', 'open');\n\n\t\t// Display the overlay.\n\t\t_$overlay\n\t\t\t.addClass('open');\n\n\t\t/*\n\t\t\tAdd the imagesLoaded handler to the dialog body, if necessary.\n\n\t\t\tNOTE: We use `querySelector()` here as jQuery has no simple way to\n\t\t\tcheck if, and only if, at least one element of the specified type\n\t\t\texists.  The best that jQuery offers is analogous to `querySelectorAll()`,\n\t\t\twhich enumerates all elements of the specified type.\n\t\t*/\n\t\tif (_$dialogBody[0].querySelector('img') !== null) {\n\t\t\t_$dialogBody\n\t\t\t\t.imagesLoaded()\n\t\t\t\t.always(() => _resizeHandler({ data : { top } }));\n\t\t}\n\n\t\t// Add `aria-hidden=true` to all direct non-dialog-children of <body> to\n\t\t// hide the underlying page from screen readers while the dialog is open.\n\t\tjQuery('body>:not(script,#store-area,tw-storydata,#ui-bar,#ui-overlay,#ui-dialog)')\n\t\t\t.attr('tabindex', -3)\n\t\t\t.attr('aria-hidden', true);\n\t\tjQuery('#ui-bar,#story')\n\t\t\t.find('[tabindex]:not([tabindex^=-])')\n\t\t\t.attr('tabindex', -2)\n\t\t\t.attr('aria-hidden', true);\n\n\t\t// Display the dialog.\n\t\t_$dialog\n\t\t\t.css(_calcPosition(top))\n\t\t\t.addClass('open')\n\t\t\t.focus();\n\n\t\t// Add the UI resize handler.\n\t\tjQuery(window)\n\t\t\t.on('resize.dialog-resize', null, { top }, jQuery.throttle(40, _resizeHandler));\n\n\t\t// Add the dialog mutation resize handler.\n\t\tif (Has.mutationObserver) {\n\t\t\t_dialogObserver = new MutationObserver(mutations => {\n\t\t\t\tfor (let i = 0; i < mutations.length; ++i) {\n\t\t\t\t\tif (mutations[i].type === 'childList') {\n\t\t\t\t\t\t_resizeHandler({ data : { top } });\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t_dialogObserver.observe(_$dialogBody[0], {\n\t\t\t\tchildList : true,\n\t\t\t\tsubtree   : true\n\t\t\t});\n\t\t}\n\t\telse {\n\t\t\t_$dialogBody\n\t\t\t\t.on(\n\t\t\t\t\t'DOMNodeInserted.dialog-resize DOMNodeRemoved.dialog-resize',\n\t\t\t\t\tnull,\n\t\t\t\t\t{ top },\n\t\t\t\t\tjQuery.throttle(40, _resizeHandler)\n\t\t\t\t);\n\t\t}\n\n\t\t// Set up the delegated UI close handler.\n\t\tjQuery(document)\n\t\t\t.on('click.dialog-close', '.ui-close', { closeFn }, dialogClose)\n\t\t\t.on('keypress.dialog-close', '.ui-close', function (ev) {\n\t\t\t\t// 13 is Enter/Return, 32 is Space.\n\t\t\t\tif (ev.which === 13 || ev.which === 32) {\n\t\t\t\t\tjQuery(this).trigger('click');\n\t\t\t\t}\n\t\t\t});\n\n\t\t// Trigger a `:dialogopened` event on the dialog body.\n\t\t/* legacy */\n\t\t_$dialogBody.trigger(':dialogopen');\n\t\t/* /legacy */\n\t\t_$dialogBody.trigger(':dialogopened');\n\n\t\treturn Dialog;\n\t}\n\n\tfunction dialogResize(data) {\n\t\treturn _resizeHandler(typeof data === 'object' ? { data } : undefined);\n\t}\n\n\tfunction dialogSetup(title, classNames) {\n\t\t_$dialogBody\n\t\t\t.empty()\n\t\t\t.removeClass();\n\n\t\tif (classNames != null) { // lazy equality for null\n\t\t\t_$dialogBody.addClass(classNames);\n\t\t}\n\n\t\t_$dialogTitle\n\t\t\t.empty()\n\t\t\t.append((title != null ? String(title) : '') || '\\u00A0'); // lazy equality for null\n\n\t\t// TODO: In v3 this should return `Dialog` for chaining.\n\t\treturn _$dialogBody.get(0);\n\t}\n\n\tfunction dialogBodyWiki(...args) {\n\t\t_$dialogBody.wiki(...args);\n\t\treturn Dialog;\n\t}\n\n\n\t/*******************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************/\n\n\tfunction _calcPosition(topPos) {\n\t\tconst top       = topPos != null ? topPos : 50; // lazy equality for null\n\t\tconst $parent   = jQuery(window);\n\t\tconst dialogPos = { left : '', right : '', top : '', bottom : '' };\n\n\t\t// Unset the dialog's positional properties before checking its dimensions.\n\t\t_$dialog.css(dialogPos);\n\n\t\tlet horzSpace = $parent.width() - _$dialog.outerWidth(true) - 1;   // -1 to address a Firefox issue\n\t\tlet vertSpace = $parent.height() - _$dialog.outerHeight(true) - 1; // -1 to address a Firefox issue\n\n\t\tif (horzSpace <= 32 + _scrollbarWidth) {\n\t\t\tvertSpace -= _scrollbarWidth;\n\t\t}\n\n\t\tif (vertSpace <= 32 + _scrollbarWidth) {\n\t\t\thorzSpace -= _scrollbarWidth;\n\t\t}\n\n\t\tif (horzSpace <= 32) {\n\t\t\tdialogPos.left = dialogPos.right = 16;\n\t\t}\n\t\telse {\n\t\t\tdialogPos.left = dialogPos.right = horzSpace / 2 >> 0;\n\t\t}\n\n\t\tif (vertSpace <= 32) {\n\t\t\tdialogPos.top = dialogPos.bottom = 16;\n\t\t}\n\t\telse {\n\t\t\tif (vertSpace / 2 > top) {\n\t\t\t\tdialogPos.top = top;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdialogPos.top = dialogPos.bottom = vertSpace / 2 >> 0;\n\t\t\t}\n\t\t}\n\n\t\tObject.keys(dialogPos).forEach(key => {\n\t\t\tif (dialogPos[key] !== '') {\n\t\t\t\tdialogPos[key] += 'px';\n\t\t\t}\n\t\t});\n\n\t\treturn dialogPos;\n\t}\n\n\tfunction _resizeHandler(ev) {\n\t\tconst top = ev && ev.data && typeof ev.data.top !== 'undefined' ? ev.data.top : 50;\n\n\t\tif (_$dialog.css('display') === 'block') {\n\t\t\t// Stow the dialog.\n\t\t\t_$dialog.css({ display : 'none' });\n\n\t\t\t// Restore the dialog with its new positional properties.\n\t\t\t_$dialog.css(jQuery.extend({ display : '' }, _calcPosition(top)));\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tappend : { value : dialogBodyAppend },\n\t\tbody   : { value : dialogBody },\n\t\tclose  : { value : dialogClose },\n\t\tinit   : { value : dialogInit },\n\t\tisOpen : { value : dialogIsOpen },\n\t\topen   : { value : dialogOpen },\n\t\tresize : { value : dialogResize },\n\t\tsetup  : { value : dialogSetup },\n\t\twiki   : { value : dialogBodyWiki },\n\n\t\t// Legacy Functions.\n\t\taddClickHandler : { value : dialogAddClickHandler }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tengine.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Config, DebugView, Dialog, Has, LoadScreen, Save, State, Story, StyleWrapper, UI, UIBar, Util,\n\t       Wikifier, postdisplay, postrender, predisplay, prehistory, prerender, setDisplayTitle\n*/\n\nvar Engine = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Engine state types object (pseudo-enumeration).\n\tconst States = Util.toEnum({\n\t\tIdle      : 'idle',\n\t\tPlaying   : 'playing',\n\t\tRendering : 'rendering'\n\t});\n\n\t// Minimum delay for DOM actions (in milliseconds).\n\tconst minDomActionDelay = 40;\n\n\t// Current state of the engine (default: `Engine.States.Idle`).\n\tlet _state = States.Idle;\n\n\t// Last time `enginePlay()` was called (in milliseconds).\n\tlet _lastPlay = null;\n\n\t// Cache of the debug view for the StoryInit special passage.\n\tlet _storyInitDebugView = null;\n\n\t// Cache of the outline patching <style> element (`StyleWrapper`-wrapped).\n\tlet _outlinePatch = null;\n\n\t// List of objects describing `StoryInterface` elements to update via passages during navigation.\n\tlet _updating = null;\n\n\n\t/*******************************************************************************************************************\n\t\tEngine Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tInitialize the core story elements and perform some bookkeeping.\n\t*/\n\tfunction engineInit() {\n\t\tif (DEBUG) { console.log('[Engine/engineInit()]'); }\n\n\t\t/*\n\t\t\tRemove #init-no-js & #init-lacking from #init-screen.\n\t\t*/\n\t\tjQuery('#init-no-js,#init-lacking').remove();\n\n\t\t/*\n\t\t\tGenerate the core story elements and insert them into the page before the store area.\n\t\t*/\n\t\t(() => {\n\t\t\tconst $elems = jQuery(document.createDocumentFragment());\n\t\t\tconst markup = Story.has('StoryInterface') && Story.get('StoryInterface').text.trim();\n\n\t\t\tif (markup) {\n\t\t\t\t// Remove the UI bar, its styles, and events.\n\t\t\t\tUIBar.destroy();\n\n\t\t\t\t// Remove the core display area styles.\n\t\t\t\tjQuery(document.head).find('#style-core-display').remove();\n\n\t\t\t\t$elems.append(markup);\n\n\t\t\t\tif ($elems.find('#passages').length === 0) {\n\t\t\t\t\tthrow new Error('no element with ID \"passages\" found within \"StoryInterface\" special passage');\n\t\t\t\t}\n\n\t\t\t\tconst updating = [];\n\n\t\t\t\t$elems.find('[data-passage]').each((i, el) => {\n\t\t\t\t\tif (el.id === 'passages') {\n\t\t\t\t\t\tthrow new Error(`\"StoryInterface\" element <${el.nodeName.toLowerCase()} id=\"passages\"> must not contain a \"data-passage\" content attribute`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst passage = el.getAttribute('data-passage').trim();\n\n\t\t\t\t\tif (el.firstElementChild !== null) {\n\t\t\t\t\t\tthrow new Error(`\"StoryInterface\" element <${el.nodeName.toLowerCase()} data-passage=\"${passage}\"> contains child elements`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Story.has(passage)) {\n\t\t\t\t\t\tupdating.push({\n\t\t\t\t\t\t\tpassage,\n\t\t\t\t\t\t\telement : el\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (updating.length > 0) {\n\t\t\t\t\t_updating = updating;\n\t\t\t\t}\n\n\t\t\t\tConfig.ui.updateStoryElements = false;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$elems.append('<div id=\"story\" role=\"main\"><div id=\"passages\"></div></div>');\n\t\t\t}\n\n\t\t\t// Insert the core UI elements into the page before the main script.\n\t\t\t$elems.insertBefore('body>script#script-sugarcube');\n\t\t})();\n\n\t\t/*\n\t\t\tGenerate and cache the ARIA outlines <style> element (`StyleWrapper`-wrapped)\n\t\t\tand set up the handler to manipulate the outlines.\n\n\t\t\tIDEA: http://www.paciellogroup.com/blog/2012/04/how-to-remove-css-outlines-in-an-accessible-manner/\n\t\t*/\n\t\t_outlinePatch = new StyleWrapper((\n\t\t\t() => jQuery(document.createElement('style'))\n\t\t\t\t.attr({\n\t\t\t\t\tid   : 'style-aria-outlines',\n\t\t\t\t\ttype : 'text/css'\n\t\t\t\t})\n\t\t\t\t.appendTo(document.head)\n\t\t\t\t.get(0) // return the <style> element itself\n\t\t)());\n\t\tlet _lastOutlineEvent;\n\t\tjQuery(document).on(\n\t\t\t'mousedown.aria-outlines keydown.aria-outlines',\n\t\t\tev => {\n\t\t\t\tif (ev.type !== _lastOutlineEvent) {\n\t\t\t\t\t_lastOutlineEvent = ev.type;\n\n\t\t\t\t\tif (ev.type === 'keydown') {\n\t\t\t\t\t\t_showOutlines();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t_hideOutlines();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\t/*\n\t\tStarts the story.\n\t*/\n\tfunction engineStart() {\n\t\tif (DEBUG) { console.log('[Engine/engineStart()]'); }\n\n\t\t/*\n\t\t\tExecute the StoryInit special passage.\n\t\t*/\n\t\tif (Story.has('StoryInit')) {\n\t\t\ttry {\n\t\t\t\tconst debugBuffer = Wikifier.wikifyEval(Story.get('StoryInit').text);\n\n\t\t\t\tif (Config.debug) {\n\t\t\t\t\tconst debugView = new DebugView(\n\t\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t\t'special',\n\t\t\t\t\t\t'StoryInit',\n\t\t\t\t\t\t'StoryInit'\n\t\t\t\t\t);\n\t\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\t\tdebugView.append(debugBuffer);\n\t\t\t\t\t_storyInitDebugView = debugView.output;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('StoryInit', ex.message);\n\t\t\t}\n\t\t}\n\n\t\t// Sanity checks.\n\t\tif (Config.passages.start == null) { // lazy equality for null\n\t\t\tthrow new Error('starting passage not selected');\n\t\t}\n\t\tif (!Story.has(Config.passages.start)) {\n\t\t\tthrow new Error(`starting passage (\"${Config.passages.start}\") not found`);\n\t\t}\n\n\t\t// Focus the document element initially.\n\t\tjQuery(document.documentElement).focus();\n\n\t\t/*\n\t\t\tAttempt to restore an active session.  Failing that, attempt to autoload the autosave,\n\t\t\tif requested.  Failing that, display the starting passage.\n\t\t*/\n\t\tif (State.restore()) {\n\t\t\tengineShow();\n\t\t}\n\t\telse {\n\t\t\tlet loadStart = true;\n\n\t\t\tswitch (typeof Config.saves.autoload) {\n\t\t\tcase 'boolean':\n\t\t\t\tif (Config.saves.autoload && Save.autosave.ok() && Save.autosave.has()) {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\t\tloadStart = !Save.autosave.load();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'string':\n\t\t\t\tif (Config.saves.autoload === 'prompt' && Save.autosave.ok() && Save.autosave.has()) {\n\t\t\t\t\tloadStart = false;\n\t\t\t\t\tUI.buildAutoload();\n\t\t\t\t\tDialog.open();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'function':\n\t\t\t\tif (Save.autosave.ok() && Save.autosave.has() && !!Config.saves.autoload()) {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\t\tloadStart = !Save.autosave.load();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (loadStart) {\n\t\t\t\tif (DEBUG) { console.log(`\\tstarting passage: \"${Config.passages.start}\"`); }\n\n\t\t\t\tenginePlay(Config.passages.start);\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t\tRestarts the story.\n\t*/\n\tfunction engineRestart() {\n\t\tif (DEBUG) { console.log('[Engine/engineRestart()]'); }\n\n\t\t/*\n\t\t\tShow the loading screen to hide any unsightly rendering shenanigans during the\n\t\t\tpage reload.\n\t\t*/\n\t\tLoadScreen.show();\n\n\t\t/*\n\t\t\tScroll the window to the top.\n\n\t\t\tThis is required by most browsers for the starting passage or it will remain at\n\t\t\twhatever its current scroll position is after the page reload.  We do it generally,\n\t\t\trather than only for the currently set starting passage, since the starting passage\n\t\t\tmay be dynamically manipulated.\n\t\t*/\n\t\twindow.scroll(0, 0);\n\n\t\t/*\n\t\t\tDelete the active session.\n\t\t*/\n\t\tState.reset();\n\n\t\t/*\n\t\t\tTrigger an ':enginerestart' event.\n\t\t*/\n\t\tjQuery.event.trigger(':enginerestart');\n\n\t\t/*\n\t\t\tReload the page.\n\t\t*/\n\t\twindow.location.reload();\n\t}\n\n\t/*\n\t\tReturns the current state of the engine.\n\t*/\n\tfunction engineState() {\n\t\treturn _state;\n\t}\n\n\t/*\n\t\tReturns whether the engine is idle.\n\t*/\n\tfunction engineIsIdle() {\n\t\treturn _state === States.Idle;\n\t}\n\n\t/*\n\t\tReturns whether the engine is playing.\n\t*/\n\tfunction engineIsPlaying() {\n\t\treturn _state !== States.Idle;\n\t}\n\n\t/*\n\t\tReturns whether the engine is rendering.\n\t*/\n\tfunction engineIsRendering() {\n\t\treturn _state === States.Rendering;\n\t}\n\n\t/*\n\t\tReturns a timestamp representing the last time `Engine.play()` was called.\n\t*/\n\tfunction engineLastPlay() {\n\t\treturn _lastPlay;\n\t}\n\n\t/*\n\t\tActivate the moment at the given index within the state history and show it.\n\t*/\n\tfunction engineGoTo(idx) {\n\t\tconst succeded = State.goTo(idx);\n\n\t\tif (succeded) {\n\t\t\tengineShow();\n\t\t}\n\n\t\treturn succeded;\n\t}\n\n\t/*\n\t\tActivate the moment at the given offset from the active moment within the state history\n\t\tand show it.\n\t*/\n\tfunction engineGo(offset) {\n\t\tconst succeded = State.go(offset);\n\n\t\tif (succeded) {\n\t\t\tengineShow();\n\t\t}\n\n\t\treturn succeded;\n\t}\n\n\t/*\n\t\tGo to the moment which directly precedes the active moment and show it.\n\t*/\n\tfunction engineBackward() {\n\t\treturn engineGo(-1);\n\t}\n\n\t/*\n\t\tGo to the moment which directly follows the active moment and show it.\n\t*/\n\tfunction engineForward() {\n\t\treturn engineGo(1);\n\t}\n\n\t/*\n\t\tRenders and displays the active (present) moment's associated passage without adding\n\t\ta new moment to the history.\n\t*/\n\tfunction engineShow() {\n\t\treturn enginePlay(State.passage, true);\n\t}\n\n\t/*\n\t\tRenders and displays the passage referenced by the given title, optionally without\n\t\tadding a new moment to the history.\n\t*/\n\tfunction enginePlay(title, noHistory) {\n\t\tif (DEBUG) { console.log(`[Engine/enginePlay(title: \"${title}\", noHistory: ${noHistory})]`); }\n\n\t\tlet passageTitle = title;\n\n\t\t// Update the engine state.\n\t\t_state = States.Playing;\n\n\t\t// Reset the temporary state and variables objects.\n\t\tTempState = {}; // eslint-disable-line no-undef\n\t\tState.clearTemporary();\n\n\t\t// Debug view setup.\n\t\tlet passageReadyOutput;\n\t\tlet passageDoneOutput;\n\n\t\t// Execute the navigation override callback.\n\t\tif (typeof Config.navigation.override === 'function') {\n\t\t\ttry {\n\t\t\t\tconst overrideTitle = Config.navigation.override(passageTitle);\n\n\t\t\t\tif (overrideTitle) {\n\t\t\t\t\tpassageTitle = overrideTitle;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op */ }\n\t\t}\n\n\t\t// Retrieve the passage by the given title.\n\t\t//\n\t\t// NOTE: The values of the `title` parameter and `passageTitle` variable\n\t\t// may be empty, strings, or numbers (though using a number as reference\n\t\t// to a numeric title should be discouraged), so after loading the passage,\n\t\t// always refer to `passage.title` and never to the others.\n\t\tconst passage = Story.get(passageTitle);\n\n\t\t// Execute the pre-history events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype : ':passageinit',\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(prehistory).forEach(task => {\n\t\t\tif (typeof prehistory[task] === 'function') {\n\t\t\t\tprehistory[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\t// Create a new entry in the history.\n\t\tif (!noHistory) {\n\t\t\tState.create(passage.title);\n\t\t}\n\n\t\t// Clear the document body's classes.\n\t\tif (document.body.className) {\n\t\t\tdocument.body.className = '';\n\t\t}\n\n\t\t// Update the last play time.\n\t\t//\n\t\t// NOTE: This is mostly for event, task, and special passage code,\n\t\t// though the likelihood of it being needed this early is low.  This\n\t\t// will be updated again later at the end.\n\t\t_lastPlay = Util.now();\n\n\t\t// Execute pre-display tasks and the `PassageReady` special passage.\n\t\tObject.keys(predisplay).forEach(task => {\n\t\t\tif (typeof predisplay[task] === 'function') {\n\t\t\t\tpredisplay[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\tif (Story.has('PassageReady')) {\n\t\t\ttry {\n\t\t\t\tpassageReadyOutput = Wikifier.wikifyEval(Story.get('PassageReady').text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('PassageReady', ex.message);\n\t\t\t}\n\t\t}\n\n\t\t// Update the engine state.\n\t\t_state = States.Rendering;\n\n\t\t// Get the passage's tags as a string, or `null` if there aren't any.\n\t\tconst dataTags = passage.tags.length > 0 ? passage.tags.join(' ') : null;\n\n\t\t// Create and set up the incoming passage element.\n\t\tconst passageEl = document.createElement('div');\n\t\tjQuery(passageEl)\n\t\t\t.attr({\n\t\t\t\tid             : passage.domId,\n\t\t\t\t'data-passage' : passage.title,\n\t\t\t\t'data-tags'    : dataTags\n\t\t\t})\n\t\t\t.addClass(`passage ${passage.className}`);\n\n\t\t// Add the passage's classes and tags to the document body.\n\t\tjQuery(document.body)\n\t\t\t.attr('data-tags', dataTags)\n\t\t\t.addClass(passage.className);\n\n\t\t// Add the passage's tags to the document element.\n\t\tjQuery(document.documentElement)\n\t\t\t.attr('data-tags', dataTags);\n\n\t\t// Execute pre-render events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagestart',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(prerender).forEach(task => {\n\t\t\tif (typeof prerender[task] === 'function') {\n\t\t\t\tprerender[task].call(passage, passageEl, task);\n\t\t\t}\n\t\t});\n\n\t\t// Render the `PassageHeader` passage, if it exists, into the passage element.\n\t\tif (Story.has('PassageHeader')) {\n\t\t\tnew Wikifier(passageEl, Story.get('PassageHeader').processText());\n\t\t}\n\n\t\t// Render the passage into its element.\n\t\tpassageEl.appendChild(passage.render());\n\n\t\t// Render the `PassageFooter` passage, if it exists, into the passage element.\n\t\tif (Story.has('PassageFooter')) {\n\t\t\tnew Wikifier(passageEl, Story.get('PassageFooter').processText());\n\t\t}\n\n\t\t// Execute post-render events and tasks.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagerender',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(postrender).forEach(task => {\n\t\t\tif (typeof postrender[task] === 'function') {\n\t\t\t\tpostrender[task].call(passage, passageEl, task);\n\t\t\t}\n\t\t});\n\n\t\t// Cache the passage container.\n\t\tconst containerEl = document.getElementById('passages');\n\n\t\t// Empty the passage container.\n\t\tif (containerEl.hasChildNodes()) {\n\t\t\tif (\n\t\t\t\t   typeof Config.passages.transitionOut === 'number'\n\t\t\t\t|| typeof Config.passages.transitionOut === 'string'\n\t\t\t\t&& Config.passages.transitionOut !== ''\n\t\t\t\t&& Has.transitionEndEvent\n\t\t\t) {\n\t\t\t\t[...containerEl.childNodes].forEach(outgoing => {\n\t\t\t\t\tconst $outgoing = jQuery(outgoing);\n\n\t\t\t\t\tif (outgoing.nodeType === Node.ELEMENT_NODE && $outgoing.hasClass('passage')) {\n\t\t\t\t\t\tif ($outgoing.hasClass('passage-out')) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$outgoing\n\t\t\t\t\t\t\t.attr('id', `out-${$outgoing.attr('id')}`)\n\t\t\t\t\t\t\t.addClass('passage-out');\n\n\t\t\t\t\t\tif (typeof Config.passages.transitionOut === 'string') {\n\t\t\t\t\t\t\t$outgoing.on(Has.transitionEndEvent, ev => {\n\t\t\t\t\t\t\t\tif (ev.originalEvent.propertyName === Config.passages.transitionOut) {\n\t\t\t\t\t\t\t\t\t$outgoing.remove();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tsetTimeout(\n\t\t\t\t\t\t\t\t() => $outgoing.remove(),\n\t\t\t\t\t\t\t\tMath.max(minDomActionDelay, Config.passages.transitionOut)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t$outgoing.remove();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery(containerEl).empty();\n\t\t\t}\n\t\t}\n\n\t\t// Append the passage element to the passage container and set up its transition.\n\t\tjQuery(passageEl)\n\t\t\t.addClass('passage-in')\n\t\t\t.appendTo(containerEl);\n\t\tsetTimeout(() => jQuery(passageEl).removeClass('passage-in'), minDomActionDelay);\n\n\t\t// Update the story display title, if necessary.\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\t// NOTE: We don't have an `else` here because that case will be handled later (below).\n\t\t\tif (_updating !== null || !Config.ui.updateStoryElements) {\n\t\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t\t}\n\t\t}\n\t\telse if (Config.passages.displayTitles && passage.title !== Config.passages.start) {\n\t\t\tdocument.title = `${passage.title} | ${Story.title}`;\n\t\t}\n\n\t\t// Scroll the window to the top.\n\t\twindow.scroll(0, 0);\n\n\t\t// Update the engine state.\n\t\t_state = States.Playing;\n\n\t\t// Execute post-display events, tasks, and the `PassageDone` special passage.\n\t\tif (Story.has('PassageDone')) {\n\t\t\ttry {\n\t\t\t\tpassageDoneOutput = Wikifier.wikifyEval(Story.get('PassageDone').text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error('PassageDone', ex.message);\n\t\t\t}\n\t\t}\n\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passagedisplay',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\t\tObject.keys(postdisplay).forEach(task => {\n\t\t\tif (typeof postdisplay[task] === 'function') {\n\t\t\t\tpostdisplay[task].call(passage, task);\n\t\t\t}\n\t\t});\n\n\t\t// Update the other interface elements, if necessary.\n\t\tif (_updating !== null) {\n\t\t\t_updating.forEach(pair => {\n\t\t\t\tjQuery(pair.element).empty();\n\t\t\t\tnew Wikifier(pair.element, Story.get(pair.passage).processText().trim());\n\t\t\t});\n\t\t}\n\t\telse if (Config.ui.updateStoryElements) {\n\t\t\tUIBar.update();\n\t\t}\n\n\t\t// Add the completed debug views for `StoryInit`, `PassageReady`, and `PassageDone`\n\t\t// to the incoming passage element.\n\t\tif (Config.debug) {\n\t\t\tlet debugView;\n\n\t\t\t// Prepend the `PassageReady` debug view.\n\t\t\tif (passageReadyOutput != null) { // lazy equality for null\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t'special',\n\t\t\t\t\t'PassageReady',\n\t\t\t\t\t'PassageReady'\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\tdebugView.append(passageReadyOutput);\n\t\t\t\tjQuery(passageEl).prepend(debugView.output);\n\t\t\t}\n\n\t\t\t// Append the `PassageDone` debug view.\n\t\t\tif (passageDoneOutput != null) { // lazy equality for null\n\t\t\t\tdebugView = new DebugView(\n\t\t\t\t\tdocument.createDocumentFragment(),\n\t\t\t\t\t'special',\n\t\t\t\t\t'PassageDone',\n\t\t\t\t\t'PassageDone'\n\t\t\t\t);\n\t\t\t\tdebugView.modes({ hidden : true });\n\t\t\t\tdebugView.append(passageDoneOutput);\n\t\t\t\tjQuery(passageEl).append(debugView.output);\n\t\t\t}\n\n\t\t\t// Prepend the cached `StoryInit` debug view, if we're showing the first moment/turn.\n\t\t\tif (State.turns === 1 && _storyInitDebugView != null) { // lazy equality for null\n\t\t\t\tjQuery(passageEl).prepend(_storyInitDebugView);\n\t\t\t}\n\t\t}\n\n\t\t// Last second post-processing for accessibility and other things.\n\t\t_hideOutlines(); // initially hide outlines\n\t\tjQuery('#story')\n\t\t\t// Add `link-external` to all `href` bearing `<a>` elements which don't have it.\n\t\t\t.find('a[href]:not(.link-external)')\n\t\t\t.addClass('link-external')\n\t\t\t.end()\n\t\t\t// Add `tabindex=0` to all interactive elements which don't have it.\n\t\t\t.find('a,link,button,input,select,textarea')\n\t\t\t.not('[tabindex]')\n\t\t\t.attr('tabindex', 0);\n\n\t\t// Handle autosaves.\n\t\tswitch (typeof Config.saves.autosave) {\n\t\tcase 'boolean':\n\t\t\tif (Config.saves.autosave) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'object':\n\t\t\tif (passage.tags.some(tag => Config.saves.autosave.includes(tag))) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'function':\n\t\t\tif (Config.saves.autosave()) {\n\t\t\t\tSave.autosave.save();\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// Execute post-play events.\n\t\tjQuery.event.trigger({\n\t\t\ttype    : ':passageend',\n\t\t\tcontent : passageEl,\n\t\t\tpassage\n\t\t});\n\n\t\t// Reset the engine state.\n\t\t_state = States.Idle;\n\n\t\t// Update the last play time.\n\t\t_lastPlay = Util.now();\n\n\t\treturn passageEl;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tLegacy Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\t[DEPRECATED] Play the given passage, optionally without altering the history.\n\t*/\n\tfunction engineDisplay(title, link, option) {\n\t\tif (DEBUG) { console.log('[Engine/engineDisplay()]'); }\n\n\t\tlet noHistory = false;\n\n\t\t// Process the option parameter.\n\t\tswitch (option) {\n\t\tcase undefined:\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'replace':\n\t\tcase 'back':\n\t\t\tnoHistory = true;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new Error(`Engine.display option parameter called with obsolete value \"${option}\"; please notify the developer`);\n\t\t}\n\n\t\tenginePlay(title, noHistory);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _hideOutlines() {\n\t\t_outlinePatch.set('*:focus{outline:none;}');\n\t}\n\n\tfunction _showOutlines() {\n\t\t_outlinePatch.clear();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tConstants.\n\t\t*/\n\t\tStates            : { value : States },\n\t\tminDomActionDelay : { value : minDomActionDelay },\n\n\t\t/*\n\t\t\tCore Functions.\n\t\t*/\n\t\tinit        : { value : engineInit },\n\t\tstart       : { value : engineStart },\n\t\trestart     : { value : engineRestart },\n\t\tstate       : { get : engineState },\n\t\tisIdle      : { value : engineIsIdle },\n\t\tisPlaying   : { value : engineIsPlaying },\n\t\tisRendering : { value : engineIsRendering },\n\t\tlastPlay    : { get : engineLastPlay },\n\t\tgoTo        : { value : engineGoTo },\n\t\tgo          : { value : engineGo },\n\t\tbackward    : { value : engineBackward },\n\t\tforward     : { value : engineForward },\n\t\tshow        : { value : engineShow },\n\t\tplay        : { value : enginePlay },\n\n\t\t/*\n\t\t\tLegacy Functions.\n\t\t*/\n\t\tdisplay : { value : engineDisplay }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tpassage.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, L10n, Util, Wikifier */\n\nvar Passage = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tlet _tagsToSkip;\n\tlet _twine1Unescape;\n\n\t/*\n\t\tTags which should not be transformed into classes:\n\t\t\tdebug      → special tag\n\t\t\tnobr       → special tag\n\t\t\tpassage    → the default class\n\t\t\tscript     → special tag (only in Twine 1)\n\t\t\tstylesheet → special tag (only in Twine 1)\n\t\t\ttwine.*    → special tag\n\t\t\twidget     → special tag\n\t*/\n\t// For Twine 1\n\tif (TWINE1) {\n\t\t_tagsToSkip = /^(?:debug|nobr|passage|script|stylesheet|widget|twine\\..*)$/i;\n\t}\n\t// For Twine 2\n\telse {\n\t\t_tagsToSkip = /^(?:debug|nobr|passage|widget|twine\\..*)$/i;\n\t}\n\n\t// For Twine 1\n\tif (TWINE1) {\n\t\t/*\n\t\t\tReturns a decoded version of the passed Twine 1 passage store encoded string.\n\t\t*/\n\t\tconst _twine1EscapesRe    = /(?:\\\\n|\\\\t|\\\\s|\\\\|\\r)/g;\n\t\tconst _hasTwine1EscapesRe = new RegExp(_twine1EscapesRe.source); // to drop the global flag\n\t\tconst _twine1EscapesMap   = Object.freeze({\n\t\t\t'\\\\n' : '\\n',\n\t\t\t'\\\\t' : '\\t',\n\t\t\t'\\\\s' : '\\\\',\n\t\t\t'\\\\'  : '\\\\',\n\t\t\t'\\r'  : ''\n\t\t});\n\n\t\t_twine1Unescape = function (str) {\n\t\t\tif (str == null) { // lazy equality for null\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tconst val = String(str);\n\t\t\treturn val && _hasTwine1EscapesRe.test(val)\n\t\t\t\t? val.replace(_twine1EscapesRe, esc => _twine1EscapesMap[esc])\n\t\t\t\t: val;\n\t\t};\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPassage Class.\n\t*******************************************************************************************************************/\n\tclass Passage {\n\t\tconstructor(title, el) {\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// Passage title/ID.\n\t\t\t\ttitle : {\n\t\t\t\t\tvalue : Util.unescape(title)\n\t\t\t\t},\n\n\t\t\t\t// Passage data element (within the story data element; i.e. T1: '[tiddler]', T2: 'tw-passagedata').\n\t\t\t\telement : {\n\t\t\t\t\tvalue : el || null\n\t\t\t\t},\n\n\t\t\t\t// Passage tags array (sorted and unique).\n\t\t\t\ttags : {\n\t\t\t\t\tvalue : Object.freeze(el && el.hasAttribute('tags')\n\t\t\t\t\t\t? el.getAttribute('tags')\n\t\t\t\t\t\t\t.trim()\n\t\t\t\t\t\t\t.splitOrEmpty(/\\s+/)\n\t\t\t\t\t\t\t.sort()\n\t\t\t\t\t\t\t.filter((tag, i, aref) => i === 0 || aref[i - 1] !== tag)\n\t\t\t\t\t\t: [])\n\t\t\t\t},\n\n\t\t\t\t// Passage excerpt.  Used by the `description()` method.\n\t\t\t\t_excerpt : {\n\t\t\t\t\twritable : true,\n\t\t\t\t\tvalue    : null\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Properties dependant upon the above set.\n\t\t\tObject.defineProperties(this, {\n\t\t\t\t// Passage DOM-compatible ID.\n\t\t\t\tdomId : {\n\t\t\t\t\tvalue : `passage-${Util.slugify(this.title)}`\n\t\t\t\t},\n\n\t\t\t\t// Passage classes array (sorted and unique).\n\t\t\t\tclasses : {\n\t\t\t\t\tvalue : Object.freeze(this.tags.length === 0 ? [] : (() =>\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tReturn the sorted list of unique classes.\n\n\t\t\t\t\t\t\tNOTE: The `this.tags` array is already sorted and unique,\n\t\t\t\t\t\t\tso we only need to filter and map here.\n\t\t\t\t\t\t*/\n\t\t\t\t\t\tthis.tags\n\t\t\t\t\t\t\t.filter(tag => !_tagsToSkip.test(tag))\n\t\t\t\t\t\t\t.map(tag => Util.slugify(tag))\n\t\t\t\t\t)())\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// Getters.\n\t\tget className() {\n\t\t\treturn this.classes.join(' ');\n\t\t}\n\n\t\t// TODO: (v3) This should be → `get source`.\n\t\tget text() {\n\t\t\tif (this.element == null) { // lazy equality for null\n\t\t\t\tconst passage = Util.escape(this.title);\n\t\t\t\tconst mesg    = `${L10n.get('errorTitle')}: ${L10n.get('errorNonexistentPassage', { passage })}`;\n\t\t\t\treturn `<div class=\"error-view\"><span class=\"error\">${mesg}</span></div>`;\n\t\t\t}\n\n\t\t\t// For Twine 1\n\t\t\tif (TWINE1) {\n\t\t\t\treturn _twine1Unescape(this.element.textContent);\n\t\t\t}\n\t\t\t// For Twine 2\n\t\t\telse { // eslint-disable-line no-else-return\n\t\t\t\treturn this.element.textContent.replace(/\\r/g, '');\n\t\t\t}\n\t\t}\n\n\t\tdescription() {\n\t\t\tconst descriptions = Config.passages.descriptions;\n\n\t\t\tif (descriptions != null) { // lazy equality for null\n\t\t\t\tswitch (typeof descriptions) {\n\t\t\t\tcase 'boolean':\n\t\t\t\t\tif (descriptions) {\n\t\t\t\t\t\treturn this.title;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'object':\n\t\t\t\t\tif (descriptions instanceof Map && descriptions.has(this.title)) {\n\t\t\t\t\t\treturn descriptions.get(this.title);\n\t\t\t\t\t}\n\t\t\t\t\telse if (descriptions.hasOwnProperty(this.title)) {\n\t\t\t\t\t\treturn descriptions[this.title];\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'function':\n\t\t\t\t\t{\n\t\t\t\t\t\tconst result = descriptions.call(this);\n\n\t\t\t\t\t\tif (result) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new TypeError('Config.passages.descriptions must be a boolean, object, or function');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Initialize the excerpt cache from the raw passage text, if necessary.\n\t\t\tif (this._excerpt === null) {\n\t\t\t\tthis._excerpt = Passage.getExcerptFromText(this.text);\n\t\t\t}\n\n\t\t\treturn this._excerpt;\n\t\t}\n\n\t\t// TODO: (v3) This should be → `get text`.\n\t\tprocessText() {\n\t\t\tif (this.element == null) { // lazy equality for null\n\t\t\t\treturn this.text;\n\t\t\t}\n\n\t\t\t// Handle image passage transclusion.\n\t\t\tif (this.tags.includes('Twine.image')) {\n\t\t\t\treturn `[img[${this.text}]]`;\n\t\t\t}\n\n\t\t\tlet processed = this.text;\n\n\t\t\t// Handle `Config.passages.onProcess`.\n\t\t\tif (Config.passages.onProcess) {\n\t\t\t\tprocessed = Config.passages.onProcess.call(null, {\n\t\t\t\t\ttitle : this.title,\n\t\t\t\t\ttags  : this.tags,\n\t\t\t\t\ttext  : processed\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Handle `Config.passages.nobr` and the `nobr` tag.\n\t\t\tif (Config.passages.nobr || this.tags.includes('nobr')) {\n\t\t\t\t// Remove all leading & trailing newlines and compact all internal sequences\n\t\t\t\t// of newlines into single spaces.\n\t\t\t\tprocessed = processed.replace(/^\\n+|\\n+$/g, '').replace(/\\n+/g, ' ');\n\t\t\t}\n\n\t\t\treturn processed;\n\t\t}\n\n\t\trender(options) {\n\t\t\t// Wikify the passage into a document fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, this.processText(), options);\n\n\t\t\t// Update the excerpt cache to reflect the rendered text, if we need it for the passage description\n\t\t\tif (Config.passages.descriptions == null) {\n\t\t\t\tthis._excerpt = Passage.getExcerptFromNode(frag);\n\t\t\t}\n\n\t\t\treturn frag;\n\t\t}\n\n\t\tstatic getExcerptFromNode(node, count) {\n\t\t\tif (!node.hasChildNodes()) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tlet excerpt = node.textContent.trim();\n\n\t\t\tif (excerpt !== '') {\n\t\t\t\tconst excerptRe = new RegExp(`(\\\\S+(?:\\\\s+\\\\S+){0,${count > 0 ? count - 1 : 7}})`);\n\t\t\t\texcerpt = excerpt\n\t\t\t\t\t// Compact whitespace.\n\t\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t\t// Attempt to match the excerpt regexp.\n\t\t\t\t\t.match(excerptRe);\n\t\t\t}\n\n\t\t\treturn excerpt ? `${excerpt[1]}\\u2026` : '\\u2026'; // horizontal ellipsis\n\t\t}\n\n\t\tstatic getExcerptFromText(text, count) {\n\t\t\tif (text === '') {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tconst excerptRe = new RegExp(`(\\\\S+(?:\\\\s+\\\\S+){0,${count > 0 ? count - 1 : 7}})`);\n\t\t\tconst excerpt   = text\n\t\t\t\t// Strip macro tags (replace with a space).\n\t\t\t\t.replace(/<<.*?>>/g, ' ')\n\t\t\t\t// Strip html tags (replace with a space).\n\t\t\t\t.replace(/<.*?>/g, ' ')\n\t\t\t\t// The above might have left problematic whitespace, so trim.\n\t\t\t\t.trim()\n\t\t\t\t// Strip table markup.\n\t\t\t\t.replace(/^\\s*\\|.*\\|.*?$/gm, '')\n\t\t\t\t// Strip image markup.\n\t\t\t\t.replace(/\\[[<>]?img\\[[^\\]]*\\]\\]/g, '')\n\t\t\t\t// Clean link markup (remove all but the link text).\n\t\t\t\t.replace(/\\[\\[([^|\\]]*?)(?:(?:\\||->|<-)[^\\]]*)?\\]\\]/g, '$1')\n\t\t\t\t// Clean heading markup.\n\t\t\t\t.replace(/^\\s*!+(.*?)$/gm, '$1')\n\t\t\t\t// Clean bold/italic/underline/highlight styles.\n\t\t\t\t.replace(/'{2}|\\/{2}|_{2}|@{2}/g, '')\n\t\t\t\t// A final trim.\n\t\t\t\t.trim()\n\t\t\t\t// Compact whitespace.\n\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t// Attempt to match the excerpt regexp.\n\t\t\t\t.match(excerptRe);\n\t\t\treturn excerpt ? `${excerpt[1]}\\u2026` : '\\u2026'; // horizontal ellipsis\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Passage;\n})();\n\n/***********************************************************************************************************************\n\n\tsave.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Dialog, Engine, L10n, State, Story, UI, storage */\n\nvar Save = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// The upper bound of the saves slots.\n\tlet _slotsUBound = -1;\n\n\n\t/*******************************************************************************************************************\n\t\tSaves Functions.\n\t*******************************************************************************************************************/\n\tfunction savesInit() {\n\t\tif (DEBUG) { console.log('[Save/savesInit()]'); }\n\n\t\t// Disable save slots and the autosave when Web Storage is unavailable.\n\t\tif (storage.name === 'cookie') {\n\t\t\tsavesObjClear();\n\t\t\tConfig.saves.autoload = undefined;\n\t\t\tConfig.saves.autosave = undefined;\n\t\t\tConfig.saves.slots = 0;\n\t\t\treturn false;\n\t\t}\n\n\t\tlet saves   = savesObjGet();\n\t\tlet updated = false;\n\n\t\t/* legacy */\n\t\t// Convert an ancient saves array into a new saves object.\n\t\tif (Array.isArray(saves)) {\n\t\t\tsaves = {\n\t\t\t\tautosave : null,\n\t\t\t\tslots    : saves\n\t\t\t};\n\t\t\tupdated = true;\n\t\t}\n\t\t/* /legacy */\n\n\t\t// Handle the author changing the number of save slots.\n\t\tif (Config.saves.slots !== saves.slots.length) {\n\t\t\tif (Config.saves.slots < saves.slots.length) {\n\t\t\t\t// Attempt to decrease the number of slots; this will only compact\n\t\t\t\t// the slots array, by removing empty slots, no saves will be deleted.\n\t\t\t\tsaves.slots.reverse();\n\n\t\t\t\tsaves.slots = saves.slots.filter(function (val) {\n\t\t\t\t\tif (val === null && this.count > 0) {\n\t\t\t\t\t\t--this.count;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\t\t\t\t}, { count : saves.slots.length - Config.saves.slots });\n\n\t\t\t\tsaves.slots.reverse();\n\t\t\t}\n\t\t\telse if (Config.saves.slots > saves.slots.length) {\n\t\t\t\t// Attempt to increase the number of slots.\n\t\t\t\t_appendSlots(saves.slots, Config.saves.slots - saves.slots.length);\n\t\t\t}\n\n\t\t\tupdated = true;\n\t\t}\n\n\t\t/* legacy */\n\t\t// Update saves with old/obsolete properties.\n\t\tif (_savesObjUpdate(saves.autosave)) {\n\t\t\tupdated = true;\n\t\t}\n\n\t\tfor (let i = 0; i < saves.slots.length; ++i) {\n\t\t\tif (_savesObjUpdate(saves.slots[i])) {\n\t\t\t\tupdated = true;\n\t\t\t}\n\t\t}\n\n\t\t// Remove save stores which are empty.\n\t\tif (_savesObjIsEmpty(saves)) {\n\t\t\tstorage.delete('saves');\n\t\t\tupdated = false;\n\t\t}\n\t\t/* /legacy */\n\n\t\t// If the saves object was updated, then update the store.\n\t\tif (updated) {\n\t\t\t_savesObjSave(saves);\n\t\t}\n\n\t\t_slotsUBound = saves.slots.length - 1;\n\n\t\treturn true;\n\t}\n\n\tfunction savesObjCreate() {\n\t\treturn {\n\t\t\tautosave : null,\n\t\t\tslots    : _appendSlots([], Config.saves.slots)\n\t\t};\n\t}\n\n\tfunction savesObjGet() {\n\t\tconst saves = storage.get('saves');\n\t\treturn saves === null ? savesObjCreate() : saves;\n\t}\n\n\tfunction savesObjClear() {\n\t\tstorage.delete('saves');\n\t\treturn true;\n\t}\n\n\tfunction savesOk() {\n\t\treturn autosaveOk() || slotsOk();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tAutosave Functions.\n\t*******************************************************************************************************************/\n\tfunction autosaveOk() {\n\t\treturn storage.name !== 'cookie' && typeof Config.saves.autosave !== 'undefined';\n\t}\n\n\tfunction autosaveHas() {\n\t\tconst saves = savesObjGet();\n\n\t\tif (saves.autosave === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction autosaveGet() {\n\t\tconst saves = savesObjGet();\n\t\treturn saves.autosave;\n\t}\n\n\tfunction autosaveLoad() {\n\t\tconst saves = savesObjGet();\n\n\t\tif (saves.autosave === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn _unmarshal(saves.autosave);\n\t}\n\n\tfunction autosaveSave(title, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves        = savesObjGet();\n\t\tconst supplemental = {\n\t\t\ttitle : title || Story.get(State.passage).description(),\n\t\t\tdate  : Date.now()\n\t\t};\n\n\t\tif (metadata != null) { // lazy equality for null\n\t\t\tsupplemental.metadata = metadata;\n\t\t}\n\n\t\tsaves.autosave = _marshal(supplemental);\n\n\t\treturn _savesObjSave(saves);\n\t}\n\n\tfunction autosaveDelete() {\n\t\tconst saves = savesObjGet();\n\t\tsaves.autosave = null;\n\t\treturn _savesObjSave(saves);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSlots Functions.\n\t*******************************************************************************************************************/\n\tfunction slotsOk() {\n\t\treturn storage.name !== 'cookie' && _slotsUBound !== -1;\n\t}\n\n\tfunction slotsLength() {\n\t\treturn _slotsUBound + 1;\n\t}\n\n\tfunction slotsCount() {\n\t\tif (!slotsOk()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\t\tlet count = 0;\n\n\t\tfor (let i = 0, iend = saves.slots.length; i < iend; ++i) {\n\t\t\tif (saves.slots[i] !== null) {\n\t\t\t\t++count;\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n\n\tfunction slotsIsEmpty() {\n\t\treturn slotsCount() === 0;\n\t}\n\n\tfunction slotsHas(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length || saves.slots[slot] === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction slotsGet(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn saves.slots[slot];\n\t}\n\n\tfunction slotsLoad(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length || saves.slots[slot] === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn _unmarshal(saves.slots[slot]);\n\t}\n\n\tfunction slotsSave(slot, title, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst supplemental = {\n\t\t\ttitle : title || Story.get(State.passage).description(),\n\t\t\tdate  : Date.now()\n\t\t};\n\n\t\tif (metadata != null) { // lazy equality for null\n\t\t\tsupplemental.metadata = metadata;\n\t\t}\n\n\t\tsaves.slots[slot] = _marshal(supplemental);\n\n\t\treturn _savesObjSave(saves);\n\t}\n\n\tfunction slotsDelete(slot) {\n\t\tif (slot < 0 || slot > _slotsUBound) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst saves = savesObjGet();\n\n\t\tif (slot >= saves.slots.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tsaves.slots[slot] = null;\n\t\treturn _savesObjSave(saves);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tDisk Import/Export Functions.\n\t*******************************************************************************************************************/\n\tfunction exportToDisk(filename, metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tfunction datestamp() {\n\t\t\tconst now = new Date();\n\t\t\tlet MM = now.getMonth() + 1;\n\t\t\tlet DD = now.getDate();\n\t\t\tlet hh = now.getHours();\n\t\t\tlet mm = now.getMinutes();\n\t\t\tlet ss = now.getSeconds();\n\n\t\t\tif (MM < 10) { MM = `0${MM}`; }\n\t\t\tif (DD < 10) { DD = `0${DD}`; }\n\t\t\tif (hh < 10) { hh = `0${hh}`; }\n\t\t\tif (mm < 10) { mm = `0${mm}`; }\n\t\t\tif (ss < 10) { ss = `0${ss}`; }\n\n\t\t\treturn `${now.getFullYear()}${MM}${DD}-${hh}${mm}${ss}`;\n\t\t}\n\n\t\tfunction legalizeName(str) {\n\t\t\t/*\n\t\t\t\tNOTE: The range of illegal characters consists of: C0 controls, double quote,\n\t\t\t\tnumber, dollar, percent, ampersand, single quote, asterisk, plus, comma,\n\t\t\t\tforward slash, colon, semi-colon, less-than, equals, greater-than, question,\n\t\t\t\tbackslash, caret, backquote/grave, pipe/vertical-bar, delete, C1 controls.\n\t\t\t*/\n\t\t\treturn String(str).trim()\n\t\t\t\t.replace(/[\\x00-\\x1f\"#$%&'*+,/:;<=>?\\\\^`|\\x7f-\\x9f]+/g, '') // eslint-disable-line no-control-regex\n\t\t\t\t.replace(/[_\\s\\u2013\\u2014-]+/g, '-'); // legacy\n\t\t}\n\n\t\tconst baseName     = filename == null ? Story.domId : legalizeName(filename); // lazy equality for null\n\t\tconst saveName     = `${baseName}-${datestamp()}.save`;\n\t\tconst supplemental = metadata == null ? {} : { metadata }; // lazy equality for null\n\t\tconst saveObj      = LZString.compressToBase64(JSON.stringify(_marshal(supplemental)));\n\t\tsaveAs(new Blob([saveObj], { type : 'text/plain;charset=UTF-8' }), saveName);\n\t}\n\n\tfunction importFromDisk(event) {\n\t\tconst file   = event.target.files[0];\n\t\tconst reader = new FileReader();\n\n\t\t// Add the handler that will capture the file information once the load is finished.\n\t\tjQuery(reader).on('load', ev => {\n\t\t\tconst target = ev.currentTarget;\n\n\t\t\tif (!target.result) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet saveObj;\n\n\t\t\ttry {\n\t\t\t\tsaveObj = JSON.parse(\n\t\t\t\t\t/* legacy */ /\\.json$/i.test(file.name) || /^\\{/.test(target.result)\n\t\t\t\t\t\t? target.result\n\t\t\t\t\t\t: /* /legacy */ LZString.decompressFromBase64(target.result)\n\t\t\t\t);\n\t\t\t}\n\t\t\tcatch (ex) { /* no-op; `_unmarshal()` will handle the error */ }\n\n\t\t\t_unmarshal(saveObj);\n\t\t});\n\n\t\t// Initiate the file load.\n\t\treader.readAsText(file);\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tSerialization Functions.\n\t*******************************************************************************************************************/\n\tfunction serialize(metadata) {\n\t\tif (typeof Config.saves.isAllowed === 'function' && !Config.saves.isAllowed()) {\n\t\t\tif (Dialog.isOpen()) {\n\t\t\t\t$(document).one(':dialogclosed', () => UI.alert(L10n.get('savesDisallowed')));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tUI.alert(L10n.get('savesDisallowed'));\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tconst supplemental = metadata == null ? {} : { metadata }; // lazy equality for null\n\t\treturn LZString.compressToBase64(JSON.stringify(_marshal(supplemental)));\n\t}\n\n\tfunction deserialize(base64Str) {\n\t\t/*\n\t\t\tNOTE: We purposefully do not attempt to catch parameter shenanigans\n\t\t\there, instead relying on `_unmarshal()` to do the heavy lifting.\n\t\t*/\n\n\t\tlet saveObj;\n\n\t\ttry {\n\t\t\tsaveObj = JSON.parse(LZString.decompressFromBase64(base64Str));\n\t\t}\n\t\tcatch (ex) { /* no-op; `_unmarshal()` will handle the error */ }\n\n\t\tif (!_unmarshal(saveObj)) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn saveObj.metadata;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _appendSlots(array, num) {\n\t\tfor (let i = 0; i < num; ++i) {\n\t\t\tarray.push(null);\n\t\t}\n\n\t\treturn array;\n\t}\n\n\tfunction _savesObjIsEmpty(saves) {\n\t\tconst slots = saves.slots;\n\t\tlet isSlotsEmpty = true;\n\n\t\tfor (let i = 0, iend = slots.length; i < iend; ++i) {\n\t\t\tif (slots[i] !== null) {\n\t\t\t\tisSlotsEmpty = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn saves.autosave === null && isSlotsEmpty;\n\t}\n\n\tfunction _savesObjSave(saves) {\n\t\tif (_savesObjIsEmpty(saves)) {\n\t\t\tstorage.delete('saves');\n\t\t\treturn true;\n\t\t}\n\n\t\treturn storage.set('saves', saves);\n\t}\n\n\tfunction _savesObjUpdate(saveObj) {\n\t\tif (saveObj == null || typeof saveObj !== 'object') { // lazy equality for null\n\t\t\treturn false;\n\t\t}\n\n\t\tlet updated = false;\n\n\t\t/* eslint-disable no-param-reassign */\n\t\tif (\n\t\t\t   !saveObj.hasOwnProperty('state')\n\t\t\t|| !saveObj.state.hasOwnProperty('delta')\n\t\t\t|| !saveObj.state.hasOwnProperty('index')\n\t\t) {\n\t\t\tif (saveObj.hasOwnProperty('data')) {\n\t\t\t\tdelete saveObj.mode;\n\t\t\t\tsaveObj.state = {\n\t\t\t\t\tdelta : State.deltaEncode(saveObj.data)\n\t\t\t\t};\n\t\t\t\tdelete saveObj.data;\n\t\t\t}\n\t\t\telse if (!saveObj.state.hasOwnProperty('delta')) {\n\t\t\t\tdelete saveObj.state.mode;\n\t\t\t\tsaveObj.state.delta = State.deltaEncode(saveObj.state.history);\n\t\t\t\tdelete saveObj.state.history;\n\t\t\t}\n\t\t\telse if (!saveObj.state.hasOwnProperty('index')) {\n\t\t\t\tdelete saveObj.state.mode;\n\t\t\t}\n\n\t\t\tsaveObj.state.index = saveObj.state.delta.length - 1;\n\t\t\tupdated = true;\n\t\t}\n\n\t\tif (saveObj.state.hasOwnProperty('rseed')) {\n\t\t\tsaveObj.state.seed = saveObj.state.rseed;\n\t\t\tdelete saveObj.state.rseed;\n\n\t\t\tsaveObj.state.delta.forEach((_, i, delta) => {\n\t\t\t\tif (delta[i].hasOwnProperty('rcount')) {\n\t\t\t\t\tdelta[i].pull = delta[i].rcount;\n\t\t\t\t\tdelete delta[i].rcount;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tupdated = true;\n\t\t}\n\n\t\tif (\n\t\t\t   saveObj.state.hasOwnProperty('expired') && typeof saveObj.state.expired === 'number'\n\t\t\t||  saveObj.state.hasOwnProperty('unique')\n\t\t\t||  saveObj.state.hasOwnProperty('last')\n\t\t) {\n\t\t\tif (saveObj.state.hasOwnProperty('expired') && typeof saveObj.state.expired === 'number') {\n\t\t\t\tdelete saveObj.state.expired;\n\t\t\t}\n\n\t\t\tif (saveObj.state.hasOwnProperty('unique') || saveObj.state.hasOwnProperty('last')) {\n\t\t\t\tsaveObj.state.expired = [];\n\n\t\t\t\tif (saveObj.state.hasOwnProperty('unique')) {\n\t\t\t\t\tsaveObj.state.expired.push(saveObj.state.unique);\n\t\t\t\t\tdelete saveObj.state.unique;\n\t\t\t\t}\n\n\t\t\t\tif (saveObj.state.hasOwnProperty('last')) {\n\t\t\t\t\tsaveObj.state.expired.push(saveObj.state.last);\n\t\t\t\t\tdelete saveObj.state.last;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tupdated = true;\n\t\t}\n\t\t/* eslint-enable no-param-reassign */\n\n\t\treturn updated;\n\t}\n\n\tfunction _marshal(supplemental) {\n\t\tif (DEBUG) { console.log('[Save/_marshal()]'); }\n\n\t\tif (supplemental != null && typeof supplemental !== 'object') { // lazy equality for null\n\t\t\tthrow new Error('supplemental parameter must be an object');\n\t\t}\n\n\t\tconst saveObj = Object.assign({}, supplemental, {\n\t\t\tid    : Config.saves.id,\n\t\t\tstate : State.marshalForSave()\n\t\t});\n\n\t\tif (Config.saves.version) {\n\t\t\tsaveObj.version = Config.saves.version;\n\t\t}\n\n\t\tif (typeof Config.saves.onSave === 'function') {\n\t\t\tConfig.saves.onSave(saveObj);\n\t\t}\n\n\t\t// Delta encode the state history and delete the non-encoded property.\n\t\tsaveObj.state.delta = State.deltaEncode(saveObj.state.history);\n\t\tdelete saveObj.state.history;\n\n\t\treturn saveObj;\n\t}\n\n\tfunction _unmarshal(saveObj) {\n\t\tif (DEBUG) { console.log('[Save/_unmarshal()]'); }\n\n\t\ttry {\n\t\t\t/* eslint-disable no-param-reassign */\n\t\t\t/* legacy */\n\t\t\t// Update saves with old/obsolete properties.\n\t\t\t_savesObjUpdate(saveObj);\n\t\t\t/* /legacy */\n\n\t\t\tif (!saveObj || !saveObj.hasOwnProperty('id') || !saveObj.hasOwnProperty('state')) {\n\t\t\t\tthrow new Error(L10n.get('errorSaveMissingData'));\n\t\t\t}\n\n\t\t\t// Delta decode the state history and delete the encoded property.\n\t\t\tsaveObj.state.history = State.deltaDecode(saveObj.state.delta);\n\t\t\tdelete saveObj.state.delta;\n\n\t\t\tif (typeof Config.saves.onLoad === 'function') {\n\t\t\t\tConfig.saves.onLoad(saveObj);\n\t\t\t}\n\n\t\t\tif (saveObj.id !== Config.saves.id) {\n\t\t\t\tthrow new Error(L10n.get('errorSaveIdMismatch'));\n\t\t\t}\n\n\t\t\t// Restore the state.\n\t\t\tState.unmarshalForSave(saveObj.state); // may also throw exceptions\n\n\t\t\t// Show the active moment.\n\t\t\tEngine.show();\n\t\t\t/* eslint-enable no-param-reassign */\n\t\t}\n\t\tcatch (ex) {\n\t\t\tUI.alert(`${ex.message.toUpperFirst()}.</p><p>${L10n.get('aborting')}.`);\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tSave Functions.\n\t\t*/\n\t\tinit  : { value : savesInit },\n\t\tget   : { value : savesObjGet },\n\t\tclear : { value : savesObjClear },\n\t\tok    : { value : savesOk },\n\n\t\t/*\n\t\t\tAutosave Functions.\n\t\t*/\n\t\tautosave : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tok     : { value : autosaveOk },\n\t\t\t\thas    : { value : autosaveHas },\n\t\t\t\tget    : { value : autosaveGet },\n\t\t\t\tload   : { value : autosaveLoad },\n\t\t\t\tsave   : { value : autosaveSave },\n\t\t\t\tdelete : { value : autosaveDelete }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tSlots Functions.\n\t\t*/\n\t\tslots : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tok      : { value : slotsOk },\n\t\t\t\tlength  : { get : slotsLength },\n\t\t\t\tisEmpty : { value : slotsIsEmpty },\n\t\t\t\tcount   : { value : slotsCount },\n\t\t\t\thas     : { value : slotsHas },\n\t\t\t\tget     : { value : slotsGet },\n\t\t\t\tload    : { value : slotsLoad },\n\t\t\t\tsave    : { value : slotsSave },\n\t\t\t\tdelete  : { value : slotsDelete }\n\t\t\t}))\n\t\t},\n\n\t\t/*\n\t\t\tDisk Import/Export Functions.\n\t\t*/\n\t\texport : { value : exportToDisk },\n\t\timport : { value : importFromDisk },\n\n\t\t/*\n\t\t\tSerialization Functions.\n\t\t*/\n\t\tserialize   : { value : serialize },\n\t\tdeserialize : { value : deserialize }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tsetting.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Util, settings:true, storage */\n\nvar Setting = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Setting control types object (pseudo-enumeration).\n\tconst Types = Util.toEnum({\n\t\tHeader : 0,\n\t\tToggle : 1,\n\t\tList   : 2,\n\t\tRange  : 3\n\t});\n\n\t// Setting definition array.\n\tconst _definitions = [];\n\n\n\t/*******************************************************************************************************************\n\t\tSettings Functions.\n\t*******************************************************************************************************************/\n\tfunction settingsInit() {\n\t\tif (DEBUG) { console.log('[Setting/settingsInit()]'); }\n\n\t\t/* legacy */\n\t\t// Attempt to migrate an existing `options` store to `settings`.\n\t\tif (storage.has('options')) {\n\t\t\tconst old = storage.get('options');\n\n\t\t\tif (old !== null) {\n\t\t\t\twindow.SugarCube.settings = settings = Object.assign(settingsCreate(), old);\n\t\t\t}\n\n\t\t\tsettingsSave();\n\t\t\tstorage.delete('options');\n\t\t}\n\t\t/* /legacy */\n\n\t\t// Load existing settings.\n\t\tsettingsLoad();\n\n\t\t// Execute `onInit` callbacks.\n\t\t_definitions.forEach(def => {\n\t\t\tif (def.hasOwnProperty('onInit')) {\n\t\t\t\tconst thisArg = {\n\t\t\t\t\tname    : def.name,\n\t\t\t\t\tvalue   : settings[def.name],\n\t\t\t\t\tdefault : def.default\n\t\t\t\t};\n\n\t\t\t\tif (def.hasOwnProperty('list')) {\n\t\t\t\t\tthisArg.list = def.list;\n\t\t\t\t}\n\n\t\t\t\tdef.onInit.call(thisArg);\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction settingsCreate() {\n\t\treturn Object.create(null);\n\t}\n\n\tfunction settingsSave() {\n\t\tconst savedSettings = settingsCreate();\n\n\t\tif (Object.keys(settings).length > 0) {\n\t\t\t_definitions\n\t\t\t\t.filter(def => def.type !== Types.Header && settings[def.name] !== def.default)\n\t\t\t\t.forEach(def => savedSettings[def.name] = settings[def.name]);\n\t\t}\n\n\t\tif (Object.keys(savedSettings).length === 0) {\n\t\t\tstorage.delete('settings');\n\t\t\treturn true;\n\t\t}\n\n\t\treturn storage.set('settings', savedSettings);\n\t}\n\n\tfunction settingsLoad() {\n\t\tconst defaultSettings = settingsCreate();\n\t\tconst loadedSettings  = storage.get('settings') || settingsCreate();\n\n\t\t// Load the defaults.\n\t\t_definitions\n\t\t\t.filter(def => def.type !== Types.Header)\n\t\t\t.forEach(def => defaultSettings[def.name] = def.default);\n\n\t\t// Assign to the `settings` object while overwriting the defaults with the loaded settings.\n\t\twindow.SugarCube.settings = settings = Object.assign(defaultSettings, loadedSettings);\n\t}\n\n\tfunction settingsClear() {\n\t\twindow.SugarCube.settings = settings = settingsCreate();\n\t\tstorage.delete('settings');\n\t\treturn true;\n\t}\n\n\tfunction settingsReset(name) {\n\t\tif (arguments.length === 0) {\n\t\t\tsettingsClear();\n\t\t\tsettingsLoad();\n\t\t}\n\t\telse {\n\t\t\tif (name == null || !definitionsHas(name)) { // lazy equality for null\n\t\t\t\tthrow new Error(`nonexistent setting \"${name}\"`);\n\t\t\t}\n\n\t\t\tconst def = definitionsGet(name);\n\n\t\t\tif (def.type !== Types.Header) {\n\t\t\t\tsettings[name] = def.default;\n\t\t\t}\n\t\t}\n\n\t\treturn settingsSave();\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tDefinitions Functions.\n\t*******************************************************************************************************************/\n\tfunction definitionsForEach(callback, thisArg) {\n\t\t_definitions.forEach(callback, thisArg);\n\t}\n\n\tfunction definitionsAdd(type, name, def) {\n\t\tif (arguments.length < 3) {\n\t\t\tconst errors = [];\n\t\t\tif (arguments.length < 1) { errors.push('type'); }\n\t\t\tif (arguments.length < 2) { errors.push('name'); }\n\t\t\tif (arguments.length < 3) { errors.push('definition'); }\n\t\t\tthrow new Error(`missing parameters, no ${errors.join(' or ')} specified`);\n\t\t}\n\n\t\tif (typeof def !== 'object') {\n\t\t\tthrow new TypeError('definition parameter must be an object');\n\t\t}\n\n\t\tif (definitionsHas(name)) {\n\t\t\tthrow new Error(`cannot clobber existing setting \"${name}\"`);\n\t\t}\n\n\t\t/*\n\t\t\tDefinition object properties and types:\n\t\t\t\ttype      →  (all)   → Setting.Types\n\t\t\t\tname      →  (all)   → string\n\t\t\t\tlabel     →  (all)   → string\n\t\t\t\tdesc      →  (all)   → string\n\t\t\t\tdefault\n\t\t\t\t\t(if defined)\n \t\t\t\t\t\t  →  Toggle  → boolean\n\t\t\t\t\t\t  →  List    → Array\n\t\t\t\t\t\t  →  Range   → number\n\t\t\t\t\t(if undefined)\n\t\t\t\t\t\t  →  Toggle  → false\n\t\t\t\t\t\t  →  List    → list[0]\n\t\t\t\t\t\t  →  Range   → max\n\t\t\t\tlist      →  List    → Array\n\t\t\t\tmin       →  Range   → number\n\t\t\t\tmax       →  Range   → number\n\t\t\t\tstep      →  Range   → number\n\t\t\t\tonInit    →  (all)   → function\n\t\t\t\tonChange  →  (all)   → function\n\t\t*/\n\t\tconst definition = {\n\t\t\ttype,\n\t\t\tname,\n\t\t\tlabel : typeof def.label === 'string' ? def.label.trim() : ''\n\t\t};\n\n\t\tif (typeof def.desc === 'string') {\n\t\t\tconst desc = def.desc.trim();\n\n\t\t\tif (desc !== '') {\n\t\t\t\tdefinition.desc = desc;\n\t\t\t}\n\t\t}\n\n\t\tswitch (type) {\n\t\tcase Types.Header:\n\t\t\tbreak;\n\n\t\tcase Types.Toggle:\n\t\t\tdefinition.default = !!def.default;\n\t\t\tbreak;\n\n\t\tcase Types.List:\n\t\t\tif (!def.hasOwnProperty('list')) {\n\t\t\t\tthrow new Error('no list specified');\n\t\t\t}\n\t\t\telse if (!Array.isArray(def.list)) {\n\t\t\t\tthrow new TypeError('list must be an array');\n\t\t\t}\n\t\t\telse if (def.list.length === 0) {\n\t\t\t\tthrow new Error('list must not be empty');\n\t\t\t}\n\n\t\t\tdefinition.list = Object.freeze(def.list);\n\n\t\t\tif (def.default == null) { // lazy equality for null\n\t\t\t\tdefinition.default = def.list[0];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst defaultIndex = def.list.indexOf(def.default);\n\n\t\t\t\tif (defaultIndex === -1) {\n\t\t\t\t\tthrow new Error('list does not contain default');\n\t\t\t\t}\n\n\t\t\t\tdefinition.default = def.list[defaultIndex];\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase Types.Range:\n\t\t\tif (!def.hasOwnProperty('min')) {\n\t\t\t\tthrow new Error('no min specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.min !== 'number'\n\t\t\t\t|| Number.isNaN(def.min)\n\t\t\t\t|| !Number.isFinite(def.min)\n\t\t\t) {\n\t\t\t\tthrow new TypeError('min must be a finite number');\n\t\t\t}\n\n\t\t\tif (!def.hasOwnProperty('max')) {\n\t\t\t\tthrow new Error('no max specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.max !== 'number'\n\t\t\t\t|| Number.isNaN(def.max)\n\t\t\t\t|| !Number.isFinite(def.max)\n\t\t\t) {\n\t\t\t\tthrow new TypeError('max must be a finite number');\n\t\t\t}\n\n\t\t\tif (!def.hasOwnProperty('step')) {\n\t\t\t\tthrow new Error('no step specified');\n\t\t\t}\n\t\t\telse if (\n\t\t\t\t   typeof def.step !== 'number'\n\t\t\t\t|| Number.isNaN(def.step)\n\t\t\t\t|| !Number.isFinite(def.step)\n\t\t\t\t|| def.step <= 0\n\t\t\t) {\n\t\t\t\tthrow new TypeError('step must be a finite number greater than zero');\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Determine how many fractional digits we need to be concerned with based on the step value.\n\t\t\t\tconst fracDigits = (() => {\n\t\t\t\t\tconst str = String(def.step);\n\t\t\t\t\tconst pos = str.lastIndexOf('.');\n\t\t\t\t\treturn pos === -1 ? 0 : str.length - pos - 1;\n\t\t\t\t})();\n\n\t\t\t\t// Set up a function to validate a given value against the step value.\n\t\t\t\tfunction stepValidate(value) {\n\t\t\t\t\tif (fracDigits > 0) {\n\t\t\t\t\t\tconst ma = Number(`${def.min}e${fracDigits}`);\n\t\t\t\t\t\tconst sa = Number(`${def.step}e${fracDigits}`);\n\t\t\t\t\t\tconst va = Number(`${value}e${fracDigits}`) - ma;\n\t\t\t\t\t\treturn Number(`${va - va % sa + ma}e-${fracDigits}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst va = value - def.min;\n\t\t\t\t\treturn va - va % def.step + def.min;\n\t\t\t\t}\n\n\t\t\t\t// Sanity check the max value against the step value.\n\t\t\t\tif (stepValidate(def.max) !== def.max) {\n\t\t\t\t\tthrow new RangeError(`max (${def.max}) is not a multiple of the step (${def.step}) plus the min (${def.min})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdefinition.max = def.max;\n\t\t\tdefinition.min = def.min;\n\t\t\tdefinition.step = def.step;\n\n\t\t\tif (def.default == null) { // lazy equality for null\n\t\t\t\tdefinition.default = def.max;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (\n\t\t\t\t\t   typeof def.default !== 'number'\n\t\t\t\t\t|| Number.isNaN(def.default)\n\t\t\t\t\t|| !Number.isFinite(def.default)\n\t\t\t\t) {\n\t\t\t\t\tthrow new TypeError('default must be a finite number');\n\t\t\t\t}\n\t\t\t\telse if (def.default < def.min) {\n\t\t\t\t\tthrow new RangeError(`default (${def.default}) is less than min (${def.min})`);\n\t\t\t\t}\n\t\t\t\telse if (def.default > def.max) {\n\t\t\t\t\tthrow new RangeError(`default (${def.default}) is greater than max (${def.max})`);\n\t\t\t\t}\n\n\t\t\t\tdefinition.default = def.default;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new Error(`unknown Setting type: ${type}`);\n\t\t}\n\n\t\tif (typeof def.onInit === 'function') {\n\t\t\tdefinition.onInit = Object.freeze(def.onInit);\n\t\t}\n\n\t\tif (typeof def.onChange === 'function') {\n\t\t\tdefinition.onChange = Object.freeze(def.onChange);\n\t\t}\n\n\t\t_definitions.push(Object.freeze(definition));\n\t}\n\n\tfunction definitionsAddHeader(name, desc) {\n\t\tdefinitionsAdd(Types.Header, name, { desc });\n\t}\n\n\tfunction definitionsAddToggle(...args) {\n\t\tdefinitionsAdd(Types.Toggle, ...args);\n\t}\n\n\tfunction definitionsAddList(...args) {\n\t\tdefinitionsAdd(Types.List, ...args);\n\t}\n\n\tfunction definitionsAddRange(...args) {\n\t\tdefinitionsAdd(Types.Range, ...args);\n\t}\n\n\tfunction definitionsIsEmpty() {\n\t\treturn _definitions.length === 0;\n\t}\n\n\tfunction definitionsHas(name) {\n\t\treturn _definitions.some(definition => definition.name === name);\n\t}\n\n\tfunction definitionsGet(name) {\n\t\treturn _definitions.find(definition => definition.name === name);\n\t}\n\n\tfunction definitionsDelete(name) {\n\t\tif (definitionsHas(name)) {\n\t\t\tdelete settings[name];\n\t\t}\n\n\t\tfor (let i = 0; i < _definitions.length; ++i) {\n\t\t\tif (_definitions[i].name === name) {\n\t\t\t\t_definitions.splice(i, 1);\n\t\t\t\tdefinitionsDelete(name);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tEnumerations.\n\t\t*/\n\t\tTypes : { value : Types },\n\n\t\t/*\n\t\t\tSettings Functions.\n\t\t*/\n\t\tinit   : { value : settingsInit },\n\t\tcreate : { value : settingsCreate },\n\t\tsave   : { value : settingsSave },\n\t\tload   : { value : settingsLoad },\n\t\tclear  : { value : settingsClear },\n\t\treset  : { value : settingsReset },\n\n\t\t/*\n\t\t\tDefinitions Functions.\n\t\t*/\n\t\tforEach   : { value : definitionsForEach },\n\t\tadd       : { value : definitionsAdd },\n\t\taddHeader : { value : definitionsAddHeader },\n\t\taddToggle : { value : definitionsAddToggle },\n\t\taddList   : { value : definitionsAddList },\n\t\taddRange  : { value : definitionsAddRange },\n\t\tisEmpty   : { value : definitionsIsEmpty },\n\t\thas       : { value : definitionsHas },\n\t\tget       : { value : definitionsGet },\n\t\tdelete    : { value : definitionsDelete }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tstory.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Alert, Config, Passage, Scripting, StyleWrapper, Util, Wikifier */\n\nvar Story = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Map of normal passages.\n\tconst _passages = {};\n\n\t// List of script passages.\n\tconst _scripts = [];\n\n\t// List of style passages.\n\tconst _styles = [];\n\n\t// List of widget passages.\n\tconst _widgets = [];\n\n\t// Story title.\n\tlet _title = '';\n\n\t// Story IFID.\n\tlet _ifId = '';\n\n\t// DOM-compatible ID.\n\tlet _domId = '';\n\n\n\t/*******************************************************************************************************************\n\t\tStory Functions.\n\t*******************************************************************************************************************/\n\tfunction storyLoad() {\n\t\tif (DEBUG) { console.log('[Story/storyLoad()]'); }\n\n\t\tconst validationCodeTags = [\n\t\t\t'widget'\n\t\t];\n\t\tconst validationNoCodeTagPassages = [\n\t\t\t'PassageDone',\n\t\t\t'PassageFooter',\n\t\t\t'PassageHeader',\n\t\t\t'PassageReady',\n\t\t\t'StoryAuthor',\n\t\t\t'StoryBanner',\n\t\t\t'StoryCaption',\n\t\t\t'StoryInit',\n\t\t\t'StoryMenu',\n\t\t\t'StoryShare',\n\t\t\t'StorySubtitle'\n\t\t];\n\n\t\tfunction validateStartingPassage(passage) {\n\t\t\tif (passage.tags.includesAny(validationCodeTags)) {\n\t\t\t\tthrow new Error(`starting passage \"${passage.title}\" contains illegal tags; invalid: \"${passage.tags.filter(tag => validationCodeTags.includes(tag)).sort().join('\", \"')}\"`);\n\t\t\t}\n\t\t}\n\n\t\tfunction validateSpecialPassages(passage) {\n\t\t\tif (validationNoCodeTagPassages.includes(passage.title) && passage.tags.includesAny(validationCodeTags)) {\n\t\t\t\tthrow new Error(`special passage \"${passage.title}\" contains illegal tags; invalid: \"${passage.tags.filter(tag => validationCodeTags.includes(tag)).sort().join('\", \"')}\"`);\n\t\t\t}\n\t\t}\n\n\t\t// For Twine 1.\n\t\tif (TWINE1) {\n\t\t\t/*\n\t\t\t\tAdditional Twine 1 validation setup.\n\t\t\t*/\n\t\t\tvalidationCodeTags.unshift('script', 'stylesheet');\n\t\t\tvalidationNoCodeTagPassages.push('StoryTitle');\n\n\t\t\tfunction validateTwine1CodePassages(passage) {\n\t\t\t\tconst codeTags  = [...validationCodeTags];\n\t\t\t\tconst foundTags = [];\n\n\t\t\t\tpassage.tags.forEach(tag => {\n\t\t\t\t\tif (codeTags.includes(tag)) {\n\t\t\t\t\t\tfoundTags.push(...codeTags.delete(tag));\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (foundTags.length > 1) {\n\t\t\t\t\tthrow new Error(`code passage \"${passage.title}\" contains multiple code tags; invalid: \"${foundTags.sort().join('\", \"')}\"`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet the default starting passage.\n\t\t\t*/\n\t\t\tConfig.passages.start = (() => {\n\t\t\t\t/*\n\t\t\t\t\tHandle the Twine 1.4+ Test Play From Here feature.\n\n\t\t\t\t\tWARNING: Do not remove the `String()` wrapper from or change the quote\n\t\t\t\t\tstyle of the `\"START_AT\"` replacement target.  The former is there to\n\t\t\t\t\tkeep UglifyJS from pruning the code into oblivion—i.e. minifying the\n\t\t\t\t\tcode into something broken.  The latter is there because the Twine 1\n\t\t\t\t\tpattern that matches it depends upon the double quotes.\n\n\t\t\t\t*/\n\t\t\t\tconst testPlay = String(\"START_AT\"); // eslint-disable-line quotes\n\n\t\t\t\tif (testPlay !== '') {\n\t\t\t\t\tif (DEBUG) { console.log(`\\tTest play; starting passage: \"${testPlay}\"`); }\n\n\t\t\t\t\tConfig.debug = true;\n\t\t\t\t\treturn testPlay;\n\t\t\t\t}\n\n\t\t\t\t// In the absence of a `testPlay` value, return 'Start'.\n\t\t\t\treturn 'Start';\n\t\t\t})();\n\n\t\t\t/*\n\t\t\t\tProcess the passages, excluding any tagged 'Twine.private' or 'annotation'.\n\t\t\t*/\n\t\t\tjQuery('#store-area')\n\t\t\t\t.children(':not([tags~=\"Twine.private\"],[tags~=\"annotation\"])')\n\t\t\t\t.each(function () {\n\t\t\t\t\tconst $this   = jQuery(this);\n\t\t\t\t\tconst passage = new Passage($this.attr('tiddler'), this);\n\n\t\t\t\t\t// Special cases.\n\t\t\t\t\tif (passage.title === Config.passages.start) {\n\t\t\t\t\t\tvalidateStartingPassage(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('stylesheet')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_styles.push(passage);\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('script')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_scripts.push(passage);\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('widget')) {\n\t\t\t\t\t\tvalidateTwine1CodePassages(passage);\n\t\t\t\t\t\t_widgets.push(passage);\n\t\t\t\t\t}\n\n\t\t\t\t\t// All other passages.\n\t\t\t\t\telse {\n\t\t\t\t\t\tvalidateSpecialPassages(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tSet the story title or throw an exception.\n\t\t\t*/\n\t\t\tif (_passages.hasOwnProperty('StoryTitle')) {\n\t\t\t\tconst buf = document.createDocumentFragment();\n\t\t\t\tnew Wikifier(buf, _passages.StoryTitle.processText().trim());\n\t\t\t\t_storySetTitle(buf.textContent);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error('cannot find the \"StoryTitle\" special passage');\n\t\t\t}\n\n\t\t\t/*\n\t\t\t\tSet the default saves ID (must be done after the call to `_storySetTitle()`).\n\t\t\t*/\n\t\t\tConfig.saves.id = Story.domId;\n\t\t}\n\n\t\t// For Twine 2.\n\t\telse {\n\t\t\tconst $storydata = jQuery('tw-storydata');\n\t\t\tconst startNode  = $storydata.attr('startnode') || '';\n\n\t\t\t/*\n\t\t\t\tSet the default starting passage.\n\t\t\t*/\n\t\t\tConfig.passages.start = null; // no default in Twine 2\n\n\t\t\t/*\n\t\t\t\tProcess story options.\n\n\t\t\t\tNOTE: Currently, the only option of interest is 'debug', so we\n\t\t\t\tsimply use a regular expression to check for it.\n\t\t\t*/\n\t\t\tConfig.debug = /\\bdebug\\b/.test($storydata.attr('options'));\n\n\t\t\t/*\n\t\t\t\tProcess stylesheet passages.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('style') // alternatively: '[type=\"text/twine-css\"]' or '#twine-user-stylesheet'\n\t\t\t\t.each(function (i) {\n\t\t\t\t\t_styles.push(new Passage(`tw-user-style-${i}`, this));\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tProcess script passages.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('script') // alternatively: '[type=\"text/twine-javascript\"]' or '#twine-user-script'\n\t\t\t\t.each(function (i) {\n\t\t\t\t\t_scripts.push(new Passage(`tw-user-script-${i}`, this));\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tProcess normal passages, excluding any tagged 'Twine.private' or 'annotation'.\n\t\t\t*/\n\t\t\t$storydata\n\t\t\t\t.children('tw-passagedata:not([tags~=\"Twine.private\"],[tags~=\"annotation\"])')\n\t\t\t\t.each(function () {\n\t\t\t\t\tconst $this   = jQuery(this);\n\t\t\t\t\tconst pid     = $this.attr('pid') || '';\n\t\t\t\t\tconst passage = new Passage($this.attr('name'), this);\n\n\t\t\t\t\t// Special cases.\n\t\t\t\t\tif (pid === startNode && startNode !== '') {\n\t\t\t\t\t\tConfig.passages.start = passage.title;\n\t\t\t\t\t\tvalidateStartingPassage(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t\telse if (passage.tags.includes('widget')) {\n\t\t\t\t\t\t_widgets.push(passage);\n\t\t\t\t\t}\n\n\t\t\t\t\t// All other passages.\n\t\t\t\t\telse {\n\t\t\t\t\t\tvalidateSpecialPassages(passage);\n\t\t\t\t\t\t_passages[passage.title] = passage;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t/*\n\t\t\t\tGet the story IFID.\n\t\t\t*/\n\t\t\t_ifId = $storydata.attr('ifid');\n\n\t\t\t/*\n\t\t\t\tSet the story title.\n\n\t\t\t\tFIXME: Maybe `$storydata.attr('name')` should be used instead of `'{{STORY_NAME}}'`?\n\t\t\t*/\n\t\t\t// _storySetTitle($storydata.attr('name'));\n\t\t\t_storySetTitle('{{STORY_NAME}}');\n\n\t\t\t/*\n\t\t\t\tSet the default saves ID (must be done after the call to `_storySetTitle()`).\n\t\t\t*/\n\t\t\tConfig.saves.id = Story.domId;\n\t\t}\n\t}\n\n\tfunction storyInit() {\n\t\tif (DEBUG) { console.log('[Story/storyInit()]'); }\n\n\t\t/*\n\t\t\tAdd the story styles.\n\t\t*/\n\t\t(() => {\n\t\t\tconst storyStyle = document.createElement('style');\n\n\t\t\t(new StyleWrapper(storyStyle))\n\t\t\t\t.add(_styles.map(style => style.text.trim()).join('\\n'));\n\n\t\t\tjQuery(storyStyle)\n\t\t\t\t.appendTo(document.head)\n\t\t\t\t.attr({\n\t\t\t\t\tid   : 'style-story',\n\t\t\t\t\ttype : 'text/css'\n\t\t\t\t});\n\t\t})();\n\n\t\t/*\n\t\t\tEvaluate the story scripts.\n\t\t*/\n\t\tfor (let i = 0; i < _scripts.length; ++i) {\n\t\t\ttry {\n\t\t\t\tScripting.evalJavaScript(_scripts[i].text);\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error(_scripts[i].title, typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t\tProcess the story widgets.\n\t\t*/\n\t\tfor (let i = 0; i < _widgets.length; ++i) {\n\t\t\ttry {\n\t\t\t\tWikifier.wikifyEval(_widgets[i].processText());\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\tconsole.error(ex);\n\t\t\t\tAlert.error(_widgets[i].title, typeof ex === 'object' ? ex.message : ex);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction _storySetTitle(rawTitle) {\n\t\tif (rawTitle == null) { // lazy equality for null\n\t\t\tthrow new Error('story title must not be null or undefined');\n\t\t}\n\n\t\tconst title = Util.unescape(String(rawTitle)).trim();\n\n\t\tif (title === '') { // lazy equality for null\n\t\t\tthrow new Error('story title must not be empty or consist solely of whitespace');\n\t\t}\n\n\t\tdocument.title = _title = title;\n\n\t\t// TODO: In v3 the `_domId` should be created from a combination of the\n\t\t// `_title` slug and the IFID, if available, to avoid collisions between\n\t\t// stories whose titles generate identical slugs.\n\t\t_domId = Util.slugify(_title);\n\n\t\t// [v2] Protect the `_domId` against being an empty string.\n\t\t//\n\t\t// If `_domId` is empty, attempt a failover.\n\t\tif (_domId === '') {\n\t\t\t// If `_ifId` is not empty, then use it.\n\t\t\tif (_ifId !== '') {\n\t\t\t\t_domId = _ifId;\n\t\t\t}\n\n\t\t\t// Elsewise generate a string from the `_title`'s code points (in hexadecimal).\n\t\t\telse {\n\t\t\t\tfor (let i = 0, len = _title.length; i < len; ++i) {\n\t\t\t\t\tconst { char, start, end } = Util.charAndPosAt(_title, i);\n\t\t\t\t\t_domId += char.codePointAt(0).toString(16);\n\t\t\t\t\ti += end - start;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction storyTitle() {\n\t\treturn _title;\n\t}\n\n\tfunction storyDomId() {\n\t\treturn _domId;\n\t}\n\n\tfunction storyIfId() {\n\t\treturn _ifId;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tPassage Functions.\n\t*******************************************************************************************************************/\n\tfunction passagesAdd(passage) {\n\t\tif (!(passage instanceof Passage)) {\n\t\t\tthrow new TypeError('Story.add passage parameter must be an instance of Passage');\n\t\t}\n\n\t\tconst title = passage.title;\n\n\t\tif (!_passages.hasOwnProperty(title)) {\n\t\t\t_passages[title] = passage;\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tfunction passagesHas(title) {\n\t\tlet type = typeof title;\n\n\t\tswitch (type) {\n\t\t// Valid types.\n\t\tcase 'number':\n\t\tcase 'string':\n\t\t\treturn _passages.hasOwnProperty(String(title));\n\n\t\t// Invalid types.  We do the extra processing just to make a nicer error.\n\t\tcase 'undefined':\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\ttype = title === null ? 'null' : 'an object';\n\t\t\tbreak;\n\n\t\tdefault: // 'bigint', 'boolean', 'function', 'symbol'\n\t\t\ttype = `a ${type}`;\n\t\t\tbreak;\n\t\t}\n\n\t\tthrow new TypeError(`Story.has title parameter cannot be ${type}`);\n\t}\n\n\tfunction passagesGet(title) {\n\t\tlet type = typeof title;\n\n\t\tswitch (type) {\n\t\t// Valid types.\n\t\tcase 'number':\n\t\tcase 'string':\n\t\t/* eslint-disable indent */\n\t\t\t{\n\t\t\t\tconst id = String(title);\n\t\t\t\treturn _passages.hasOwnProperty(id) ? _passages[id] : new Passage(id || '(unknown)');\n\t\t\t}\n\t\t/* eslint-enable indent */\n\n\t\t// Invalid types.  We do the extra processing just to make a nicer error.\n\t\tcase 'undefined':\n\t\t\t/* no-op */\n\t\t\tbreak;\n\n\t\tcase 'object':\n\t\t\ttype = title === null ? 'null' : 'an object';\n\t\t\tbreak;\n\n\t\tdefault: // 'bigint', 'boolean', 'function', 'symbol'\n\t\t\ttype = `a ${type}`;\n\t\t\tbreak;\n\t\t}\n\n\t\tthrow new TypeError(`Story.get title parameter cannot be ${type}`);\n\t}\n\n\tfunction passagesGetAllRegular() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Object.assign({}, _passages));\n\t}\n\n\tfunction passagesGetAllScript() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_scripts));\n\t}\n\n\tfunction passagesGetAllStylesheet() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_styles));\n\t}\n\n\tfunction passagesGetAllWidget() {\n\t\t// NOTE: Return an immutable copy, rather than the internal mutable original.\n\t\treturn Object.freeze(Array.from(_widgets));\n\t}\n\n\tfunction passagesLookup(key, value  /* legacy */, sortKey = 'title'/* /legacy */) {\n\t\tconst results = [];\n\n\t\tObject.keys(_passages).forEach(name => {\n\t\t\tconst passage = _passages[name];\n\n\t\t\t// Objects (sans `null`).\n\t\t\tif (typeof passage[key] === 'object' && passage[key] !== null) {\n\t\t\t\t// The only object type currently supported is `Array`, since the\n\t\t\t\t// non-method `Passage` object properties currently yield only either\n\t\t\t\t// primitives or arrays.\n\t\t\t\tif (passage[key] instanceof Array && passage[key].some(m => Util.sameValueZero(m, value))) {\n\t\t\t\t\tresults.push(passage);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// All other types (incl. `null`).\n\t\t\telse if (Util.sameValueZero(passage[key], value)) {\n\t\t\t\tresults.push(passage);\n\t\t\t}\n\t\t});\n\n\t\t// For v3.\n\t\t// /* eslint-disable no-nested-ternary */\n\t\t// // QUESTION: Do we really need to sort the list?\n\t\t// results.sort((a, b) => a.title === b.title ? 0 : a.title < b.title ? -1 : +1);\n\t\t// /* eslint-enable no-nested-ternary */\n\n\t\t/* legacy */\n\t\t/* eslint-disable eqeqeq, no-nested-ternary, max-len */\n\t\tresults.sort((a, b) => a[sortKey] == b[sortKey] ? 0 : a[sortKey] < b[sortKey] ? -1 : +1); // lazy equality for null\n\t\t/* eslint-enable eqeqeq, no-nested-ternary, max-len */\n\t\t/* /legacy */\n\n\t\treturn results;\n\t}\n\n\tfunction passagesLookupWith(predicate /* legacy */, sortKey = 'title'/* /legacy */) {\n\t\tif (typeof predicate !== 'function') {\n\t\t\tthrow new TypeError('Story.lookupWith predicate parameter must be a function');\n\t\t}\n\n\t\tconst results = [];\n\n\t\tObject.keys(_passages).forEach(name => {\n\t\t\tconst passage = _passages[name];\n\n\t\t\tif (predicate(passage)) {\n\t\t\t\tresults.push(passage);\n\t\t\t}\n\t\t});\n\n\t\t// For v3.\n\t\t// /* eslint-disable no-nested-ternary */\n\t\t// // QUESTION: Do we really need to sort the list?\n\t\t// results.sort((a, b) => a.title === b.title ? 0 : a.title < b.title ? -1 : +1);\n\t\t// /* eslint-enable no-nested-ternary */\n\n\t\t/* legacy */\n\t\t/* eslint-disable eqeqeq, no-nested-ternary, max-len */\n\t\tresults.sort((a, b) => a[sortKey] == b[sortKey] ? 0 : a[sortKey] < b[sortKey] ? -1 : +1); // lazy equality for null\n\t\t/* eslint-enable eqeqeq, no-nested-ternary, max-len */\n\t\t/* /legacy */\n\n\t\treturn results;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t// Story Functions.\n\t\tload  : { value : storyLoad },\n\t\tinit  : { value : storyInit },\n\t\ttitle : { get : storyTitle },\n\t\tdomId : { get : storyDomId },\n\t\tifId  : { get : storyIfId },\n\n\t\t// Passage Functions.\n\t\tadd              : { value : passagesAdd },\n\t\thas              : { value : passagesHas },\n\t\tget              : { value : passagesGet },\n\t\tgetAllRegular    : { value : passagesGetAllRegular },\n\t\tgetAllScript     : { value : passagesGetAllScript },\n\t\tgetAllStylesheet : { value : passagesGetAllStylesheet },\n\t\tgetAllWidget     : { value : passagesGetAllWidget },\n\t\tlookup           : { value : passagesLookup },\n\t\tlookupWith       : { value : passagesLookupWith }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tui.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Dialog, Engine, Has, L10n, Save, Setting, State, Story, Util, Wikifier, Config, errorPrologRegExp,\n\t       settings\n*/\n\nvar UI = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t/*******************************************************************************************************************\n\t\tUI Functions, Core.\n\t*******************************************************************************************************************/\n\tfunction uiAssembleLinkList(passage, listEl) {\n\t\tlet list = listEl;\n\n\t\t// Cache the values of `Config.debug` and `Config.cleanupWikifierOutput`,\n\t\t// then disable them during this method's run.\n\t\tconst debugState = Config.debug;\n\t\tconst cleanState = Config.cleanupWikifierOutput;\n\t\tConfig.debug = false;\n\t\tConfig.cleanupWikifierOutput = false;\n\n\t\ttry {\n\t\t\tif (list == null) { // lazy equality for null\n\t\t\t\tlist = document.createElement('ul');\n\t\t\t}\n\n\t\t\t// Wikify the content of the given source passage into a fragment.\n\t\t\tconst frag = document.createDocumentFragment();\n\t\t\tnew Wikifier(frag, Story.get(passage).processText().trim());\n\n\t\t\t// Gather the text of any error elements within the fragment…\n\t\t\tconst errors = [...frag.querySelectorAll('.error')]\n\t\t\t\t.map(errEl => errEl.textContent.replace(errorPrologRegExp, ''));\n\n\t\t\t// …and throw an exception, if there were any errors.\n\t\t\tif (errors.length > 0) {\n\t\t\t\tthrow new Error(errors.join('; '));\n\t\t\t}\n\n\t\t\twhile (frag.hasChildNodes()) {\n\t\t\t\tconst node = frag.firstChild;\n\n\t\t\t\t// Create list items for <a>-element nodes.\n\t\t\t\tif (node.nodeType === Node.ELEMENT_NODE && node.nodeName.toUpperCase() === 'A') {\n\t\t\t\t\tconst li = document.createElement('li');\n\t\t\t\t\tlist.appendChild(li);\n\t\t\t\t\tli.appendChild(node);\n\t\t\t\t}\n\n\t\t\t\t// Discard non-<a>-element nodes.\n\t\t\t\telse {\n\t\t\t\t\tfrag.removeChild(node);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\t// Restore the `Config` settings to their original values.\n\t\t\tConfig.cleanupWikifierOutput = cleanState;\n\t\t\tConfig.debug = debugState;\n\t\t}\n\n\t\treturn list;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUI Functions, Built-ins.\n\t*******************************************************************************************************************/\n\tfunction uiOpenAlert(message, /* options, closeFn */ ...args) {\n\t\tjQuery(Dialog.setup('Alert', 'alert'))\n\t\t\t.append(\n\t\t\t\t  `<p>${message}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"alert-ok\" class=\"ui-close\">${L10n.get(['alertOk', 'ok'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t);\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenJumpto(/* options, closeFn */ ...args) {\n\t\tuiBuildJumpto();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenRestart(/* options, closeFn */ ...args) {\n\t\tuiBuildRestart();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenSaves(/* options, closeFn */ ...args) {\n\t\tuiBuildSaves();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenSettings(/* options, closeFn */ ...args) {\n\t\tuiBuildSettings();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiOpenShare(/* options, closeFn */ ...args) {\n\t\tuiBuildShare();\n\t\tDialog.open(...args);\n\t}\n\n\tfunction uiBuildAutoload() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildAutoload()]'); }\n\n\t\tjQuery(Dialog.setup(L10n.get('autoloadTitle'), 'autoload'))\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  `<p>${L10n.get('autoloadPrompt')}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"autoload-ok\" class=\"ui-close\">${L10n.get(['autoloadOk', 'ok'])}</button></li>`\n\t\t\t\t+ `<li><button id=\"autoload-cancel\" class=\"ui-close\">${L10n.get(['autoloadCancel', 'cancel'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t);\n\n\t\t// Add an additional delegated click handler for the `.ui-close` elements to handle autoloading.\n\t\tjQuery(document).one('click.autoload', '.ui-close', ev => {\n\t\t\tconst isAutoloadOk = ev.target.id === 'autoload-ok';\n\t\t\tjQuery(document).one(':dialogclosed', () => {\n\t\t\t\tif (DEBUG) { console.log(`\\tattempting autoload: \"${Save.autosave.get().title}\"`); }\n\n\t\t\t\tif (!isAutoloadOk || !Save.autosave.load()) {\n\t\t\t\t\tEngine.play(Config.passages.start);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildJumpto() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildJumpto()]'); }\n\n\t\tconst list = document.createElement('ul');\n\n\t\tjQuery(Dialog.setup(L10n.get('jumptoTitle'), 'jumpto list'))\n\t\t\t.append(list);\n\n\t\tconst expired = State.expired.length;\n\n\t\tfor (let i = State.size - 1; i >= 0; --i) {\n\t\t\tif (i === State.activeIndex) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst passage = Story.get(State.history[i].title);\n\n\t\t\tif (passage && passage.tags.includes('bookmark')) {\n\t\t\t\tjQuery(document.createElement('li'))\n\t\t\t\t\t.append(\n\t\t\t\t\t\tjQuery(document.createElement('a'))\n\t\t\t\t\t\t\t.ariaClick({ one : true }, (function (idx) {\n\t\t\t\t\t\t\t\treturn () => jQuery(document).one(':dialogclosed', () => Engine.goTo(idx));\n\t\t\t\t\t\t\t})(i))\n\t\t\t\t\t\t\t.addClass('ui-close')\n\t\t\t\t\t\t\t.text(`${L10n.get('jumptoTurn')} ${expired + i + 1}: ${passage.description()}`)\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo(list);\n\t\t\t}\n\t\t}\n\n\t\tif (!list.hasChildNodes()) {\n\t\t\tjQuery(list).append(`<li><a><em>${L10n.get('jumptoUnavailable')}</em></a></li>`);\n\t\t}\n\t}\n\n\tfunction uiBuildRestart() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildRestart()]'); }\n\n\t\tjQuery(Dialog.setup(L10n.get('restartTitle'), 'restart'))\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  `<p>${L10n.get('restartPrompt')}</p><ul class=\"buttons\">`\n\t\t\t\t+ `<li><button id=\"restart-ok\">${L10n.get(['restartOk', 'ok'])}</button></li>`\n\t\t\t\t+ `<li><button id=\"restart-cancel\" class=\"ui-close\">${L10n.get(['restartCancel', 'cancel'])}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t)\n\t\t\t.find('#restart-ok')\n\t\t\t/*\n\t\t\t\tInstead of adding '.ui-close' to '#restart-ok' (to receive the use of the default\n\t\t\t\tdelegated dialog close handler), we set up a special case close handler here.  We\n\t\t\t\tdo this to ensure that the invocation of `Engine.restart()` happens after the dialog\n\t\t\t\thas fully closed.  If we did not, then a race condition could occur, causing display\n\t\t\t\tshenanigans.\n\t\t\t*/\n\t\t\t.ariaClick({ one : true }, () => {\n\t\t\t\tjQuery(document).one(':dialogclosed', () => Engine.restart());\n\t\t\t\tDialog.close();\n\t\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildSaves() {\n\t\tfunction createActionItem(bId, bClass, bText, bAction) {\n\t\t\tconst $btn = jQuery(document.createElement('button'))\n\t\t\t\t.attr('id', `saves-${bId}`)\n\t\t\t\t.html(bText);\n\n\t\t\tif (bClass) {\n\t\t\t\t$btn.addClass(bClass);\n\t\t\t}\n\n\t\t\tif (bAction) {\n\t\t\t\t$btn.ariaClick(bAction);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$btn.ariaDisabled(true);\n\t\t\t}\n\n\t\t\treturn jQuery(document.createElement('li'))\n\t\t\t\t.append($btn);\n\t\t}\n\n\t\tfunction createSaveList() {\n\t\t\tfunction createButton(bId, bClass, bText, bSlot, bAction) {\n\t\t\t\tconst $btn = jQuery(document.createElement('button'))\n\t\t\t\t\t.attr('id', `saves-${bId}-${bSlot}`)\n\t\t\t\t\t.addClass(bId)\n\t\t\t\t\t.html(bText);\n\n\t\t\t\tif (bClass) {\n\t\t\t\t\t$btn.addClass(bClass);\n\t\t\t\t}\n\n\t\t\t\tif (bAction) {\n\t\t\t\t\tif (bSlot === 'auto') {\n\t\t\t\t\t\t$btn.ariaClick({\n\t\t\t\t\t\t\tlabel : `${bText} ${L10n.get('savesLabelAuto')}`\n\t\t\t\t\t\t}, () => bAction());\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t$btn.ariaClick({\n\t\t\t\t\t\t\tlabel : `${bText} ${L10n.get('savesLabelSlot')} ${bSlot + 1}`\n\t\t\t\t\t\t}, () => bAction(bSlot));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$btn.ariaDisabled(true);\n\t\t\t\t}\n\n\t\t\t\treturn $btn;\n\t\t\t}\n\n\t\t\tconst saves  = Save.get();\n\t\t\tconst $tbody = jQuery(document.createElement('tbody'));\n\n\t\t\tif (Save.autosave.ok()) {\n\t\t\t\tconst $tdSlot = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdLoad = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDesc = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDele = jQuery(document.createElement('td'));\n\n\t\t\t\t// Add the slot ID.\n\t\t\t\tjQuery(document.createElement('b'))\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttitle        : L10n.get('savesLabelAuto'),\n\t\t\t\t\t\t'aria-label' : L10n.get('savesLabelAuto')\n\t\t\t\t\t})\n\t\t\t\t\t.text('A') // '\\u25C6' Black Diamond\n\t\t\t\t\t.appendTo($tdSlot);\n\n\t\t\t\tif (saves.autosave) {\n\t\t\t\t\t// Add the load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('load', 'ui-close', L10n.get('savesLabelLoad'), 'auto', () => {\n\t\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.autosave.load());\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description (title and datestamp).\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.text(saves.autosave.title)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.addClass('datestamp')\n\t\t\t\t\t\t.html(\n\t\t\t\t\t\t\tsaves.autosave.date\n\t\t\t\t\t\t\t\t? `${new Date(saves.autosave.date).toLocaleString()}`\n\t\t\t\t\t\t\t\t: `<em>${L10n.get('savesUnknownDate')}</em>`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\n\t\t\t\t\t// Add the delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), 'auto', () => {\n\t\t\t\t\t\t\tSave.autosave.delete();\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Add the disabled load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('load', null, L10n.get('savesLabelLoad'), 'auto')\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description.\n\t\t\t\t\t$tdDesc.addClass('empty').text('\\u2022\\u00a0\\u00a0\\u2022\\u00a0\\u00a0\\u2022');\n\n\t\t\t\t\t// Add the disabled delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), 'auto')\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t.append($tdSlot)\n\t\t\t\t\t.append($tdLoad)\n\t\t\t\t\t.append($tdDesc)\n\t\t\t\t\t.append($tdDele)\n\t\t\t\t\t.appendTo($tbody);\n\t\t\t}\n\n\t\t\tfor (let i = 0, iend = saves.slots.length; i < iend; ++i) {\n\t\t\t\tconst $tdSlot = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdLoad = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDesc = jQuery(document.createElement('td'));\n\t\t\t\tconst $tdDele = jQuery(document.createElement('td'));\n\n\t\t\t\t// Add the slot ID.\n\t\t\t\t$tdSlot.append(document.createTextNode(i + 1));\n\n\t\t\t\tif (saves.slots[i]) {\n\t\t\t\t\t// Add the load button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('save', 'ui-close', L10n.get('savesLabelSave'), i, Save.slots.save),\n\t\t\t\t\t\tcreateButton('load', 'ui-close', L10n.get('savesLabelLoad'), i, slot => {\n\t\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.slots.load(slot));\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description (title and datestamp).\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.text(saves.slots[i].title)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\t\t\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t\t\t.addClass('datestamp')\n\t\t\t\t\t\t.html(\n\t\t\t\t\t\t\tsaves.slots[i].date\n\t\t\t\t\t\t\t\t? `${new Date(saves.slots[i].date).toLocaleString()}`\n\t\t\t\t\t\t\t\t: `<em>${L10n.get('savesUnknownDate')}</em>`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo($tdDesc);\n\n\t\t\t\t\t// Add the delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), i, slot => {\n\t\t\t\t\t\t\tSave.slots.delete(slot);\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Add the save button.\n\t\t\t\t\t$tdLoad.append(\n\t\t\t\t\t\tcreateButton('save', 'ui-close', L10n.get('savesLabelSave'), i, Save.slots.save)\n\t\t\t\t\t);\n\n\t\t\t\t\t// Add the description.\n\t\t\t\t\t$tdDesc.addClass('empty').text('\\u2022\\u00a0\\u00a0\\u2022\\u00a0\\u00a0\\u2022');\n\n\t\t\t\t\t// Add the disabled delete button.\n\t\t\t\t\t$tdDele.append(\n\t\t\t\t\t\tcreateButton('delete', null, L10n.get('savesLabelDelete'), i)\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tjQuery(document.createElement('tr'))\n\t\t\t\t\t.append($tdSlot)\n\t\t\t\t\t.append($tdLoad)\n\t\t\t\t\t.append($tdDesc)\n\t\t\t\t\t.append($tdDele)\n\t\t\t\t\t.appendTo($tbody);\n\t\t\t}\n\n\t\t\treturn jQuery(document.createElement('table'))\n\t\t\t\t.attr('id', 'saves-list')\n\t\t\t\t.append($tbody);\n\t\t}\n\n\t\tif (DEBUG) { console.log('[UI/uiBuildSaves()]'); }\n\n\t\tconst $dialogBody = jQuery(Dialog.setup(L10n.get('savesTitle'), 'saves'));\n\t\tconst savesOk     = Save.ok();\n\n\t\t// Add saves list.\n\t\tif (savesOk) {\n\t\t\t$dialogBody.append(createSaveList());\n\t\t}\n\n\t\t// Add button bar items (export, import, and clear).\n\t\tif (savesOk || Has.fileAPI) {\n\t\t\tconst $btnBar = jQuery(document.createElement('ul'))\n\t\t\t\t.addClass('buttons')\n\t\t\t\t.appendTo($dialogBody);\n\n\t\t\tif (Has.fileAPI) {\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'export',\n\t\t\t\t\t'ui-close',\n\t\t\t\t\tL10n.get('savesLabelExport'),\n\t\t\t\t\t() => Save.export()\n\t\t\t\t));\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'import',\n\t\t\t\t\tnull,\n\t\t\t\t\tL10n.get('savesLabelImport'),\n\t\t\t\t\t() => $dialogBody.find('#saves-import-file').trigger('click')\n\t\t\t\t));\n\n\t\t\t\t// Add the hidden `input[type=file]` element which will be triggered by the `#saves-import` button.\n\t\t\t\tjQuery(document.createElement('input'))\n\t\t\t\t\t.css({\n\t\t\t\t\t\tdisplay    : 'block',\n\t\t\t\t\t\tvisibility : 'hidden',\n\t\t\t\t\t\tposition   : 'fixed',\n\t\t\t\t\t\tleft       : '-9999px',\n\t\t\t\t\t\ttop        : '-9999px',\n\t\t\t\t\t\twidth      : '1px',\n\t\t\t\t\t\theight     : '1px'\n\t\t\t\t\t})\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttype          : 'file',\n\t\t\t\t\t\tid            : 'saves-import-file',\n\t\t\t\t\t\ttabindex      : -1,\n\t\t\t\t\t\t'aria-hidden' : true\n\t\t\t\t\t})\n\t\t\t\t\t.on('change', ev => {\n\t\t\t\t\t\tjQuery(document).one(':dialogclosed', () => Save.import(ev));\n\t\t\t\t\t\tDialog.close();\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo($dialogBody);\n\t\t\t}\n\n\t\t\tif (savesOk) {\n\t\t\t\t$btnBar.append(createActionItem(\n\t\t\t\t\t'clear',\n\t\t\t\t\tnull,\n\t\t\t\t\tL10n.get('savesLabelClear'),\n\t\t\t\t\tSave.autosave.has() || !Save.slots.isEmpty()\n\t\t\t\t\t\t? () => {\n\t\t\t\t\t\t\tSave.clear();\n\t\t\t\t\t\t\tuiBuildSaves();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t: null\n\t\t\t\t));\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tuiOpenAlert(L10n.get('savesIncapable'));\n\t\treturn false;\n\t}\n\n\tfunction uiBuildSettings() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildSettings()]'); }\n\n\t\tconst $dialogBody = jQuery(Dialog.setup(L10n.get('settingsTitle'), 'settings'));\n\n\t\tSetting.forEach(control => {\n\t\t\tif (control.type === Setting.Types.Header) {\n\t\t\t\tconst name     = control.name;\n\t\t\t\tconst id       = Util.slugify(name);\n\t\t\t\tconst $header  = jQuery(document.createElement('div'));\n\t\t\t\tconst $heading = jQuery(document.createElement('h2'));\n\n\t\t\t\t$header\n\t\t\t\t\t.attr('id', `header-body-${id}`)\n\t\t\t\t\t.append($heading)\n\t\t\t\t\t.appendTo($dialogBody);\n\t\t\t\t$heading\n\t\t\t\t\t.attr('id', `header-heading-${id}`)\n\t\t\t\t\t.wiki(name);\n\n\t\t\t\t// Set up the description, if any.\n\t\t\t\tif (control.desc) {\n\t\t\t\t\tjQuery(document.createElement('p'))\n\t\t\t\t\t\t.attr('id', `header-desc-${id}`)\n\t\t\t\t\t\t.wiki(control.desc)\n\t\t\t\t\t\t.appendTo($header);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst name        = control.name;\n\t\t\tconst id          = Util.slugify(name);\n\t\t\tconst $setting    = jQuery(document.createElement('div'));\n\t\t\tconst $label      = jQuery(document.createElement('label'));\n\t\t\tconst $controlBox = jQuery(document.createElement('div'));\n\t\t\tlet $control;\n\n\t\t\t// Set up the label+control wrapper.\n\t\t\tjQuery(document.createElement('div'))\n\t\t\t\t.append($label)\n\t\t\t\t.append($controlBox)\n\t\t\t\t.appendTo($setting);\n\n\t\t\t// Set up the description, if any.\n\t\t\tif (control.desc) {\n\t\t\t\tjQuery(document.createElement('p'))\n\t\t\t\t\t.attr('id', `setting-desc-${id}`)\n\t\t\t\t\t.wiki(control.desc)\n\t\t\t\t\t.appendTo($setting);\n\t\t\t}\n\n\t\t\t// Set up the label.\n\t\t\t$label\n\t\t\t\t.attr({\n\t\t\t\t\tid  : `setting-label-${id}`,\n\t\t\t\t\tfor : `setting-control-${id}` // must be in sync with $control's ID (see below)\n\t\t\t\t})\n\t\t\t\t.wiki(control.label);\n\n\t\t\t// Set up the control.\n\t\t\tif (settings[name] == null) { // lazy equality for null\n\t\t\t\tsettings[name] = control.default;\n\t\t\t}\n\n\t\t\tswitch (control.type) {\n\t\t\tcase Setting.Types.Toggle:\n\t\t\t\t$control = jQuery(document.createElement('button'));\n\n\t\t\t\tif (settings[name]) {\n\t\t\t\t\t$control\n\t\t\t\t\t\t.addClass('enabled')\n\t\t\t\t\t\t.text(L10n.get('settingsOn'));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$control\n\t\t\t\t\t\t.text(L10n.get('settingsOff'));\n\t\t\t\t}\n\n\t\t\t\t$control.ariaClick(function () {\n\t\t\t\t\tif (settings[name]) {\n\t\t\t\t\t\tjQuery(this)\n\t\t\t\t\t\t\t.removeClass('enabled')\n\t\t\t\t\t\t\t.text(L10n.get('settingsOff'));\n\t\t\t\t\t\tsettings[name] = false;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tjQuery(this)\n\t\t\t\t\t\t\t.addClass('enabled')\n\t\t\t\t\t\t\t.text(L10n.get('settingsOn'));\n\t\t\t\t\t\tsettings[name] = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tSetting.save();\n\n\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\tdefault : control.default\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase Setting.Types.List:\n\t\t\t\t$control = jQuery(document.createElement('select'));\n\n\t\t\t\tfor (let i = 0, iend = control.list.length; i < iend; ++i) {\n\t\t\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t\t\t.val(i)\n\t\t\t\t\t\t.text(control.list[i])\n\t\t\t\t\t\t.appendTo($control);\n\t\t\t\t}\n\n\t\t\t\t$control\n\t\t\t\t\t.val(control.list.indexOf(settings[name]))\n\t\t\t\t\t.attr('tabindex', 0)\n\t\t\t\t\t.on('change', function () {\n\t\t\t\t\t\tsettings[name] = control.list[Number(this.value)];\n\t\t\t\t\t\tSetting.save();\n\n\t\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\t\tdefault : control.default,\n\t\t\t\t\t\t\t\tlist    : control.list\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase Setting.Types.Range:\n\t\t\t\t$control = jQuery(document.createElement('input'));\n\n\t\t\t\t// NOTE: Setting the value with `<jQuery>.val()` can cause odd behavior\n\t\t\t\t// in Edge if it's called before the type is set, so we use the `value`\n\t\t\t\t// content attribute here to dodge the entire issue.\n\t\t\t\t$control\n\t\t\t\t\t.attr({\n\t\t\t\t\t\ttype     : 'range',\n\t\t\t\t\t\tmin      : control.min,\n\t\t\t\t\t\tmax      : control.max,\n\t\t\t\t\t\tstep     : control.step,\n\t\t\t\t\t\tvalue    : settings[name],\n\t\t\t\t\t\ttabindex : 0\n\t\t\t\t\t})\n\t\t\t\t\t.on('change input', function () {\n\t\t\t\t\t\tsettings[name] = Number(this.value);\n\t\t\t\t\t\tSetting.save();\n\n\t\t\t\t\t\tif (control.hasOwnProperty('onChange')) {\n\t\t\t\t\t\t\tcontrol.onChange.call({\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tvalue   : settings[name],\n\t\t\t\t\t\t\t\tdefault : control.default,\n\t\t\t\t\t\t\t\tmin     : control.min,\n\t\t\t\t\t\t\t\tmax     : control.max,\n\t\t\t\t\t\t\t\tstep    : control.step\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.on('keypress', ev => {\n\t\t\t\t\t\tif (ev.which === 13) {\n\t\t\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t\t\t$control.trigger('change');\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$control\n\t\t\t\t.attr('id', `setting-control-${id}`)\n\t\t\t\t.appendTo($controlBox);\n\n\t\t\t$setting\n\t\t\t\t.attr('id', `setting-body-${id}`)\n\t\t\t\t.appendTo($dialogBody);\n\t\t});\n\n\t\t// Add the button bar.\n\t\t$dialogBody\n\t\t\t.append(\n\t\t\t\t  '<ul class=\"buttons\">'\n\t\t\t\t+     `<li><button id=\"settings-ok\" class=\"ui-close\">${L10n.get(['settingsOk', 'ok'])}</button></li>`\n\t\t\t\t+     `<li><button id=\"settings-reset\">${L10n.get('settingsReset')}</button></li>`\n\t\t\t\t+ '</ul>'\n\t\t\t)\n\t\t\t.find('#settings-reset')\n\t\t\t/*\n\t\t\t\tInstead of adding '.ui-close' to '#settings-reset' (to receive the use of the default\n\t\t\t\tdelegated dialog close handler), we set up a special case close handler here.  We\n\t\t\t\tdo this to ensure that the invocation of `window.location.reload()` happens after the\n\t\t\t\tdialog has fully closed.  If we did not, then a race condition could occur, causing\n\t\t\t\tdisplay shenanigans.\n\t\t\t*/\n\t\t\t.ariaClick({ one : true }, () => {\n\t\t\t\tjQuery(document).one(':dialogclosed', () => {\n\t\t\t\t\tSetting.reset();\n\t\t\t\t\twindow.location.reload();\n\t\t\t\t});\n\t\t\t\tDialog.close();\n\t\t\t});\n\n\t\treturn true;\n\t}\n\n\tfunction uiBuildShare() {\n\t\tif (DEBUG) { console.log('[UI/uiBuildShare()]'); }\n\n\t\ttry {\n\t\t\tjQuery(Dialog.setup(L10n.get('shareTitle'), 'share list'))\n\t\t\t\t.append(uiAssembleLinkList('StoryShare'));\n\t\t}\n\t\tcatch (ex) {\n\t\t\tconsole.error(ex);\n\t\t\tAlert.error('StoryShare', ex.message);\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tUI Functions, Core.\n\t\t*/\n\t\tassembleLinkList : { value : uiAssembleLinkList },\n\n\t\t/*\n\t\t\tUI Functions, Built-ins.\n\t\t*/\n\t\talert         : { value : uiOpenAlert },\n\t\tjumpto        : { value : uiOpenJumpto },\n\t\trestart       : { value : uiOpenRestart },\n\t\tsaves         : { value : uiOpenSaves },\n\t\tsettings      : { value : uiOpenSettings },\n\t\tshare         : { value : uiOpenShare },\n\t\tbuildAutoload : { value : uiBuildAutoload },\n\t\tbuildJumpto   : { value : uiBuildJumpto },\n\t\tbuildRestart  : { value : uiBuildRestart },\n\t\tbuildSaves    : { value : uiBuildSaves },\n\t\tbuildSettings : { value : uiBuildSettings },\n\t\tbuildShare    : { value : uiBuildShare },\n\n\t\t/*\n\t\t\tLegacy Aliases.\n\t\t*/\n\t\t// `UIBar` methods.\n\t\t/* global UIBar */\n\t\tstow                     : { value : () => UIBar.stow() },\n\t\tunstow                   : { value : () => UIBar.unstow() },\n\t\tsetStoryElements         : { value : () => UIBar.update() },\n\t\t// `Dialog` methods.\n\t\tisOpen                   : { value : (...args) => Dialog.isOpen(...args) },\n\t\tbody                     : { value : () => Dialog.body() },\n\t\tsetup                    : { value : (...args) => Dialog.setup(...args) },\n\t\taddClickHandler          : { value : (...args) => Dialog.addClickHandler(...args) },\n\t\topen                     : { value : (...args) => Dialog.open(...args) },\n\t\tclose                    : { value : (...args) => Dialog.close(...args) },\n\t\tresize                   : { value : () => Dialog.resize() },\n\t\t// Deprecated method names.\n\t\tbuildDialogAutoload      : { value : uiBuildAutoload },\n\t\tbuildDialogJumpto        : { value : uiBuildJumpto },\n\t\tbuildDialogRestart       : { value : uiBuildRestart },\n\t\tbuildDialogSaves         : { value : uiBuildSaves },\n\t\tbuildDialogSettings      : { value : uiBuildSettings },\n\t\tbuildDialogShare         : { value : uiBuildShare },\n\t\tbuildLinkListFromPassage : { value : uiAssembleLinkList }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tuibar.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Dialog, Engine, L10n, Setting, State, Story, UI, Config, setDisplayTitle, setPageElement\n*/\n\nvar UIBar = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// UI bar element cache.\n\tlet _$uiBar = null;\n\n\n\t/*******************************************************************************\n\t\tUI Bar Functions.\n\t*******************************************************************************/\n\n\tfunction uiBarDestroy() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarDestroy()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Hide the UI bar.\n\t\t_$uiBar.hide();\n\n\t\t// Remove its namespaced events.\n\t\tjQuery(document).off('.ui-bar');\n\n\t\t// Remove its styles.\n\t\tjQuery(document.head).find('#style-ui-bar').remove();\n\n\t\t// Remove it from the DOM.\n\t\t_$uiBar.remove();\n\n\t\t// Drop the reference to the element.\n\t\t_$uiBar = null;\n\t}\n\n\tfunction uiBarHide() {\n\t\tif (_$uiBar) {\n\t\t\t_$uiBar.hide();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarInit() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarInit()]'); }\n\n\t\tif (document.getElementById('ui-bar')) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Generate the UI bar elements.\n\t\tconst $elems = (() => {\n\t\t\tconst toggleLabel   = L10n.get('uiBarToggle');\n\t\t\tconst backwardLabel = L10n.get('uiBarBackward');\n\t\t\tconst jumptoLabel   = L10n.get('uiBarJumpto');\n\t\t\tconst forwardLabel  = L10n.get('uiBarForward');\n\n\t\t\treturn jQuery(document.createDocumentFragment())\n\t\t\t\t.append(\n\t\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t\t  '<div id=\"ui-bar\">'\n\t\t\t\t\t+     '<div id=\"ui-bar-tray\">'\n\t\t\t\t\t+         `<button id=\"ui-bar-toggle\" tabindex=\"0\" title=\"${toggleLabel}\" aria-label=\"${toggleLabel}\"></button>`\n\t\t\t\t\t+         '<div id=\"ui-bar-history\">'\n\t\t\t\t\t+             `<button id=\"history-backward\" tabindex=\"0\" title=\"${backwardLabel}\" aria-label=\"${backwardLabel}\">\\uE821</button>`\n\t\t\t\t\t+             `<button id=\"history-jumpto\" tabindex=\"0\" title=\"${jumptoLabel}\" aria-label=\"${jumptoLabel}\">\\uE839</button>`\n\t\t\t\t\t+             `<button id=\"history-forward\" tabindex=\"0\" title=\"${forwardLabel}\" aria-label=\"${forwardLabel}\">\\uE822</button>`\n\t\t\t\t\t+         '</div>'\n\t\t\t\t\t+     '</div>'\n\t\t\t\t\t+     '<div id=\"ui-bar-body\">'\n\t\t\t\t\t+         '<header id=\"title\" role=\"banner\">'\n\t\t\t\t\t+             '<div id=\"story-banner\"></div>'\n\t\t\t\t\t+             '<h1 id=\"story-title\"></h1>'\n\t\t\t\t\t+             '<div id=\"story-subtitle\"></div>'\n\t\t\t\t\t+             '<div id=\"story-title-separator\"></div>'\n\t\t\t\t\t+             '<p id=\"story-author\"></p>'\n\t\t\t\t\t+         '</header>'\n\t\t\t\t\t+         '<div id=\"story-caption\"></div>'\n\t\t\t\t\t+         '<nav id=\"menu\" role=\"navigation\">'\n\t\t\t\t\t+             '<ul id=\"menu-story\"></ul>'\n\t\t\t\t\t+             '<ul id=\"menu-core\">'\n\t\t\t\t\t+                 `<li id=\"menu-item-saves\"><a tabindex=\"0\">${L10n.get('savesTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-settings\"><a tabindex=\"0\">${L10n.get('settingsTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-restart\"><a tabindex=\"0\">${L10n.get('restartTitle')}</a></li>`\n\t\t\t\t\t+                 `<li id=\"menu-item-share\"><a tabindex=\"0\">${L10n.get('shareTitle')}</a></li>`\n\t\t\t\t\t+             '</ul>'\n\t\t\t\t\t+         '</nav>'\n\t\t\t\t\t+     '</div>'\n\t\t\t\t\t+ '</div>'\n\t\t\t\t\t/* eslint-enable max-len */\n\t\t\t\t);\n\t\t})();\n\n\t\t/*\n\t\t\tCache the UI bar element, since its going to be used often.\n\n\t\t\tNOTE: We rewrap the element itself, rather than simply using the result\n\t\t\tof `find()`, so that we cache an uncluttered jQuery-wrapper (i.e. `context`\n\t\t\trefers to the element and there is no `prevObject`).\n\t\t*/\n\t\t_$uiBar = jQuery($elems.find('#ui-bar').get(0));\n\n\t\t// Insert the UI bar elements into the page before the main script.\n\t\t$elems.insertBefore('body>script#script-sugarcube');\n\n\t\t// Set up the UI bar's global event handlers.\n\t\tjQuery(document)\n\t\t\t// Set up a handler for the history-backward/-forward buttons.\n\t\t\t.on(':historyupdate.ui-bar', (($backward, $forward) => () => {\n\t\t\t\t$backward.ariaDisabled(State.length < 2);\n\t\t\t\t$forward.ariaDisabled(State.length === State.size);\n\t\t\t})(jQuery('#history-backward'), jQuery('#history-forward')));\n\t}\n\n\tfunction uiBarIsHidden() {\n\t\treturn _$uiBar && _$uiBar.css('display') === 'none';\n\t}\n\n\tfunction uiBarIsStowed() {\n\t\treturn _$uiBar && _$uiBar.hasClass('stowed');\n\t}\n\n\tfunction uiBarShow() {\n\t\tif (_$uiBar) {\n\t\t\t_$uiBar.show();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarStart() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarStart()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Set up the #ui-bar's initial state.\n\t\tif (\n\t\t\ttypeof Config.ui.stowBarInitially === 'boolean'\n\t\t\t\t? Config.ui.stowBarInitially\n\t\t\t\t: jQuery(window).width() <= Config.ui.stowBarInitially\n\t\t) {\n\t\t\tuiBarStow(true);\n\t\t}\n\n\t\t// Set up the #ui-bar-toggle and #ui-bar-history widgets.\n\t\tjQuery('#ui-bar-toggle')\n\t\t\t.ariaClick({\n\t\t\t\tlabel : L10n.get('uiBarToggle')\n\t\t\t}, () => _$uiBar.toggleClass('stowed'));\n\n\t\tif (Config.history.controls) {\n\t\t\tjQuery('#history-backward')\n\t\t\t\t.ariaDisabled(State.length < 2)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tlabel : L10n.get('uiBarBackward')\n\t\t\t\t}, () => Engine.backward());\n\n\t\t\tif (Story.lookup('tags', 'bookmark').length > 0) {\n\t\t\t\tjQuery('#history-jumpto')\n\t\t\t\t\t.ariaClick({\n\t\t\t\t\t\tlabel : L10n.get('uiBarJumpto')\n\t\t\t\t\t}, () => UI.jumpto());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tjQuery('#history-jumpto').remove();\n\t\t\t}\n\n\t\t\tjQuery('#history-forward')\n\t\t\t\t.ariaDisabled(State.length === State.size)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tlabel : L10n.get('uiBarForward')\n\t\t\t\t}, () => Engine.forward());\n\t\t}\n\t\telse {\n\t\t\tjQuery('#ui-bar-history').remove();\n\t\t}\n\n\t\t// Set up the story display title.\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t}\n\t\telse {\n\t\t\tif (TWINE1) { // for Twine 1\n\t\t\t\tsetPageElement('story-title', 'StoryTitle', Story.title);\n\t\t\t}\n\t\t\telse { // for Twine 2\n\t\t\t\tjQuery('#story-title').text(Story.title);\n\t\t\t}\n\t\t}\n\n\t\t// Set up the dynamic page elements.\n\t\tif (!Story.has('StoryCaption')) {\n\t\t\tjQuery('#story-caption').remove();\n\t\t}\n\n\t\tif (!Story.has('StoryMenu')) {\n\t\t\tjQuery('#menu-story').remove();\n\t\t}\n\n\t\tif (!Config.ui.updateStoryElements) {\n\t\t\t// We only need to set the story elements here if `Config.ui.updateStoryElements`\n\t\t\t// is falsy, since otherwise they will be set by `Engine.play()`.\n\t\t\tuiBarUpdate();\n\t\t}\n\n\t\t// Set up the Saves menu item.\n\t\tjQuery('#menu-item-saves a')\n\t\t\t.ariaClick(ev => {\n\t\t\t\tev.preventDefault();\n\t\t\t\tUI.buildSaves();\n\t\t\t\tDialog.open();\n\t\t\t})\n\t\t\t.text(L10n.get('savesTitle'));\n\n\t\t// Set up the Settings menu item.\n\t\tif (!Setting.isEmpty()) {\n\t\t\tjQuery('#menu-item-settings a')\n\t\t\t\t.ariaClick(ev => {\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\tUI.buildSettings();\n\t\t\t\t\tDialog.open();\n\t\t\t\t})\n\t\t\t\t.text(L10n.get('settingsTitle'));\n\t\t}\n\t\telse {\n\t\t\tjQuery('#menu-item-settings').remove();\n\t\t}\n\n\t\t// Set up the Restart menu item.\n\t\tjQuery('#menu-item-restart a')\n\t\t\t.ariaClick(ev => {\n\t\t\t\tev.preventDefault();\n\t\t\t\tUI.buildRestart();\n\t\t\t\tDialog.open();\n\t\t\t})\n\t\t\t.text(L10n.get('restartTitle'));\n\n\t\t// Set up the Share menu item.\n\t\tif (Story.has('StoryShare')) {\n\t\t\tjQuery('#menu-item-share a')\n\t\t\t\t.ariaClick(ev => {\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\tUI.buildShare();\n\t\t\t\t\tDialog.open();\n\t\t\t\t})\n\t\t\t\t.text(L10n.get('shareTitle'));\n\t\t}\n\t\telse {\n\t\t\tjQuery('#menu-item-share').remove();\n\t\t}\n\t}\n\n\tfunction uiBarStow(noAnimation) {\n\t\tif (_$uiBar && !_$uiBar.hasClass('stowed')) {\n\t\t\tlet $story;\n\n\t\t\tif (noAnimation) {\n\t\t\t\t$story = jQuery('#story');\n\t\t\t\t$story.addClass('no-transition');\n\t\t\t\t_$uiBar.addClass('no-transition');\n\t\t\t}\n\n\t\t\t_$uiBar.addClass('stowed');\n\n\t\t\tif (noAnimation) {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t$story.removeClass('no-transition');\n\t\t\t\t\t_$uiBar.removeClass('no-transition');\n\t\t\t\t}, Engine.minDomActionDelay);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarUnstow(noAnimation) {\n\t\tif (_$uiBar && _$uiBar.hasClass('stowed')) {\n\t\t\tlet $story;\n\n\t\t\tif (noAnimation) {\n\t\t\t\t$story = jQuery('#story');\n\t\t\t\t$story.addClass('no-transition');\n\t\t\t\t_$uiBar.addClass('no-transition');\n\t\t\t}\n\n\t\t\t_$uiBar.removeClass('stowed');\n\n\t\t\tif (noAnimation) {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t$story.removeClass('no-transition');\n\t\t\t\t\t_$uiBar.removeClass('no-transition');\n\t\t\t\t}, Engine.minDomActionDelay);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tfunction uiBarUpdate() {\n\t\tif (DEBUG) { console.log('[UIBar/uiBarUpdate()]'); }\n\n\t\tif (!_$uiBar) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Set up the (non-navigation) dynamic page elements.\n\t\tsetPageElement('story-banner', 'StoryBanner');\n\t\tif (Story.has('StoryDisplayTitle')) {\n\t\t\tsetDisplayTitle(Story.get('StoryDisplayTitle').processText());\n\t\t}\n\t\tsetPageElement('story-subtitle', 'StorySubtitle');\n\t\tsetPageElement('story-author', 'StoryAuthor');\n\t\tsetPageElement('story-caption', 'StoryCaption');\n\n\t\t// Set up the #menu-story items.\n\t\tconst menuStory = document.getElementById('menu-story');\n\n\t\tif (menuStory !== null) {\n\t\t\tjQuery(menuStory).empty();\n\n\t\t\tif (Story.has('StoryMenu')) {\n\t\t\t\ttry {\n\t\t\t\t\tUI.assembleLinkList('StoryMenu', menuStory);\n\t\t\t\t}\n\t\t\t\tcatch (ex) {\n\t\t\t\t\tconsole.error(ex);\n\t\t\t\t\tAlert.error('StoryMenu', ex.message);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/*******************************************************************************\n\t\tObject Exports.\n\t*******************************************************************************/\n\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tdestroy  : { value : uiBarDestroy },\n\t\thide     : { value : uiBarHide },\n\t\tinit     : { value : uiBarInit },\n\t\tisHidden : { value : uiBarIsHidden },\n\t\tisStowed : { value : uiBarIsStowed },\n\t\tshow     : { value : uiBarShow },\n\t\tstart    : { value : uiBarStart },\n\t\tstow     : { value : uiBarStow },\n\t\tunstow   : { value : uiBarUnstow },\n\t\tupdate   : { value : uiBarUpdate },\n\n\t\t// Legacy Functions.\n\t\tsetStoryElements : { value : uiBarUpdate }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tdebugbar.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal DebugView, Engine, L10n, Patterns, State, Util, session\n*/\n\nvar DebugBar = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\tconst _variableRe   = new RegExp(`^${Patterns.variable}$`);\n\tconst _numericKeyRe = /^\\d+$/;\n\tconst _watchList    = [];\n\tlet _$debugBar   = null;\n\tlet _$watchBody  = null;\n\tlet _$watchList  = null;\n\tlet _$turnSelect = null;\n\tlet _stowed      = true;\n\n\n\t/*******************************************************************************************************************\n\t\tDebug Bar Functions.\n\t*******************************************************************************************************************/\n\tfunction debugBarInit() {\n\t\tif (DEBUG) { console.log('[DebugBar/debugBarInit()]'); }\n\n\t\t/*\n\t\t\tGenerate the debug bar elements and append them to the `<body>`.\n\t\t*/\n\t\tconst barToggleLabel   = L10n.get('debugBarToggle');\n\t\tconst watchAddLabel    = L10n.get('debugBarAddWatch');\n\t\tconst watchAllLabel    = L10n.get('debugBarWatchAll');\n\t\tconst watchNoneLabel   = L10n.get('debugBarWatchNone');\n\t\tconst watchToggleLabel = L10n.get('debugBarWatchToggle');\n\t\tconst viewsToggleLabel = L10n.get('debugBarViewsToggle');\n\n\t\tjQuery(document.createDocumentFragment())\n\t\t\t.append(\n\t\t\t\t/* eslint-disable max-len */\n\t\t\t\t  '<div id=\"debug-bar\">'\n\t\t\t\t+     '<div id=\"debug-bar-watch\">'\n\t\t\t\t+         `<div>${L10n.get('debugBarNoWatches')}</div>>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div>'\n\t\t\t\t+         `<button id=\"debug-bar-watch-toggle\" tabindex=\"0\" title=\"${watchToggleLabel}\" aria-label=\"${watchToggleLabel}\">${L10n.get('debugBarLabelWatch')}</button>`\n\t\t\t\t+         `<label id=\"debug-bar-watch-label\" for=\"debug-bar-watch-input\">${L10n.get('debugBarLabelAdd')}</label>`\n\t\t\t\t+         '<input id=\"debug-bar-watch-input\" name=\"debug-bar-watch-input\" type=\"text\" list=\"debug-bar-watch-list\" tabindex=\"0\">'\n\t\t\t\t+         '<datalist id=\"debug-bar-watch-list\" aria-hidden=\"true\" hidden=\"hidden\"></datalist>'\n\t\t\t\t+         `<button id=\"debug-bar-watch-add\" tabindex=\"0\" title=\"${watchAddLabel}\" aria-label=\"${watchAddLabel}\"></button>`\n\t\t\t\t+         `<button id=\"debug-bar-watch-all\" tabindex=\"0\" title=\"${watchAllLabel}\" aria-label=\"${watchAllLabel}\"></button>`\n\t\t\t\t+         `<button id=\"debug-bar-watch-none\" tabindex=\"0\" title=\"${watchNoneLabel}\" aria-label=\"${watchNoneLabel}\"></button>`\n\t\t\t\t+     '</div>'\n\t\t\t\t+     '<div>'\n\t\t\t\t+         `<button id=\"debug-bar-views-toggle\" tabindex=\"0\" title=\"${viewsToggleLabel}\" aria-label=\"${viewsToggleLabel}\">${L10n.get('debugBarLabelViews')}</button>`\n\t\t\t\t+         `<label id=\"debug-bar-turn-label\" for=\"debug-bar-turn-select\">${L10n.get('debugBarLabelTurn')}</label>`\n\t\t\t\t+         '<select id=\"debug-bar-turn-select\" tabindex=\"0\"></select>'\n\t\t\t\t+     '</div>'\n\t\t\t\t+     `<button id=\"debug-bar-toggle\" tabindex=\"0\" title=\"${barToggleLabel}\" aria-label=\"${barToggleLabel}\"></button>`\n\t\t\t\t+ '</div>'\n\t\t\t\t+ '<div id=\"debug-bar-hint\"></div>'\n\t\t\t\t/* eslint-enable max-len */\n\t\t\t)\n\t\t\t.appendTo('body');\n\n\t\t/*\n\t\t\tCache various oft used elements.\n\n\t\t\tNOTE: We rewrap the elements themselves, rather than simply using\n\t\t\tthe results of `find()`, so that we cache uncluttered jQuery-wrappers\n\t\t\t(i.e. `context` refers to the elements and there is no `prevObject`).\n\t\t*/\n\t\t_$debugBar   = jQuery('#debug-bar');\n\t\t_$watchBody  = jQuery(_$debugBar.find('#debug-bar-watch').get(0));\n\t\t_$watchList  = jQuery(_$debugBar.find('#debug-bar-watch-list').get(0));\n\t\t_$turnSelect = jQuery(_$debugBar.find('#debug-bar-turn-select').get(0));\n\n\t\tconst $barToggle   = jQuery(_$debugBar.find('#debug-bar-toggle').get(0));\n\t\tconst $watchToggle = jQuery(_$debugBar.find('#debug-bar-watch-toggle').get(0));\n\t\tconst $watchInput  = jQuery(_$debugBar.find('#debug-bar-watch-input').get(0));\n\t\tconst $watchAdd    = jQuery(_$debugBar.find('#debug-bar-watch-add').get(0));\n\t\tconst $watchAll    = jQuery(_$debugBar.find('#debug-bar-watch-all').get(0));\n\t\tconst $watchNone   = jQuery(_$debugBar.find('#debug-bar-watch-none').get(0));\n\t\tconst $viewsToggle = jQuery(_$debugBar.find('#debug-bar-views-toggle').get(0));\n\n\t\t/*\n\t\t\tSet up the debug bar's local event handlers.\n\t\t*/\n\t\t$barToggle\n\t\t\t.ariaClick(debugBarToggle);\n\t\t$watchToggle\n\t\t\t.ariaClick(debugBarWatchToggle);\n\t\t$watchInput\n\t\t\t.on(':addwatch', function () {\n\t\t\t\tdebugBarWatchAdd(this.value.trim());\n\t\t\t\tthis.value = '';\n\t\t\t})\n\t\t\t.on('keypress', ev => {\n\t\t\t\tif (ev.which === 13) { // 13 is Return/Enter\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t$watchInput.trigger(':addwatch');\n\t\t\t\t}\n\t\t\t});\n\t\t$watchAdd\n\t\t\t.ariaClick(() => $watchInput.trigger(':addwatch'));\n\t\t$watchAll\n\t\t\t.ariaClick(debugBarWatchAddAll);\n\t\t$watchNone\n\t\t\t.ariaClick(debugBarWatchClear);\n\t\t_$turnSelect\n\t\t\t.on('change', function () {\n\t\t\t\tEngine.goTo(Number(this.value));\n\t\t\t});\n\t\t$viewsToggle\n\t\t\t.ariaClick(() => {\n\t\t\t\tDebugView.toggle();\n\t\t\t\t_updateSession();\n\t\t\t});\n\n\t\t/*\n\t\t\tSet up the debug bar's global event handlers.\n\t\t*/\n\t\tjQuery(document)\n\t\t\t// Set up a handler for the history select.\n\t\t\t.on(':historyupdate.debug-bar', _updateTurnSelect)\n\t\t\t// Set up a handler for the variables watch.\n\t\t\t.on(':passageend.debug-bar', () => {\n\t\t\t\t_updateWatchBody();\n\t\t\t\t_updateWatchList();\n\t\t\t})\n\t\t\t// Set up a handler for engine resets to clear the active debug session.\n\t\t\t.on(':enginerestart.debug-bar', _clearSession);\n\n\t\t/*\n\t\t\tInitially enable debug views if there's no active debug session.\n\t\t*/\n\t\tif (!_hasSession()) {\n\t\t\tDebugView.enable();\n\t\t}\n\t}\n\n\tfunction debugBarStart() {\n\t\tif (DEBUG) { console.log('[DebugBar/debugBarStart()]'); }\n\n\t\t// Attempt to restore an existing session.\n\t\t_restoreSession();\n\n\t\t// Update the UI.\n\t\t_updateBar();\n\t\t_updateTurnSelect();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t}\n\n\tfunction debugBarIsStowed() {\n\t\treturn _stowed;\n\t}\n\n\tfunction debugBarStow() {\n\t\t_debugBarStowNoUpdate();\n\t\t_stowed = true;\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarUnstow() {\n\t\t_debugBarUnstowNoUpdate();\n\t\t_stowed = false;\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarToggle() {\n\t\tif (_stowed) {\n\t\t\tdebugBarUnstow();\n\t\t}\n\t\telse {\n\t\t\tdebugBarStow();\n\t\t}\n\t}\n\n\tfunction debugBarWatchAdd(varName) {\n\t\tif (!_variableRe.test(varName)) {\n\t\t\treturn;\n\t\t}\n\n\t\t_watchList.pushUnique(varName);\n\t\t_watchList.sort();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchAddAll() {\n\t\tObject.keys(State.variables).map(name => _watchList.pushUnique(`$${name}`));\n\t\tObject.keys(State.temporary).map(name => _watchList.pushUnique(`_${name}`));\n\n\t\t_watchList.sort();\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchClear() {\n\t\tfor (let i = _watchList.length - 1; i >= 0; --i) {\n\t\t\t_watchList.pop();\n\t\t}\n\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchDelete(varName) {\n\t\t_watchList.delete(varName);\n\t\t_updateWatchBody();\n\t\t_updateWatchList();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchDisable() {\n\t\t_debugBarWatchDisableNoUpdate();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchEnable() {\n\t\t_debugBarWatchEnableNoUpdate();\n\t\t_updateSession();\n\t}\n\n\tfunction debugBarWatchIsEnabled() {\n\t\treturn !_$watchBody.attr('hidden');\n\t}\n\n\tfunction debugBarWatchToggle() {\n\t\tif (_$watchBody.attr('hidden')) {\n\t\t\tdebugBarWatchEnable();\n\t\t}\n\t\telse {\n\t\t\tdebugBarWatchDisable();\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tUtility Functions.\n\t*******************************************************************************************************************/\n\tfunction _debugBarStowNoUpdate() {\n\t\t_$debugBar.css('right', `-${_$debugBar.outerWidth()}px`);\n\t}\n\n\tfunction _debugBarUnstowNoUpdate() {\n\t\t_$debugBar.css('right', 0);\n\t}\n\n\tfunction _debugBarWatchDisableNoUpdate() {\n\t\t_$watchBody.attr({\n\t\t\t'aria-hidden' : true,\n\t\t\thidden        : 'hidden'\n\t\t});\n\t}\n\n\tfunction _debugBarWatchEnableNoUpdate() {\n\t\t_$watchBody.removeAttr('aria-hidden hidden');\n\t}\n\n\tfunction _clearSession() {\n\t\tsession.delete('debugState');\n\t}\n\n\tfunction _hasSession() {\n\t\treturn session.has('debugState');\n\t}\n\n\tfunction _restoreSession() {\n\t\tif (!_hasSession()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst debugState = session.get('debugState');\n\n\t\t_stowed = debugState.stowed;\n\n\t\t_watchList.push(...debugState.watchList);\n\n\t\tif (debugState.watchEnabled) {\n\t\t\t_debugBarWatchEnableNoUpdate();\n\t\t}\n\t\telse {\n\t\t\t_debugBarWatchDisableNoUpdate();\n\t\t}\n\n\t\tif (debugState.viewsEnabled) {\n\t\t\tDebugView.enable();\n\t\t}\n\t\telse {\n\t\t\tDebugView.disable();\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction _updateSession() {\n\t\tsession.set('debugState', {\n\t\t\tstowed       : _stowed,\n\t\t\twatchList    : _watchList,\n\t\t\twatchEnabled : debugBarWatchIsEnabled(),\n\t\t\tviewsEnabled : DebugView.isEnabled()\n\t\t});\n\t}\n\n\tfunction _updateBar() {\n\t\tif (_stowed) {\n\t\t\tdebugBarStow();\n\t\t}\n\t\telse {\n\t\t\tdebugBarUnstow();\n\t\t}\n\t}\n\n\tfunction _updateWatchBody() {\n\t\tif (_watchList.length === 0) {\n\t\t\t_$watchBody\n\t\t\t\t.empty()\n\t\t\t\t.append(`<div>${L10n.get('debugBarNoWatches')}</div>`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst delLabel = L10n.get('debugBarDeleteWatch');\n\t\tconst $table   = jQuery(document.createElement('table'));\n\t\tconst $tbody   = jQuery(document.createElement('tbody'));\n\n\t\tfor (let i = 0, len = _watchList.length; i < len; ++i) {\n\t\t\tconst varName = _watchList[i];\n\t\t\tconst varKey  = varName.slice(1);\n\t\t\tconst store   = varName[0] === '$' ? State.variables : State.temporary;\n\t\t\tconst $row    = jQuery(document.createElement('tr'));\n\t\t\tconst $delBtn = jQuery(document.createElement('button'));\n\t\t\tconst $code   = jQuery(document.createElement('code'));\n\n\t\t\t$delBtn\n\t\t\t\t.addClass('watch-delete')\n\t\t\t\t.attr('data-name', varName)\n\t\t\t\t.ariaClick({\n\t\t\t\t\tone   : true,\n\t\t\t\t\tlabel : delLabel\n\t\t\t\t}, () => debugBarWatchDelete(varName));\n\t\t\t$code\n\t\t\t\t.text(_toWatchString(store[varKey]));\n\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.append($delBtn)\n\t\t\t\t.appendTo($row);\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.text(varName)\n\t\t\t\t.appendTo($row);\n\t\t\tjQuery(document.createElement('td'))\n\t\t\t\t.append($code)\n\t\t\t\t.appendTo($row);\n\t\t\t$row\n\t\t\t\t.appendTo($tbody);\n\t\t}\n\n\t\t$table\n\t\t\t.append($tbody);\n\t\t_$watchBody\n\t\t\t.empty()\n\t\t\t.append($table);\n\t}\n\n\tfunction _updateWatchList() {\n\t\tconst svn = Object.keys(State.variables);\n\t\tconst tvn = Object.keys(State.temporary);\n\n\t\tif (svn.length === 0 && tvn.length === 0) {\n\t\t\t_$watchList.empty();\n\t\t\treturn;\n\t\t}\n\n\t\tconst names   = [...svn.map(name => `$${name}`), ...tvn.map(name => `_${name}`)].sort();\n\t\tconst options = document.createDocumentFragment();\n\n\t\tnames.delete(_watchList);\n\n\t\tfor (let i = 0, len = names.length; i < len; ++i) {\n\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t.val(names[i])\n\t\t\t\t.appendTo(options);\n\t\t}\n\n\t\t_$watchList\n\t\t\t.empty()\n\t\t\t.append(options);\n\t}\n\n\tfunction _updateTurnSelect() {\n\t\tconst histLen = State.size;\n\t\tconst expLen  = State.expired.length;\n\t\tconst options = document.createDocumentFragment();\n\n\t\tfor (let i = 0; i < histLen; ++i) {\n\t\t\tjQuery(document.createElement('option'))\n\t\t\t\t.val(i)\n\t\t\t\t.text(`${expLen + i + 1}. ${Util.escape(State.history[i].title)}`)\n\t\t\t\t.appendTo(options);\n\t\t}\n\n\t\t_$turnSelect\n\t\t\t.empty()\n\t\t\t.ariaDisabled(histLen < 2)\n\t\t\t.append(options)\n\t\t\t.val(State.activeIndex);\n\t}\n\n\tfunction _toWatchString(value) {\n\t\t/*\n\t\t\tHandle the `null` primitive.\n\t\t*/\n\t\tif (value === null) {\n\t\t\treturn 'null';\n\t\t}\n\n\t\t/*\n\t\t\tHandle the rest of the primitives and functions.\n\t\t*/\n\t\tswitch (typeof value) {\n\t\tcase 'number':\n\t\t\tif (Number.isNaN(value)) {\n\t\t\t\treturn 'NaN';\n\t\t\t}\n\t\t\telse if (!Number.isFinite(value)) {\n\t\t\t\treturn 'Infinity';\n\t\t\t}\n\t\t\t/* falls through */\n\t\tcase 'boolean':\n\t\tcase 'symbol':\n\t\tcase 'undefined':\n\t\t\treturn String(value);\n\n\t\tcase 'string':\n\t\t\treturn JSON.stringify(value);\n\n\t\t// case 'symbol':\n\t\t// \treturn `Symbol\\u202F\"${String(value).slice(7, -1)}\"`;\n\n\t\tcase 'function':\n\t\t\t// return JSON.stringify(value.toString());\n\t\t\treturn 'Function';\n\t\t}\n\n\t\tconst objType = Util.toStringTag(value);\n\n\t\t// /*\n\t\t// \tHandle instances of the primitive exemplar objects (`Boolean`, `Number`, `String`).\n\t\t// */\n\t\t// if (objType === 'Boolean') {\n\t\t// \treturn `Boolean\\u202F{${String(value)}}`;\n\t\t// }\n\t\t// if (objType === 'Number') {\n\t\t// \treturn `Number\\u202F{${String(value)}}`;\n\t\t// }\n\t\t// if (objType === 'String') {\n\t\t// \treturn `String\\u202F{\"${String(value)}\"}`;\n\t\t// }\n\n\t\t/*\n\t\t\tHandle `Date` objects.\n\t\t*/\n\t\tif (objType === 'Date') {\n\t\t\t// return `Date\\u202F${value.toISOString()}`;\n\t\t\treturn `Date\\u202F{${value.toLocaleString()}}`;\n\t\t}\n\n\t\t/*\n\t\t\tHandle `RegExp` objects.\n\t\t*/\n\t\tif (objType === 'RegExp') {\n\t\t\treturn `RegExp\\u202F${value.toString()}`;\n\t\t}\n\n\t\tconst result = [];\n\n\t\t/*\n\t\t\tHandle `Array` & `Set` objects.\n\t\t*/\n\t\tif (value instanceof Array || value instanceof Set) {\n\t\t\tconst list = value instanceof Array ? value : Array.from(value);\n\n\t\t\t// own numeric properties\n\t\t\t// NOTE: Do not use `<Array>.forEach()` here as it skips undefined members.\n\t\t\tfor (let i = 0, len = list.length; i < len; ++i) {\n\t\t\t\tresult.push(list.hasOwnProperty(i) ? _toWatchString(list[i]) : '<empty>');\n\t\t\t}\n\n\t\t\t// own enumerable non-numeric expando properties\n\t\t\tObject.keys(list)\n\t\t\t\t.filter(key => !_numericKeyRe.test(key))\n\t\t\t\t.forEach(key => result.push(`${_toWatchString(key)}: ${_toWatchString(list[key])}`));\n\n\t\t\treturn `${objType}(${list.length})\\u202F[${result.join(', ')}]`;\n\t\t}\n\n\t\t/*\n\t\t\tHandle `Map` objects.\n\t\t*/\n\t\tif (value instanceof Map) {\n\t\t\tvalue.forEach((val, key) => result.push(`${_toWatchString(key)} \\u2192 ${_toWatchString(val)}`));\n\n\t\t\treturn `${objType}(${value.size})\\u202F{${result.join(', ')}}`;\n\t\t}\n\n\t\t/*\n\t\t\tGeneral object handling.\n\t\t*/\n\t\t// own enumerable properties\n\t\tObject.keys(value)\n\t\t\t.forEach(key => result.push(`${_toWatchString(key)}: ${_toWatchString(value[key])}`));\n\n\t\treturn `${objType}\\u202F{${result.join(', ')}}`;\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\t/*\n\t\t\tDebug Bar Functions.\n\t\t*/\n\t\tinit     : { value : debugBarInit },\n\t\tisStowed : { value : debugBarIsStowed },\n\t\tstart    : { value : debugBarStart },\n\t\tstow     : { value : debugBarStow },\n\t\ttoggle   : { value : debugBarToggle },\n\t\tunstow   : { value : debugBarUnstow },\n\n\t\t/*\n\t\t\tWatch Functions.\n\t\t*/\n\t\twatch : {\n\t\t\tvalue : Object.freeze(Object.defineProperties({}, {\n\t\t\t\tadd       : { value : debugBarWatchAdd },\n\t\t\t\tall       : { value : debugBarWatchAddAll },\n\t\t\t\tclear     : { value : debugBarWatchClear },\n\t\t\t\tdelete    : { value : debugBarWatchDelete },\n\t\t\t\tdisable   : { value : debugBarWatchDisable },\n\t\t\t\tenable    : { value : debugBarWatchEnable },\n\t\t\t\tisEnabled : { value : debugBarWatchIsEnabled },\n\t\t\t\ttoggle    : { value : debugBarWatchToggle }\n\t\t\t}))\n\t\t}\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tloadscreen.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/* global Config, Engine */\n\nvar LoadScreen = (() => { // eslint-disable-line no-unused-vars, no-var\n\t'use strict';\n\n\t// Locks collection.\n\tconst _locks = new Set();\n\n\t// Auto-incrementing lock ID.\n\tlet _autoId = 0;\n\n\n\t/*******************************************************************************************************************\n\t\tLoadScreen Functions.\n\t*******************************************************************************************************************/\n\t/*\n\t\tInitialize management of the loading screen.\n\t*/\n\tfunction loadScreenInit() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenInit()]'); }\n\n\t\t// Add a `readystatechange` listener for hiding/showing the loading screen.\n\t\tjQuery(document).on('readystatechange.SugarCube', () => {\n\t\t\tif (DEBUG) { console.log(`[LoadScreen/<readystatechange>] document.readyState: \"${document.readyState}\"; locks(${_locks.size}):`, _locks); }\n\n\t\t\tif (_locks.size > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// The value of `document.readyState` may be: 'loading' -> 'interactive' -> 'complete'.\n\t\t\t// Though, to reach this point, it must already be in, at least, the 'interactive' state.\n\t\t\tif (document.readyState === 'complete') {\n\t\t\t\tif (jQuery(document.documentElement).attr('data-init') === 'loading') {\n\t\t\t\t\tif (Config.loadDelay > 0) {\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tif (_locks.size === 0) {\n\t\t\t\t\t\t\t\tloadScreenHide();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, Math.max(Engine.minDomActionDelay, Config.loadDelay));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tloadScreenHide();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloadScreenShow();\n\t\t\t}\n\t\t});\n\t}\n\n\t/*\n\t\tClear the loading screen.\n\t*/\n\tfunction loadScreenClear() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenClear()]'); }\n\n\t\t// Remove the event listener.\n\t\tjQuery(document).off('readystatechange.SugarCube');\n\n\t\t// Clear all locks.\n\t\t_locks.clear();\n\n\t\t// Hide the loading screen.\n\t\tloadScreenHide();\n\t}\n\n\t/*\n\t\tHide the loading screen.\n\t*/\n\tfunction loadScreenHide() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenHide()]'); }\n\n\t\tjQuery(document.documentElement).removeAttr('data-init');\n\t}\n\n\t/*\n\t\tShow the loading screen.\n\t*/\n\tfunction loadScreenShow() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenShow()]'); }\n\n\t\tjQuery(document.documentElement).attr('data-init', 'loading');\n\t}\n\n\t/*\n\t\tReturns a new lock ID after locking and showing the loading screen.\n\t*/\n\tfunction loadScreenLock() {\n\t\tif (DEBUG) { console.log('[LoadScreen/loadScreenLock()]'); }\n\n\t\t++_autoId;\n\t\t_locks.add(_autoId);\n\n\t\tif (DEBUG) { console.log(`\\tacquired loading screen lock; id: ${_autoId}`); }\n\n\t\tloadScreenShow();\n\t\treturn _autoId;\n\t}\n\n\t/*\n\t\tRemove the lock associated with the given lock ID and, if no locks remain,\n\t\ttrigger a `readystatechange` event.\n\t*/\n\tfunction loadScreenUnlock(id) {\n\t\tif (DEBUG) { console.log(`[LoadScreen/loadScreenUnlock(id: ${id})]`); }\n\n\t\tif (id == null) { // lazy equality for null\n\t\t\tthrow new Error('LoadScreen.unlock called with a null or undefined ID');\n\t\t}\n\n\t\tif (_locks.has(id)) {\n\t\t\t_locks.delete(id);\n\n\t\t\tif (DEBUG) { console.log(`\\treleased loading screen lock; id: ${id}`); }\n\t\t}\n\n\t\tif (_locks.size === 0) {\n\t\t\tjQuery(document).trigger('readystatechange');\n\t\t}\n\t}\n\n\n\t/*******************************************************************************************************************\n\t\tModule Exports.\n\t*******************************************************************************************************************/\n\treturn Object.freeze(Object.defineProperties({}, {\n\t\tinit   : { value : loadScreenInit },\n\t\tclear  : { value : loadScreenClear },\n\t\thide   : { value : loadScreenHide },\n\t\tshow   : { value : loadScreenShow },\n\t\tlock   : { value : loadScreenLock },\n\t\tunlock : { value : loadScreenUnlock }\n\t}));\n})();\n\n/***********************************************************************************************************************\n\n\tsugarcube.js\n\n\tCopyright © 2013–2020 Thomas Michael Edwards <thomasmedwards@gmail.com>. All rights reserved.\n\tUse of this source code is governed by a BSD 2-clause \"Simplified\" License, which may be found in the LICENSE file.\n\n***********************************************************************************************************************/\n/*\n\tglobal Alert, Browser, Config, Dialog, Engine, Fullscreen, Has, LoadScreen, SimpleStore, L10n, Macro, Passage,\n\t       Save, Scripting, Setting, SimpleAudio, State, Story, UI, UIBar, DebugBar, Util, Visibility, Wikifier\n*/\n/* eslint-disable no-var */\n\n/*\n\tVersion object.\n*/\nvar version = Object.freeze({\n\ttitle      : 'SugarCube',\n\tmajor      : 2,\n\tminor      : 31,\n\tpatch      : 1,\n\tprerelease : null,\n\tbuild      : 21,\n\tdate       : new Date(\"2020-05-06T21:53:59.980Z\"),\n\t/* legacy */\n\textensions : {},\n\t/* /legacy */\n\n\ttoString() {\n\t\t'use strict';\n\n\t\tconst prerelease = this.prerelease ? `-${this.prerelease}` : '';\n\t\treturn `${this.major}.${this.minor}.${this.patch}${prerelease}+${this.build}`;\n\t},\n\n\tshort() {\n\t\t'use strict';\n\n\t\tconst prerelease = this.prerelease ? `-${this.prerelease}` : '';\n\t\treturn `${this.title} (v${this.major}.${this.minor}.${this.patch}${prerelease})`;\n\t},\n\n\tlong() {\n\t\t'use strict';\n\n\t\treturn `${this.title} v${this.toString()} (${this.date.toUTCString()})`;\n\t}\n});\n\n/* eslint-disable no-unused-vars */\n/*\n\tInternal variables.\n*/\n// Temporary state object.\nvar TempState = {};\n\n// Legacy macros object.\nvar macros = {};\n\n// Post-display task callbacks object.\nvar postdisplay = {};\n\n// Post-render task callbacks object.\nvar postrender = {};\n\n// Pre-display task callbacks object.\nvar predisplay = {};\n\n// Pre-history task callbacks object.\nvar prehistory = {};\n\n// Pre-render task callbacks object.\nvar prerender = {};\n\n// Session storage manager object.\nvar session = null;\n\n// Settings object.\nvar settings = {};\n\n// Setup object.\nvar setup = {};\n\n// Persistant storage manager object.\nvar storage = null;\n\n/*\n\tLegacy aliases.\n*/\nvar browser       = Browser;\nvar config        = Config;\nvar has           = Has;\nvar History       = State;\nvar state         = State;\nvar tale          = Story;\nvar TempVariables = State.temporary;\n/* eslint-enable no-unused-vars */\n\n/*\n\tGlobal `SugarCube` object.  Allows scripts to detect if they're running in SugarCube by\n\ttesting for the object (e.g. `\"SugarCube\" in window`) and contains exported identifiers\n\tfor debugging purposes.\n*/\nwindow.SugarCube = {};\n\n/*\n\tMain function, entry point for the story.\n*/\njQuery(() => {\n\t'use strict';\n\n\tif (DEBUG) { console.log('[SugarCube/main()] Document loaded; beginning startup.'); }\n\n\t/*\n\t\tWARNING!\n\n\t\tThe ordering of the code within this function is critically important,\n\t\tso be careful when mucking around with it.\n\t*/\n\ttry {\n\t\t// Acquire an initial lock for and initialize the loading screen.\n\t\tconst lockId = LoadScreen.lock();\n\t\tLoadScreen.init();\n\n\t\t// Normalize the document.\n\t\tif (document.normalize) {\n\t\t\tdocument.normalize();\n\t\t}\n\n\t\t// Load the story data (must be done before most anything else).\n\t\tStory.load();\n\n\t\t// Instantiate the storage and session objects.\n\t\t// NOTE: `SimpleStore.create(storageId, persistent)`\n\t\tstorage = SimpleStore.create(Story.domId, true);\n\t\tsession = SimpleStore.create(Story.domId, false);\n\n\t\t// Initialize the user interface (must be done before story initialization, specifically before scripts).\n\t\tDialog.init();\n\t\tUIBar.init();\n\t\tEngine.init();\n\n\t\t// Initialize the story (largely load the user styles, scripts, and widgets).\n\t\tStory.init();\n\n\t\t// Initialize the localization (must be done after story initialization).\n\t\tL10n.init();\n\n\t\t// Alert when the browser is degrading required capabilities (must be done after localization initialization).\n\t\tif (!session.has('rcWarn') && storage.name === 'cookie') {\n\t\t\t/* eslint-disable no-alert */\n\t\t\tsession.set('rcWarn', 1);\n\t\t\twindow.alert(L10n.get('warningNoWebStorage'));\n\t\t\t/* eslint-enable no-alert */\n\t\t}\n\n\t\t// Initialize the saves (must be done after story initialization, but before engine start).\n\t\tSave.init();\n\n\t\t// Initialize the settings.\n\t\tSetting.init();\n\n\t\t// Initialize the macros.\n\t\tMacro.init();\n\n\t\t// Start the engine (should be done as late as possible, but before interface startup).\n\t\tEngine.start();\n\n\t\t// Initialize the debug bar interface (should be done as late as possible, but before interface startup).\n\t\tif (Config.debug) {\n\t\t\tDebugBar.init();\n\t\t}\n\n\t\t// Set a recurring timer to start the interfaces (necessary due to DOM readiness issues in some browsers).\n\t\tconst $window    = $(window);\n\t\tconst vprCheckId = setInterval(() => {\n\t\t\t// If `$window.width()` returns a zero value, bail out and wait.\n\t\t\tif (!$window.width()) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Clear the recurring timer.\n\t\t\tclearInterval(vprCheckId);\n\n\t\t\t// Start the UI bar interface.\n\t\t\tUIBar.start();\n\n\t\t\t// Start the debug bar interface.\n\t\t\tif (Config.debug) {\n\t\t\t\tDebugBar.start();\n\t\t\t}\n\n\t\t\t// Trigger the `:storyready` global synthetic event.\n\t\t\tjQuery.event.trigger({ type : ':storyready' });\n\n\t\t\t// Release the loading screen lock after a short delay.\n\t\t\tsetTimeout(() => LoadScreen.unlock(lockId), Engine.minDomActionDelay * 2);\n\t\t}, Engine.minDomActionDelay);\n\n\t\t// Finally, export identifiers for debugging purposes.\n\t\tObject.defineProperty(window, 'SugarCube', {\n\t\t\t// WARNING: We need to assign new values at points, so seal it, do not freeze it.\n\t\t\tvalue : Object.seal(Object.assign(Object.create(null), {\n\t\t\t\tBrowser,\n\t\t\t\tConfig,\n\t\t\t\tDialog,\n\t\t\t\tEngine,\n\t\t\t\tFullscreen,\n\t\t\t\tHas,\n\t\t\t\tL10n,\n\t\t\t\tMacro,\n\t\t\t\tPassage,\n\t\t\t\tSave,\n\t\t\t\tScripting,\n\t\t\t\tSetting,\n\t\t\t\tSimpleAudio,\n\t\t\t\tState,\n\t\t\t\tStory,\n\t\t\t\tUI,\n\t\t\t\tUIBar,\n\t\t\t\tDebugBar,\n\t\t\t\tUtil,\n\t\t\t\tVisibility,\n\t\t\t\tWikifier,\n\t\t\t\tsession,\n\t\t\t\tsettings,\n\t\t\t\tsetup,\n\t\t\t\tstorage,\n\t\t\t\tversion\n\t\t\t}))\n\t\t});\n\n\t\tif (DEBUG) { console.log('[SugarCube/main()] Startup complete; story ready.'); }\n\t}\n\tcatch (ex) {\n\t\tconsole.error(ex);\n\t\tLoadScreen.clear();\n\t\treturn Alert.fatal(null, ex.message, ex);\n\t}\n});\n\n})(window, window.document, jQuery);\n}\n\t</script>\n</body>\n</html>\n"});
\ No newline at end of file
-- 
GitLab