! function() {
"use strict";
function FastClick(layer, options) {
function bind(method, context) {
return function() {
return method.apply(context, arguments)
}
}
var oldOnClick;
if (options = options || {}, this.trackingClick = !1, this.trackingClickStart = 0, this.targetElement = null, this.touchStartX = 0, this.touchStartY = 0, this.lastTouchIdentifier = 0, this.touchBoundary = options.touchBoundary || 10, this.layer = layer, this.tapDelay = options.tapDelay || 200, this.tapTimeout = options.tapTimeout || 700, !FastClick.notNeeded(layer)) {
for (var methods = ["onMouse", "onClick", "onTouchStart", "onTouchMove", "onTouchEnd", "onTouchCancel"], context = this, i = 0, l = methods.length; i < l; i++) context[methods[i]] = bind(context[methods[i]], context);
deviceIsAndroid && (layer.addEventListener("mouseover", this.onMouse, !0), layer.addEventListener("mousedown", this.onMouse, !0), layer.addEventListener("mouseup", this.onMouse, !0)), layer.addEventListener("click", this.onClick, !0), layer.addEventListener("touchstart", this.onTouchStart, !1), layer.addEventListener("touchmove", this.onTouchMove, !1), layer.addEventListener("touchend", this.onTouchEnd, !1), layer.addEventListener("touchcancel", this.onTouchCancel, !1), Event.prototype.stopImmediatePropagation || (layer.removeEventListener = function(type, callback, capture) {
var rmv = Node.prototype.removeEventListener;
"click" === type ? rmv.call(layer, type, callback.hijacked || callback, capture) : rmv.call(layer, type, callback, capture)
}, layer.addEventListener = function(type, callback, capture) {
var adv = Node.prototype.addEventListener;
"click" === type ? adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
event.propagationStopped || callback(event)
}), capture) : adv.call(layer, type, callback, capture)
}), "function" == typeof layer.onclick && (oldOnClick = layer.onclick, layer.addEventListener("click", function(event) {
oldOnClick(event)
}, !1), layer.onclick = null)
}
}
var deviceIsWindowsPhone = navigator.userAgent.indexOf("Windows Phone") >= 0,
deviceIsAndroid = navigator.userAgent.indexOf("Android") > 0 && !deviceIsWindowsPhone,
deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent) && !deviceIsWindowsPhone,
deviceIsIOS4 = deviceIsIOS && /OS 4_\d(_\d)?/.test(navigator.userAgent),
deviceIsIOSWithBadTarget = deviceIsIOS && /OS [6-7]_\d/.test(navigator.userAgent),
deviceIsBlackBerry10 = navigator.userAgent.indexOf("BB10") > 0;
FastClick.prototype.needsClick = function(target) {
switch (target.nodeName.toLowerCase()) {
case "button":
case "select":
case "textarea":
if (target.disabled) return !0;
break;
case "input":
if (deviceIsIOS && "file" === target.type || target.disabled) return !0;
break;
case "label":
case "iframe":
case "video":
return !0
}
return /\bneedsclick\b/.test(target.className)
}, FastClick.prototype.needsFocus = function(target) {
switch (target.nodeName.toLowerCase()) {
case "textarea":
return !0;
case "select":
return !deviceIsAndroid;
case "input":
switch (target.type) {
case "button":
case "checkbox":
case "file":
case "image":
case "radio":
case "submit":
return !1
}
return !target.disabled && !target.readOnly;
default:
return /\bneedsfocus\b/.test(target.className)
}
}, FastClick.prototype.sendClick = function(targetElement, event) {
var clickEvent, touch;
document.activeElement && document.activeElement !== targetElement && document.activeElement.blur(), touch = event.changedTouches[0], clickEvent = document.createEvent("MouseEvents"), clickEvent.initMouseEvent(this.determineEventType(targetElement), !0, !0, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, !1, !1, !1, !1, 0, null), clickEvent.forwardedTouchEvent = !0, targetElement.dispatchEvent(clickEvent)
}, FastClick.prototype.determineEventType = function(targetElement) {
return deviceIsAndroid && "select" === targetElement.tagName.toLowerCase() ? "mousedown" : "click"
}, FastClick.prototype.focus = function(targetElement) {
var length;
deviceIsIOS && targetElement.setSelectionRange && 0 !== targetElement.type.indexOf("date") && "time" !== targetElement.type && "month" !== targetElement.type ? (length = targetElement.value.length, targetElement.setSelectionRange(length, length)) : targetElement.focus()
}, FastClick.prototype.updateScrollParent = function(targetElement) {
var scrollParent, parentElement;
if (scrollParent = targetElement.fastClickScrollParent, !scrollParent || !scrollParent.contains(targetElement)) {
parentElement = targetElement;
do {
if (parentElement.scrollHeight > parentElement.offsetHeight) {
scrollParent = parentElement, targetElement.fastClickScrollParent = parentElement;
break
}
parentElement = parentElement.parentElement
} while (parentElement)
}
scrollParent && (scrollParent.fastClickLastScrollTop = scrollParent.scrollTop)
}, FastClick.prototype.getTargetElementFromEventTarget = function(eventTarget) {
return eventTarget.nodeType === Node.TEXT_NODE ? eventTarget.parentNode : eventTarget
}, FastClick.prototype.onTouchStart = function(event) {
var targetElement, touch, selection;
if (event.targetTouches.length > 1) return !0;
if (targetElement = this.getTargetElementFromEventTarget(event.target), touch = event.targetTouches[0], deviceIsIOS) {
if (selection = window.getSelection(), selection.rangeCount && !selection.isCollapsed) return !0;
if (!deviceIsIOS4) {
if (touch.identifier && touch.identifier === this.lastTouchIdentifier) return event.preventDefault(), !1;
this.lastTouchIdentifier = touch.identifier, this.updateScrollParent(targetElement)
}
}
return this.trackingClick = !0, this.trackingClickStart = event.timeStamp, this.targetElement = targetElement, this.touchStartX = touch.pageX, this.touchStartY = touch.pageY, event.timeStamp - this.lastClickTime < this.tapDelay && event.preventDefault(), !0
}, FastClick.prototype.touchHasMoved = function(event) {
var touch = event.changedTouches[0],
boundary = this.touchBoundary;
return Math.abs(touch.pageX - this.touchStartX) > boundary || Math.abs(touch.pageY - this.touchStartY) > boundary
}, FastClick.prototype.onTouchMove = function(event) {
return !this.trackingClick || ((this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) && (this.trackingClick = !1, this.targetElement = null), !0)
}, FastClick.prototype.findControl = function(labelElement) {
return void 0 !== labelElement.control ? labelElement.control : labelElement.htmlFor ? document.getElementById(labelElement.htmlFor) : labelElement.querySelector("button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea")
}, FastClick.prototype.onTouchEnd = function(event) {
var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;
if (!this.trackingClick) return !0;
if (event.timeStamp - this.lastClickTime < this.tapDelay) return this.cancelNextClick = !0, !0;
if (event.timeStamp - this.trackingClickStart > this.tapTimeout) return !0;
if (this.cancelNextClick = !1, this.lastClickTime = event.timeStamp, trackingClickStart = this.trackingClickStart, this.trackingClick = !1, this.trackingClickStart = 0, deviceIsIOSWithBadTarget && (touch = event.changedTouches[0], targetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset) || targetElement, targetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent), targetTagName = targetElement.tagName.toLowerCase(), "label" === targetTagName) {
if (forElement = this.findControl(targetElement)) {
if (this.focus(targetElement), deviceIsAndroid) return !1;
targetElement = forElement
}
} else if (this.needsFocus(targetElement)) return event.timeStamp - trackingClickStart > 100 || deviceIsIOS && window.top !== window && "input" === targetTagName ? (this.targetElement = null, !1) : (this.focus(targetElement), this.sendClick(targetElement, event), deviceIsIOS && "select" === targetTagName || (this.targetElement = null, event.preventDefault()), !1);
return !(!deviceIsIOS || deviceIsIOS4 || (scrollParent = targetElement.fastClickScrollParent, !scrollParent || scrollParent.fastClickLastScrollTop === scrollParent.scrollTop)) || (this.needsClick(targetElement) || (event.preventDefault(), this.sendClick(targetElement, event)), !1)
}, FastClick.prototype.onTouchCancel = function() {
this.trackingClick = !1, this.targetElement = null
}, FastClick.prototype.onMouse = function(event) {
return !this.targetElement || (!!event.forwardedTouchEvent || (!event.cancelable || (!(!this.needsClick(this.targetElement) || this.cancelNextClick) || (event.stopImmediatePropagation ? event.stopImmediatePropagation() : event.propagationStopped = !0, event.stopPropagation(), event.preventDefault(), !1))))
}, FastClick.prototype.onClick = function(event) {
var permitted;
return this.trackingClick ? (this.targetElement = null, this.trackingClick = !1, !0) : "submit" === event.target.type && 0 === event.detail || (permitted = this.onMouse(event), permitted || (this.targetElement = null), permitted)
}, FastClick.prototype.destroy = function() {
var layer = this.layer;
deviceIsAndroid && (layer.removeEventListener("mouseover", this.onMouse, !0), layer.removeEventListener("mousedown", this.onMouse, !0), layer.removeEventListener("mouseup", this.onMouse, !0)), layer.removeEventListener("click", this.onClick, !0), layer.removeEventListener("touchstart", this.onTouchStart, !1), layer.removeEventListener("touchmove", this.onTouchMove, !1), layer.removeEventListener("touchend", this.onTouchEnd, !1), layer.removeEventListener("touchcancel", this.onTouchCancel, !1)
}, FastClick.notNeeded = function(layer) {
var metaViewport, chromeVersion, blackberryVersion, firefoxVersion;
if ("undefined" == typeof window.ontouchstart) return !0;
if (chromeVersion = +(/Chrome\/([0-9]+)/.exec(navigator.userAgent) || [, 0])[1]) {
if (!deviceIsAndroid) return !0;
if (metaViewport = document.querySelector("meta[name=viewport]")) {
if (metaViewport.content.indexOf("user-scalable=no") !== -1) return !0;
if (chromeVersion > 31 && document.documentElement.scrollWidth <= window.outerWidth) return !0
}
}
if (deviceIsBlackBerry10 && (blackberryVersion = navigator.userAgent.match(/Version\/([0-9]*)\.([0-9]*)/), blackberryVersion[1] >= 10 && blackberryVersion[2] >= 3 && (metaViewport = document.querySelector("meta[name=viewport]")))) {
if (metaViewport.content.indexOf("user-scalable=no") !== -1) return !0;
if (document.documentElement.scrollWidth <= window.outerWidth) return !0
}
return "none" === layer.style.msTouchAction || "manipulation" === layer.style.touchAction || (firefoxVersion = +(/Firefox\/([0-9]+)/.exec(navigator.userAgent) || [, 0])[1], !!(firefoxVersion >= 27 && (metaViewport = document.querySelector("meta[name=viewport]"), metaViewport && (metaViewport.content.indexOf("user-scalable=no") !== -1 || document.documentElement.scrollWidth <= window.outerWidth))) || ("none" === layer.style.touchAction || "manipulation" === layer.style.touchAction))
}, FastClick.attach = function(layer, options) {
return new FastClick(layer, options)
}, "function" == typeof define && "object" == typeof define.amd && define.amd ? define(function() {
return FastClick
}) : "undefined" != typeof module && module.exports ? (module.exports = FastClick.attach, module.exports.FastClick = FastClick) : window.FastClick = FastClick
}(),
function() {
"use strict";
function startEngine() {
_haven_start()
}
var haven = {};
haven.error = function(message) {
var elem = document.createElement("div"),
spinner = document.getElementById("spinner"),
loader = document.getElementById("loader");
throw elem.id = "fatal-error", elem.innerHTML = message, document.body.appendChild(elem), spinner && spinner.parentNode.removeChild(spinner), loader && (loader.className = "stopped"), new Error(message)
}, haven.start = function(opt) {
haven.options.init(opt.options), haven.file.init(opt.virtualStoryfile), haven.assets.addCallback(function(cb) {
haven.input.init(), cb()
}), haven.prompt.init({
enginePrompt: !!opt.enginePrompt,
unicode: !!opt.unicode
}), haven.style.init({
engineFontFamily: !!opt.engineFontFamily
}), haven.assets.addCallback(function(cb) {
haven.loader.remove(), cb()
}), haven.assets.finalCallback(startEngine), "addEventListener" in document && document.addEventListener("DOMContentLoaded", function() {
FastClick.attach(document.body)
}, !1)
}, window.haven = haven
}(),
function() {
function done() {
var i = 0,
metaCallback = function() {
i++, i < callbacks.length ? callbacks[i](metaCallback) : lastCallback && lastCallback()
};
0 !== callbacks.length && callbacks[0](metaCallback)
}
var lastCallback, assets = {},
expectedAssets = ["engine", "storyfile"],
callbacks = [];
assets.addCallback = function(cb) {
0 === expectedAssets.length && setTimeout(cb, 0), callbacks.push(cb)
}, assets.expect = function(asset) {
return 0 === expectedAssets.length ? void console.warn('An expected asset "' + asset + '" was added but all previous assets have already finished loading') : void expectedAssets.push(asset)
}, assets.finalCallback = function(cb) {
lastCallback = cb
}, assets.finished = function(asset) {
var index = expectedAssets.indexOf(asset);
return index !== -1 && (expectedAssets.splice(index, 1), 0 === expectedAssets.length && done(), !0)
}, haven.assets = assets
}(window.haven || {}),
function() {
"use strict";
function encodeHtml(text) {
for (var encoded = "", i = 0; i < text.length; ++i)
if (text.charCodeAt(i) > 127) encoded += "" + text.charCodeAt(i) + ";";
else switch (text[i]) {
case "&":
encoded += "&";
break;
case "<":
encoded += "<";
break;
case ">":
encoded += ">";
break;
case "\r":
encoded += "\n";
break;
default:
encoded += text[i]
}
return encoded
}
var buffer = {},
outputBuffer = [""];
buffer.append = function(text, targetWindow) {
if (outputBuffer[targetWindow] || (outputBuffer[targetWindow] = ""), text.indexOf("\n") > -1 || text.indexOf("\r") > -1) {
var nextLBR = Math.max(text.lastIndexOf("\n"), text.lastIndexOf("\r")) + 1;
outputBuffer[targetWindow] += encodeHtml(text.substr(0, nextLBR)), haven.buffer.flush(targetWindow), outputBuffer[targetWindow] = encodeHtml(text.substr(nextLBR))
} else outputBuffer[targetWindow] += encodeHtml(text)
}, buffer.flush = function flush(targetWindow) {
if (void 0 === targetWindow)
for (var i in outputBuffer) flush(+i);
outputBuffer[targetWindow] && haven.window.get(targetWindow) && (haven.window.append(outputBuffer[targetWindow], targetWindow), outputBuffer[targetWindow] = "", 0 === targetWindow && (haven.isTextPrinted = !0))
}, buffer.newline = function(targetWindow) {
outputBuffer[targetWindow] ? outputBuffer[targetWindow] += "\n" : outputBuffer[targetWindow] = "\n", haven.buffer.flush(targetWindow)
}, haven.buffer = buffer
}(),
function() {
"use strict";
function fnv32(a) {
for (var len = a.length, fnv = 0, i = 0; i < len; i++) fnv = fnv + ((fnv << 1) + (fnv << 4) + (fnv << 7) + (fnv << 8) + (fnv << 24) >>> 0) ^ 255 & a[i];
return fnv >>> 0
}
function writeGamefile(done) {
interpreterLoaded && isGamefileLoaded || (interpreterLoaded ? document.getElementById("loader-message").innerHTML = "Loading game file" : document.getElementById("loader-message").innerHTML = "Loading interpreter"), document.getElementById("loader-message").innerHTML = "Starting game", FS.writeFile(storyFilename, gamefile, {
encoding: "binary"
}), datadir = "/gamedata_" + checksum, FS.analyzePath(datadir).exists || FS.mkdir(datadir), FS.mount(IDBFS, {
root: "."
}, datadir), FS.analyzePath("gamedata").exists || FS.mkdir("gamedata"), FS.mount(IDBFS, {
root: "."
}, "gamedata"), FS.chdir("gamedata"), FS.syncfs(!0, function() {
haven.options.get("autosave") && (haven.state.autosave.setName("/gamedata_" + checksum + "/autosave"), haven.state.autosave.restore()), haven.input.keypress.init(), done()
})
}
var gamefile, checksum, datadir, storyFilename, file = {},
interpreterLoaded = !1,
isGamefileLoaded = !1;
file.init = function(virtualFilename) {
var requestUrl, useProxy, gameUrl = haven.options.get("story"),
proxyOption = haven.options.get("use_proxy");
storyFilename = virtualFilename, gameUrl || haven.error("No story file specified");
var xmlhttp = new XMLHttpRequest;
switch ("" + proxyOption) {
case "always":
case "true":
case "1":
useProxy = !0;
break;
case "never":
case "false":
case "0":
useProxy = !1;
break;
default:
useProxy = /^https?:\/\//.test(gameUrl) && 0 !== gameUrl.indexOf(window.location.protocol + "//" + window.location.host), "auto" !== proxyOption && console.warn('Unknown use_proxy option "' + proxyOption + '", using "auto"')
}
requestUrl = useProxy ? haven.options.get("proxy_url").split("%s").join(encodeURIComponent(gameUrl)) : gameUrl, haven.assets.addCallback(writeGamefile), xmlhttp.responseType = "arraybuffer", xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) switch (xmlhttp.status) {
case 200:
isGamefileLoaded = !0, gamefile = new Uint8Array(xmlhttp.response), checksum = fnv32(gamefile).toString(16), haven.assets.finished("storyfile");
break;
case 404:
haven.error("Game file not found");
break;
case 415:
useProxy ? haven.error(String.fromCharCode.apply(null, new Uint8Array(xmlhttp.response))) : haven.error("Unsupported Media Type error encountered when loading game file");
break;
case 0:
haven.error("Unspecified error loading game file (possibly cross-origin restriction)");
break;
default:
haven.error("Error loading game file. Server returned status code " + xmlhttp.status + " (" + xmlhttp.statusText + ")")
}
}, xmlhttp.open("GET", requestUrl, !0), xmlhttp.send()
}, file.prompt = function(why) {
var filename = prompt("Enter filename " + why);
filename && /\S/.test(filename) ? haven.prompt.input.value = datadir + "/" + filename.split("/").join("-") : haven.prompt.input.value = "", setTimeout(function() {
haven.prompt.form.dispatchEvent(new Event("submit")), setTimeout(function() {
FS.syncfs(!1, function() {})
}, 1e3)
}, 1)
}, file.readUIState = function() {
try {
var state = FS.readFile(autosaveFilename + "_haven_uidata", {
encoding: "utf8"
});
return JSON.parse(state)
} catch (e) {
return null
}
}, file.syncfs = function() {
FS.syncfs(!1, function() {})
}, window.onbeforeunload = function() {
FS.syncfs(!1, function() {})
}, document.getElementById("loader-message").innerHTML = "Loading interpreter and game file", haven.file = file
}(),
function() {
var input = {},
inputMode = null,
keypressBuffer = [];
input.getMode = function() {
return inputMode
}, input.init = function() {
document.addEventListener("keydown", input.keypress.send, !1), document.addEventListener("click", input.keypress.send, !1)
}, input.keypress = {
init: function() {
inputMode || (inputMode = "buffer")
},
isWaiting: function() {
return haven.buffer.flush(), haven.isTextPrinted && haven.prompt.scrollOrFocus(), keypressBuffer.length > 0
},
send: function(e) {
var keyCode = e.keyCode,
doc = document.documentElement,
scrolltop = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
if (!(e.altKey || e.ctrlKey || e.metaKey || e.shiftKey)) {
switch (inputMode) {
case "buffer":
keypressBuffer.push(keyCode);
break;
case "getline":
case null:
return void haven.prompt.scrollOrFocus(e);
case "getkey":
break;
case "endgame":
return void(window.location = hugojs_options.exit_url);
default:
haven.error("Interpreter error: unknown input mode " + inputMode)
}
return inputMode = "buffer", scrolltop + window.innerHeight < document.body.clientHeight - 40 ? void haven.prompt.scrollOrFocus(e) : void Module.ccall("haven_getkey", "null", ["number"], [keyCode])
}
},
wait: function() {
inputMode = "getkey", haven.buffer.flush(), haven.prompt.setDoScroll(), keypressBuffer.length > 0 && input.keypress.send({
keyCode: keypressBuffer.shift()
})
}
}, input.setMode = function(mode) {
inputMode = mode
}, haven.input = input
}(),
function() {
"use strict";
var loader = {};
loader.remove = function() {
var loaderOverlay = document.getElementById("loader");
loaderOverlay && loaderOverlay.parentNode.removeChild(loaderOverlay)
}, haven.loader = loader
}(),
function() {
function getParameter(name, type, defaultValue) {
var value, valueSearch = new RegExp("[?&]" + name + "=(.*?)(#|&|$)", "i").exec(window.location.href);
if (null === valueSearch || valueSearch.length < 2) return defaultValue;
switch (value = decodeURIComponent(valueSearch[1].split("+").join(" ")), type) {
case "boolean":
return "true" === value.toLowerCase() || "on" === value || "1" === value || "false" !== value.toLowerCase() && "off" !== value && "0" !== value && defaultValue;
case "number":
return parseFloat(value) + "" === value ? parseFloat(value) : NaN;
default:
return 0 === value.length ? defaultValue : value
}
}
var options = {},
opt = {
autosave: !0,
exit_url: "",
extra_opcodes: !0,
proxy_url: "proxy.php",
use_proxy: "auto",
windowing: !0
};
options.get = function(name) {
return opt[name]
}, options.init = function(defaults) {
var option_key;
defaults = defaults || {};
for (option_key in defaults) defaults.hasOwnProperty(option_key) && void 0 !== defaults[option_key] && (opt[option_key] = defaults[option_key]);
if (opt.lock_story || (opt.story = getParameter("story", "string", opt.story)), !opt.lock_options) {
for (option_key in opt) "story" !== option_key && opt.hasOwnProperty(option_key) && (opt[option_key] = getParameter(option_key, typeof opt[option_key], opt[option_key]));
"false" !== opt.exit_url && "0" !== opt.exit_url || (opt.exit_url = !1)
}
}, options.set = function(name, value) {
opt[name] = value
}, haven.options = options
}(),
function() {
"use strict";
function appendPrompt(caret, inputText, targetContainer) {
for (var target = haven.window.container.get(targetContainer), lastLineinput = document.createElement("div"), lastPrefix = document.createElement("span"), lastCommand = document.createElement("span"), previousLastPrompt = document.getElementsByClassName("lineinput last"), i = previousLastPrompt.length - 1; i >= 0; --i) previousLastPrompt[i].classList.remove("last");
lastLineinput.className = "lineinput last", lastPrefix.className = "prompt-prefix", lastCommand.className = "prompt-input", lastPrefix.innerHTML = caret, lastCommand.innerHTML = inputText, lastLineinput.appendChild(lastPrefix), lastLineinput.appendChild(lastCommand), target.appendChild(lastLineinput)
}
function getCmdFromHistory(delta) {
var current = currentCmdHistory,
new_current = current + delta;
current === -1 && (currentCmdText = inputElem.value), new_current < cmdHistory.length && new_current >= 0 ? (inputElem.value = cmdHistory[new_current], currentCmdHistory = new_current) : new_current === -1 && (inputElem.value = currentCmdText, currentCmdHistory = new_current)
}
function resizeInput() {
inputElem.style.width = haven.window.get(0).clientWidth - inputX - 2 + "px"
}
function scrollToContent() {
for (var newScrollTop, output = haven.window.get(0), statusline = haven.window.get(1), nodes = textNodesUnder(output), scrolltop = (window.pageYOffset || document.documentElement.scrollTop) - (document.documentElement.clientTop || 0), nonWhitespaceRegex = /\S/, i = 0; i < nodes.length; ++i)
if (nonWhitespaceRegex.test(nodes[i].textContent)) return newScrollTop = nodes[i].parentNode.getBoundingClientRect().top - window.innerHeight / 3, statusline && (newScrollTop += statusline.getBoundingClientRect().height), void(scrolltop < newScrollTop && window.scrollTo(0, newScrollTop))
}
function textNodesUnder(node) {
var all = [];
for (node = node.firstChild; node; node = node.nextSibling) 3 == node.nodeType ? all.push(node) : all = all.concat(textNodesUnder(node));
return all
}
var prompt = {},
cmdHistory = [],
currentCmdHistory = -1,
currentCmdText = "",
doScroll = !1,
enginePrompt = !1,
inputElem = document.getElementById("lineinput-field"),
inputX = 0,
isTextPrinted = !1,
prefixElem = document.getElementById("lineinput-prefix"),
promptElem = document.getElementById("lineinput"),
lineinputReadyEvent = new CustomEvent("lineinputReady");
prompt.get = function() {
return promptElem
}, prompt.hide = function() {
haven.input.setMode("buffer"), promptElem.parentNode && promptElem.parentNode.removeChild(promptElem)
}, prompt.history = {
add: function(cmd) {
return !!cmd && (cmdHistory.push(cmd), !0)
},
clear: function() {
cmdHistory = []
},
get: function() {
return cmdHistory.slice()
},
remove: function(index) {
return 0 !== cmdHistory.length && ("number" != typeof index ? (cmdHistory.pop(), !0) : !(index < 0 || index >= cmdHistory.length) && void cmdHistory.splice(index, 1))
},
set: function(newHistory) {
cmdHistory = newHistory.slice()
}
};
for (var defaultDiacriticsRemovalMap = [{
base: "A",
letters: "AⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ"
}, {
base: "AA",
letters: "Ꜳ"
}, {
base: "AE",
letters: "ÆǼǢ"
}, {
base: "AO",
letters: "Ꜵ"
}, {
base: "AU",
letters: "Ꜷ"
}, {
base: "AV",
letters: "ꜸꜺ"
}, {
base: "AY",
letters: "Ꜽ"
}, {
base: "B",
letters: "BⒷBḂḄḆɃƂƁ"
}, {
base: "C",
letters: "CⒸCĆĈĊČÇḈƇȻꜾ"
}, {
base: "D",
letters: "DⒹDḊĎḌḐḒḎĐƋƊƉꝹ"
}, {
base: "DZ",
letters: "DZDŽ"
}, {
base: "Dz",
letters: "DzDž"
}, {
base: "E",
letters: "EⒺEÈÉÊỀẾỄỂẼĒḔḖĔĖËẺĚȄȆẸỆȨḜĘḘḚƐƎ"
}, {
base: "F",
letters: "FⒻFḞƑꝻ"
}, {
base: "G",
letters: "GⒼGǴĜḠĞĠǦĢǤƓꞠꝽꝾ"
}, {
base: "H",
letters: "HⒽHĤḢḦȞḤḨḪĦⱧⱵꞍ"
}, {
base: "I",
letters: "IⒾIÌÍÎĨĪĬİÏḮỈǏȈȊỊĮḬƗ"
}, {
base: "J",
letters: "JⒿJĴɈ"
}, {
base: "K",
letters: "KⓀKḰǨḲĶḴƘⱩꝀꝂꝄꞢ"
}, {
base: "L",
letters: "LⓁLĿĹĽḶḸĻḼḺŁȽⱢⱠꝈꝆꞀ"
}, {
base: "LJ",
letters: "LJ"
}, {
base: "Lj",
letters: "Lj"
}, {
base: "M",
letters: "MⓂMḾṀṂⱮƜ"
}, {
base: "N",
letters: "NⓃNǸŃÑṄŇṆŅṊṈȠƝꞐꞤ"
}, {
base: "NJ",
letters: "NJ"
}, {
base: "Nj",
letters: "Nj"
}, {
base: "O",
letters: "OⓄOÒÓÔỒỐỖỔÕṌȬṎŌṐṒŎȮȰÖȪỎŐǑȌȎƠỜỚỠỞỢỌỘǪǬØǾƆƟꝊꝌ"
}, {
base: "OI",
letters: "Ƣ"
}, {
base: "OO",
letters: "Ꝏ"
}, {
base: "OU",
letters: "Ȣ"
}, {
base: "OE",
letters: "Œ"
}, {
base: "oe",
letters: "œ"
}, {
base: "P",
letters: "PⓅPṔṖƤⱣꝐꝒꝔ"
}, {
base: "Q",
letters: "QⓆQꝖꝘɊ"
}, {
base: "R",
letters: "RⓇRŔṘŘȐȒṚṜŖṞɌⱤꝚꞦꞂ"
}, {
base: "S",
letters: "SⓈSẞŚṤŜṠŠṦṢṨȘŞⱾꞨꞄ"
}, {
base: "T",
letters: "TⓉTṪŤṬȚŢṰṮŦƬƮȾꞆ"
}, {
base: "TZ",
letters: "Ꜩ"
}, {
base: "U",
letters: "UⓊUÙÚÛŨṸŪṺŬÜǛǗǕǙỦŮŰǓȔȖƯỪỨỮỬỰỤṲŲṶṴɄ"
}, {
base: "V",
letters: "VⓋVṼṾƲꝞɅ"
}, {
base: "VY",
letters: "Ꝡ"
}, {
base: "W",
letters: "WⓌWẀẂŴẆẄẈⱲ"
}, {
base: "X",
letters: "XⓍXẊẌ"
}, {
base: "Y",
letters: "YⓎYỲÝŶỸȲẎŸỶỴƳɎỾ"
}, {
base: "Z",
letters: "ZⓏZŹẐŻŽẒẔƵȤⱿⱫꝢ"
}, {
base: "a",
letters: "aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐ"
}, {
base: "aa",
letters: "ꜳ"
}, {
base: "ae",
letters: "æǽǣ"
}, {
base: "ao",
letters: "ꜵ"
}, {
base: "au",
letters: "ꜷ"
}, {
base: "av",
letters: "ꜹꜻ"
}, {
base: "ay",
letters: "ꜽ"
}, {
base: "b",
letters: "bⓑbḃḅḇƀƃɓ"
}, {
base: "c",
letters: "cⓒcćĉċčçḉƈȼꜿↄ"
}, {
base: "d",
letters: "dⓓdḋďḍḑḓḏđƌɖɗꝺ"
}, {
base: "dz",
letters: "dzdž"
}, {
base: "e",
letters: "eⓔeèéêềếễểẽēḕḗĕėëẻěȅȇẹệȩḝęḙḛɇɛǝ"
}, {
base: "f",
letters: "fⓕfḟƒꝼ"
}, {
base: "g",
letters: "gⓖgǵĝḡğġǧģǥɠꞡᵹꝿ"
}, {
base: "h",
letters: "hⓗhĥḣḧȟḥḩḫẖħⱨⱶɥ"
}, {
base: "hv",
letters: "ƕ"
}, {
base: "i",
letters: "iⓘiìíîĩīĭïḯỉǐȉȋịįḭɨı"
}, {
base: "j",
letters: "jⓙjĵǰɉ"
}, {
base: "k",
letters: "kⓚkḱǩḳķḵƙⱪꝁꝃꝅꞣ"
}, {
base: "l",
letters: "lⓛlŀĺľḷḹļḽḻſłƚɫⱡꝉꞁꝇ"
}, {
base: "lj",
letters: "lj"
}, {
base: "m",
letters: "mⓜmḿṁṃɱɯ"
}, {
base: "n",
letters: "nⓝnǹńñṅňṇņṋṉƞɲʼnꞑꞥ"
}, {
base: "nj",
letters: "nj"
}, {
base: "o",
letters: "oⓞoòóôồốỗổõṍȭṏōṑṓŏȯȱöȫỏőǒȍȏơờớỡởợọộǫǭøǿɔꝋꝍɵ"
}, {
base: "oi",
letters: "ƣ"
}, {
base: "ou",
letters: "ȣ"
}, {
base: "oo",
letters: "ꝏ"
}, {
base: "p",
letters: "pⓟpṕṗƥᵽꝑꝓꝕ"
}, {
base: "q",
letters: "qⓠqɋꝗꝙ"
}, {
base: "r",
letters: "rⓡrŕṙřȑȓṛṝŗṟɍɽꝛꞧꞃ"
}, {
base: "s",
letters: "sⓢsßśṥŝṡšṧṣṩșşȿꞩꞅẛ"
}, {
base: "t",
letters: "tⓣtṫẗťṭțţṱṯŧƭʈⱦꞇ"
}, {
base: "tz",
letters: "ꜩ"
}, {
base: "u",
letters: "uⓤuùúûũṹūṻŭüǜǘǖǚủůűǔȕȗưừứữửựụṳųṷṵʉ"
}, {
base: "v",
letters: "vⓥvṽṿʋꝟʌ"
}, {
base: "vy",
letters: "ꝡ"
}, {
base: "w",
letters: "wⓦwẁẃŵẇẅẘẉⱳ"
}, {
base: "x",
letters: "xⓧxẋẍ"
}, {
base: "y",
letters: "yⓨyỳýŷỹȳẏÿỷẙỵƴɏỿ"
}, {
base: "z",
letters: "zⓩzźẑżžẓẕƶȥɀⱬꝣ"
}], diacriticsMap = {}, i = 0; i < defaultDiacriticsRemovalMap.length; i++)
for (var letters = defaultDiacriticsRemovalMap[i].letters, j = 0; j < letters.length; j++) diacriticsMap[letters[j]] = defaultDiacriticsRemovalMap[i].base;
prompt.init = function(opt) {
if (enginePrompt = !!opt.enginePrompt, promptElem.addEventListener("submit", function(e) {
e.preventDefault(), opt.unicode || (inputElem.value = inputElem.value.replace(/[^\u0000-\u007E]/g, function(a) {
return diacriticsMap[a] || a
})), inputElem.value !== cmdHistory[0] && /\S/.test(inputElem.value) && cmdHistory.unshift(inputElem.value), currentCmdHistory = -1, enginePrompt || e.detail && e.detail.silent || appendPrompt(prompt.prefix.get(), inputElem.value, 0), Module.ccall("haven_getline", "null", ["string"], [inputElem.value + "\n"]), inputElem.value = "", prompt.hide()
}, !1), inputElem.addEventListener("keydown", function(e) {
var keyCode = e.which || e.keyCode;
38 === keyCode && (getCmdFromHistory(1), e.preventDefault()), 40 === keyCode && (getCmdFromHistory(-1), e.preventDefault())
}, !1), "ontouchstart" in window) {
var firstFocus = !0;
inputElem.addEventListener("focus", function() {
firstFocus ? firstFocus = !1 : document.body.classList.add("safarifix")
}), inputElem.addEventListener("blur", function() {
document.body.classList.remove("safarifix")
})
}
window.addEventListener("resize", resizeInput, !1), promptElem.parentNode.removeChild(promptElem)
}, prompt.isReady = function() {
return "getline" === haven.input.getMode()
}, prompt.prefix = {
get: function() {
return enginePrompt ? "" : prefixElem.innerHTML
},
set: function(prefix) {
enginePrompt || (prefixElem.innerHTML = prefix)
}
}, prompt.resizeInput = resizeInput, prompt.scrollOrFocus = function(e) {
var doc = document.documentElement,
scrolltop = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0),
selection = window.getSelection || function() {
return document.selection ? document.selection.createRange().text : ""
},
playAreaHeight = window.innerHeight;
if (haven.window.get(1) && (playAreaHeight = window.innerHeight - haven.window.get(1).getBoundingClientRect().height), !e || !(32 === e.keycode || e.keyCode > 127 || e.altKey || e.ctrlKey || e.metaKey)) {
if (!e || e.target && "INPUT" !== e.target.nodeName && "" === selection().toString())
if (scrolltop + window.innerHeight > document.body.clientHeight - 40) promptElem.parentNode && (window.scrollTo(0, 9e9), inputElem.focus(), e && e.stopPropagation && document.activeElement !== inputElem && e.stopPropagation());
else if (doScroll ? (window.scrollTo(0, scrolltop + playAreaHeight - 40), promptElem.parentNode && scrolltop + playAreaHeight + window.innerHeight - 40 >= document.body.clientHeight && inputElem.focus(), e && e.preventDefault && e.preventDefault()) : scrollToContent(), e && "keydown" === e.type && 8 === (e.which || e.keyCode)) return !1;
isTextPrinted = !1
}
}, prompt.setDoScroll = function(status) {
doScroll = status
}, prompt.show = function() {
haven.input.setMode("getline"), haven.buffer.flush(), haven.window.get(0).appendChild(promptElem), inputX = enginePrompt ? inputElem.offsetLeft - haven.window.get(0).offsetLeft : prefixElem.offsetWidth, resizeInput(), prompt.scrollOrFocus(), doScroll = !0, haven.state.autosave.save(), promptElem.dispatchEvent(lineinputReadyEvent)
}, haven.prompt = prompt
}(),
function() {
"use strict";
var state = {},
autosaveFilename = "",
readUIState = function() {
try {
var state = FS.readFile(autosaveFilename + "_uidata", {
encoding: "utf8"
});
return JSON.parse(state)
} catch (e) {
return null
}
};
state.autosave = {
remove: function() {
try {
FS.unlink(autosaveFilename)
} catch (e) {}
},
restore: function() {
try {
FS.stat(autosaveFilename), Module.ccall("hugojs_set_autosave_filename", "null", ["string"], [autosaveFilename])
} catch (e) {}
},
save: function() {
haven.options.get("autosave") && (FS.writeFile(autosaveFilename + "_uidata", JSON.stringify(haven.window.getUIState()), {
encoding: "utf8"
}), Module.ccall("haven_save_autosave", "int", ["string"], [autosaveFilename]))
},
setName: function(filename) {
autosaveFilename = filename
}
}, state.restoreUI = function() {
var windowCount, i, savedState = readUIState();
if (savedState) {
for (windowCount = haven.options.get("windowing") ? savedState.windowContents.length : 1, haven.window.clear(), i = 0; i < windowCount; ++i) haven.window.create(i, savedState.windowDimensions[i].left, savedState.windowDimensions[i].top, savedState.windowDimensions[i].right, savedState.windowDimensions[i].bottom);
for (haven.style.color.restore(savedState.currentColors), haven.style.restore(savedState.font), haven.window.position.restore(savedState.position), savedState.title && (document.title = savedState.title), i = 0; i < savedState.windowContents.length; ++i) haven.window.get(i).innerHTML = savedState.windowContents[i], haven.style.apply(haven.window.get(i), i);
haven.style.apply(document.body, 0), Module.ccall("hugojs_set_font", "null", ["int"], [savedState.font[0].original]), Module.ccall("hugojs_set_colors", "null", ["int", "int"], [savedState.currentColors[0].text, savedState.currentColors[0].background]), haven.prompt.history.set(savedState.cmdHistory || []), window.scrollTo(0, 9e9), haven.prompt.setDoScroll()
}
}, window.haven.state = state
}(),
function() {
"use strict";
function defaultColors(targetWindow) {
return 1 === targetWindow ? {
text: 15,
background: 1
} : {
text: 7,
background: 0
}
}
function defaultStyles() {
return {
bold: !1,
italic: !1,
underline: !1,
proportional: !0,
original: 0
}
}
var style = {},
currentColors = [defaultColors(0)],
font = [defaultStyles()],
ignoreFontFamily = !1;
style.apply = function(elem, targetWindow) {
var newClasses = [],
prompt = haven.prompt.get().getElementsByTagName("INPUT")[0],
setPromptStyle = 0 === targetWindow;
currentColors[targetWindow] || (currentColors[targetWindow] = defaultColors(targetWindow)), haven.options.get("engineColors") && (newClasses.push("textcolor-" + currentColors[targetWindow].text), newClasses.push("bgcolor-" + currentColors[targetWindow].background)), elem.className = elem.className.replace(/\b(text|bg)color-\d+/g, ""), elem.classList.remove("font-fixed-width"), setPromptStyle && (prompt.className = prompt.className.replace(/\b(text|bg)color-\d+/g, ""), prompt.classList.remove("font-fixed-width")), font[targetWindow] || (font[targetWindow] = defaultStyles());
for (var prop in font[targetWindow]) ignoreFontFamily && "proportional" === prop || font[targetWindow].hasOwnProperty(prop) && (elem.classList.remove("font-" + prop), setPromptStyle && prompt.classList.remove("font-" + prop), font[targetWindow][prop] && newClasses.push("font-" + prop));
ignoreFontFamily || !font[targetWindow].hasOwnProperty("proportional") || font[targetWindow].proportional || newClasses.push("font-fixed-width");
for (var i = 0; i < newClasses.length; ++i) elem.classList.add(newClasses[i]), setPromptStyle && prompt.classList.add(newClasses[i])
}, style.color = {
get: function() {
return currentColors
},
restore: function(oldState) {
currentColors = oldState
},
set: function(which, color, targetWindow) {
currentColors[targetWindow] || (currentColors[targetWindow] = defaultColors(targetWindow)), currentColors[targetWindow][which] !== color && (haven.buffer.flush(targetWindow), currentColors[targetWindow][which] = color)
}
}, style.font = {
get: function() {
return font
}
}, style.init = function(options) {
ignoreFontFamily = !options.engineFontFamily
}, style.restore = function(oldState) {
font = oldState;
}, style.set = function(type, value, targetWindow) {
haven.buffer.flush(targetWindow), font[targetWindow][type] = value
}, haven.style = style
}(),
function() {
"use strict";
function createLines(amount, column, havenWindow) {
for (var i = 0; i < amount; ++i) {
var newlineFiller = document.createElement("span");
newlineFiller.className = "font-fixed-width", newlineFiller.innerHTML = "\n", outputWindows[havenWindow].appendChild(newlineFiller)
}
if (column > 0) {
var spaceFiller = document.createElement("span");
spaceFiller.innerHTML = Array(column).join(" "), spaceFiller.className = "font-fixed-width", outputWindows[havenWindow].appendChild(spaceFiller)
}
win.position.reset(havenWindow)
}
function replacePart(line, col, newContent, havenWindow) {
var textContent, output = outputWindows[havenWindow],
nodes = textNodesUnder(output),
range = document.createRange(),
currentLine = 1,
currentCol = 1,
startFound = !1,
endCounter = 0,
overflow = function() {
for (var i = 0; i < nodes.length; ++i)
if (textContent = nodes[i].textContent, currentLine === line)
for (var j = 0; j < textContent.length; ++j) {
if (startFound) {
if (endCounter++, endCounter === newContent.textContent.length || "\n" === textContent[j]) return range.setEnd(nodes[i], j), !1
} else if (currentCol === col) {
if (range.setStart(nodes[i], j), startFound = !0, j === textContent.length - 1) return range.setEnd(nodes[i], j), !1
} else if ("\n" === textContent[j]) {
var filler = document.createTextNode(Array(col - currentCol + 1).join(" ") + "\n");
return nodes[i].textContent = textContent.substr(0, j) + " ", nodes[i].parentNode.insertBefore(filler, nodes[i].nextSibling), range.setStart(filler, col - currentCol - 1), range.setEnd(filler, col - currentCol - 1), !1
}
currentCol++
} else textContent.indexOf("\n") > -1 && currentLine++;
return !0
}();
return overflow ? (createLines(position[havenWindow].line - currentLine, col, havenWindow), void output.appendChild(newContent)) : (newContent.textContent.indexOf("\n") > -1 ? (newContent.textContent = newContent.textContent.replace("\n", ""), position[havenWindow].line++, position[havenWindow].col = 1) : position[havenWindow].col += newContent.textContent.length, range.deleteContents(), range.insertNode(newContent), void(newContent.nextSibling || (position[havenWindow].line = null, position[havenWindow].col = null)))
}
function textNodesUnder(node) {
var all = [];
for (node = node.firstChild; node; node = node.nextSibling) 3 == node.nodeType ? all.push(node) : all = all.concat(textNodesUnder(node));
return all
}
var win = {},
outputWindows = [document.getElementById("window0")],
mainContainer = document.getElementById("output"),
currentContainers = [outputWindows[0]],
position = [],
windowDimensions = [];
win.append = function(content, targetWindow) {
var textContainer = document.createElement("span");
position[targetWindow] || (position[targetWindow] = {
col: null,
line: null
}), haven.style.apply(textContainer, targetWindow), textContainer.innerHTML = content, null !== position[targetWindow].col && null !== position[targetWindow].line ? replacePart(position[targetWindow].line, position[targetWindow].col, textContainer, targetWindow) : currentContainers[targetWindow].appendChild(textContainer)
}, win.clear = function(targetWindow) {
if (void 0 === targetWindow) haven.buffer.flush(0), mainContainer.innerHTML = "", mainContainer.appendChild(outputWindows[0]), haven.style.apply(outputWindows[0], 0), haven.style.apply(document.body, 0), win.position.reset();
else {
if (!outputWindows[targetWindow]) return;
haven.buffer.flush(targetWindow), outputWindows[targetWindow].innerHTML = "", haven.style.apply(outputWindows[targetWindow], targetWindow), 0 === targetWindow && haven.style.apply(document.body, 0), win.position.reset(targetWindow)
}
}, win.create = function(outputWindow, left, top, right, bottom) {
var newWindow, dimensions = win.measureDimensions(),
charHeight = dimensions.char.height,
mainContainer = haven.window.get(0).parentNode;
return windowDimensions[outputWindow] = {
left: left,
top: top,
right: right,
bottom: bottom
}, !!haven.options.get("windowing") && (0 === outputWindow ? void(haven.window.get(0).style.paddingTop = (top - 1) * dimensions.char.height + "px") : (haven.window.get(outputWindow) && mainContainer.removeChild(haven.window.get(outputWindow)), newWindow = document.createElement("div"), newWindow.id = "window" + outputWindow, newWindow.className = "havenwindow font-fixed-width", newWindow.style.height = charHeight * (bottom - top + 1) + "px", newWindow.style.top = (top - 1) * charHeight + "px", newWindow.style.marginLeft = left - 1 + "px", newWindow.style.width = (right - left + 2) * dimensions.char.width + "px", outputWindows[outputWindow] = newWindow, currentContainers[outputWindow] = newWindow, void haven.window.container.append(newWindow, mainContainer)))
}, win.container = {
append: function(container, target) {
"number" == typeof target ? outputWindows[target].appendChild(container) : target.appendChild(container)
},
get: function(targetWindow) {
return currentContainers[targetWindow]
},
set: function(newContainer, targetWindow) {
currentContainers[targetWindow] = newContainer
}
}, win.get = function(targetWindow) {
return outputWindows[targetWindow]
}, win.getUIState = function() {
var lastChild, windowContents = [],
promptElem = haven.prompt.get(),
promptParent = promptElem.parentNode;
promptParent && promptParent.removeChild(promptElem), lastChild = outputWindows[0].lastChild, outputWindows[0].removeChild(lastChild);
for (var i = 0; i < outputWindows.length; ++i) windowContents[i] = outputWindows[i].innerHTML;
outputWindows[0].appendChild(lastChild), promptParent && promptParent.appendChild(promptElem);
var lastLbr = windowContents[0].lastIndexOf("\n");
return windowContents[0] = windowContents[0].substring(0, lastLbr) + windowContents[0].substring(lastLbr + 1), {
cmdHistory: haven.prompt.history.get(),
currentColors: haven.style.color.get(),
font: haven.style.font.get(),
position: position,
title: document.title,
windowDimensions: windowDimensions,
windowContents: windowContents
}
}, win.measureDimensions = function() {
var measureElemHeight, outputContainer = haven.window.get(0).parentNode,
dimensions = {
window: {
width: parseInt(window.getComputedStyle(outputContainer).width, 10),
height: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
},
line: {},
char: {}
},
measureElem = document.createElement("span"),
outputDimensions = dimensions.window;
return measureElem.innerHTML = "00000
00000
00000", measureElem.className = "font-fixed-width", measureElem.style.display = "inline-block", outputContainer.appendChild(measureElem), dimensions.char.width = measureElem.offsetWidth / 5, dimensions.line.width = Math.floor(outputDimensions.width / dimensions.char.width - 1), measureElem.style.display = "block", measureElemHeight = measureElem.clientHeight, measureElem.innerHTML += "
00000
00000", dimensions.char.height = (measureElem.clientHeight - measureElemHeight) / 2, dimensions.line.height = Math.floor(outputDimensions.height / dimensions.char.height), measureElem.parentNode.removeChild(measureElem), dimensions
}, win.position = {
reset: function(targetWindow) {
void 0 === targetWindow ? position = {
col: null,
line: null
} : win.position.set(null, null, targetWindow)
},
restore: function(oldState) {
position = oldState
},
set: function(col, line, havenWindow) {
position[havenWindow] || (position[havenWindow] = {}), position[havenWindow].col = col, position[havenWindow].line = line
}
}, win.setTitle = function(title) {
document.title = title
}, haven.window = win
}(), window.Module = {
arguments: [],
preRun: [],
postRun: [function() {
haven.assets.finished("engine")
}],
print: function(text) {
haven.error("Unexpected engine output to stdout: " + text)
},
printErr: function() {
console.log(arguments), haven.error(Array.prototype.slice.call(arguments).join(" "))
},
TOTAL_MEMORY: 33554432
};