From df7bb265c9e126ed800d3ea6fde80a0f6b22cc12 Mon Sep 17 00:00:00 2001 From: joshunrau Date: Wed, 26 Aug 2026 10:45:58 -0400 Subject: [PATCH] add TMB_DIGIT_SYMBOL_CODING A nine-item "Coding" variant of the digit-symbol task, requested by Dr. Anne Almey so that data is comparable with the older version BHOP already uses. Built as a standalone instrument on the current TestMyBrain runtime, adapted from TMB_DIGIT_SYMBOL_MATCHING. Differences from the six-item Matching task: - Nine symbols in a single-row key, each over its digit, rather than a 2x3 grid whose digit row doubles as the response buttons. The key is built from spans, not divs, because showFrame() hides every div in the document and a div-based key would be invisible on the instruction screens. - The chosen digit is shown under the key for 500 ms and the next symbol follows immediately, replacing the red highlight box. Setting tmbUI.highlight to '' removes both the box and the 250 ms delay TestHelper otherwise imposes between response and next stimulus. - Response buttons are shown only when responding by touch; on a keyboard the screen is just the probe and the key, as in the source material. The symbols are TMB's existing _1 through _9, which match the nine images Anne supplied, in the same order. The existing digit rule already yields 1,2,3,1,2,3,1,2,3 across them. Test duration, practice trials, seeding and all outcome variables are inherited from the Matching task, and the submitted payload has the same shape, so the two are directly comparable. testVersion is set explicitly rather than derived from window.location.pathname, which is meaningless inside an ODC iframe. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01VieAnND225JubARffM5g6Y --- .../TestHelper.v1.Oct23.js | 913 ++++ .../TestMyBrain.12.18.min.js | 4129 +++++++++++++++++ .../TMB_DIGIT_SYMBOL_CODING/_1.webp | Bin 0 -> 800 bytes .../TMB_DIGIT_SYMBOL_CODING/_2.webp | Bin 0 -> 1238 bytes .../TMB_DIGIT_SYMBOL_CODING/_3.webp | Bin 0 -> 548 bytes .../TMB_DIGIT_SYMBOL_CODING/_4.webp | Bin 0 -> 882 bytes .../TMB_DIGIT_SYMBOL_CODING/_5.webp | Bin 0 -> 1072 bytes .../TMB_DIGIT_SYMBOL_CODING/_6.webp | Bin 0 -> 304 bytes .../TMB_DIGIT_SYMBOL_CODING/_7.webp | Bin 0 -> 1310 bytes .../TMB_DIGIT_SYMBOL_CODING/_8.webp | Bin 0 -> 1084 bytes .../TMB_DIGIT_SYMBOL_CODING/_9.webp | Bin 0 -> 1144 bytes .../TMB_DIGIT_SYMBOL_CODING/_resp1.webp | Bin 0 -> 254 bytes .../TMB_DIGIT_SYMBOL_CODING/_resp2.webp | Bin 0 -> 802 bytes .../TMB_DIGIT_SYMBOL_CODING/_resp3.webp | Bin 0 -> 902 bytes .../chooseInput.v1.Feb24.js | 265 ++ .../TMB_DIGIT_SYMBOL_CODING/fragment.html | 14 + .../TMB_DIGIT_SYMBOL_CODING/index.ts | 90 + .../TMB_DIGIT_SYMBOL_CODING/render.d.ts | 1 + .../TMB_DIGIT_SYMBOL_CODING/render.js | 594 +++ .../TMB_DIGIT_SYMBOL_CODING/styles.css | 138 + .../TMB_DIGIT_SYMBOL_CODING/translator.ts | 110 + 21 files changed, 6254 insertions(+) create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/TestHelper.v1.Oct23.js create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/TestMyBrain.12.18.min.js create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/_1.webp create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/_2.webp create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/_3.webp create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/_4.webp create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/_5.webp create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/_6.webp create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/_7.webp create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/_8.webp create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/_9.webp create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/_resp1.webp create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/_resp2.webp create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/_resp3.webp create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/chooseInput.v1.Feb24.js create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/fragment.html create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/index.ts create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/render.d.ts create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/render.js create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/styles.css create mode 100644 lib/interactive/TMB_DIGIT_SYMBOL_CODING/translator.ts diff --git a/lib/interactive/TMB_DIGIT_SYMBOL_CODING/TestHelper.v1.Oct23.js b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/TestHelper.v1.Oct23.js new file mode 100644 index 0000000..59dc5dc --- /dev/null +++ b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/TestHelper.v1.Oct23.js @@ -0,0 +1,913 @@ +/* eslint-disable */ + +/* + + Copyright 2023 The Many Brains Project, Inc. and McLean Hospital. + + This code is made available under a GNU Lesser General Public License 3.0 + (LGPLv3). + https://www.gnu.org/licenses/lgpl-3.0.html. + + Author: Paolo Martini, Roger Strong + Last updated: 10.19.2023 + Version: TestHelper.v1.Oct23 + + */ + +function debounce(func, wait, immediate) { + /* + Returns a function, that, as long as it continues to be invoked, + will not be triggered. The function will be called after it stops + being invoked for `wait` milliseconds. If `immediate` is passed, + the function is triggered on the leading edge, instead of the trailing. + + Usage: + + var resizeHandler = debounce(function() { your code here }, 100); + window.addEventListener('resize', resizeHandler); + + N.B. The event is passed to the returned function as arguments[0] + */ + + var timeout; + return function () { + var context = this, + args = arguments; + var later = function () { + timeout = null; + if (!immediate) { + func.apply(context, args); + } + }; + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) { + func.apply(context, args); + } + }; +} + +function disableSelect() { + var s = document.body.style; + + if (typeof s.webkitUserSelect !== 'undefined') s.webkitUserSelect = 'none'; + else if (typeof s.MozUserSelect !== 'undefined') s.MozUserSelect = 'none'; + else if (typeof s.msUserSelect !== 'undefined') s.msUserSelect = 'none'; + else if (typeof s.oUserSelect !== 'undefined') s.oUserSelect = 'none'; + else if (typeof s.userSelect !== 'undefined') s.userSelect = 'none'; + else if (typeof document.onselectstart !== 'undefined') + document.onselectstart = function () { + return false; + }; + + // disable 'save image' popup on iPhone + if (s.webkitTouchCallout !== undefined) s.webkitTouchCallout = 'none'; +} + +tmbUI.getInput = function () { + var i, + timeStamp = now(), + downDebounce = false, + upDebounce = true, + highlightEl, + errorMessage = '', + validUpEventTypes = []; + + // parse the tmbUI object + for (var key in tmbUI) { + // filter out prototype properties + if (tmbUI.hasOwnProperty(key)) { + switch (key) { + // keys, clicks or taps + case 'UIevents': + // must specify input events + if (tmbUI.UIevents.length === 0) { + errorMessage += 'Must specify UIevents: ' + "'keys', 'clicks' or 'taps'. "; + } + // accept single argument not as array + if (!(tmbUI.UIevents instanceof Array)) { + tmbUI.UIevents = [tmbUI.UIevents]; + } + // veto invalid events + for (i = 0; i < tmbUI.UIevents.length; i++) { + if (!['keys', 'clicks', 'taps'].includes(tmbUI.UIevents[i])) { + errorMessage += "'" + tmbUI.UIevents[i] + "' is not a valid event. "; + } + } + // are touch events available? + if (tmbUI.UIevents.includes('taps') && !hasTouch && !hasPointer) { + errorMessage += "'taps' is not a valid event. "; + } + break; + // valid keyboard keys + case 'UIkeys': + // accept single argument not as array + if (!(tmbUI.UIkeys instanceof Array)) { + tmbUI.UIkeys = [tmbUI.UIkeys]; + } + // keys must be valid keycodes + for (i = 0; i < tmbUI.UIkeys.length; i++) { + if (!keyboardCodes[tmbUI.UIkeys[i]]) { + errorMessage += "'" + tmbUI.UIkeys[i] + "' is not a valid keyboard code. "; + } + } + break; + // ids of elements to attach listeners to, + // or corresponding to keys + case 'UIelements': + // accept single argument not as array + if (!(tmbUI.UIelements instanceof Array)) { + tmbUI.UIelements = [tmbUI.UIelements]; + } + // must be DOM elements + for (i = 0; i < tmbUI.UIelements.length; i++) { + if (!getID(tmbUI.UIelements[i])) { + errorMessage += "'" + tmbUI.UIelements[i] + "' is not a valid element. "; + } + } + break; + // listening timeout in ms + case 'timeout': + // minimum timeout is 150 ms + if (tmbUI.timeout < 150) errorMessage += 'Timeout is ' + tmbUI.timeout + ' ms, ' + 'must be > 150 ms. '; + break; + // function has not raised readyUI event yet + case 'timeoutRef': + // called this function while still processing + if (tmbUI.timeoutRef !== 0) { + tmbUI.message += "'getInput' called again while " + 'still busy. '; + return false; + } + break; + // do we want to highlight the element + // the user responds to? + case 'highlight': + // must be empty string or valid css class + if (tmbUI.highlight !== '') { + var found = [].slice.call(document.styleSheets).some(function (sheet) { + return [].slice.call(sheet.cssRules).some(function (rule) { + return rule.selectorText === '.' + tmbUI.highlight; + }); + }); + if (!found) { + errorMessage += "'highlight' must be " + 'empty string or valid CSS class. '; + } + } + break; + case 'onreadyUI': + break; + case 'getInput': + break; + case 'status': + tmbUI.status = ''; + break; + case 'message': + tmbUI.message = ''; + break; + case 'response': + tmbUI.response = ''; + break; + case 'downTimestamp': + tmbUI.downTimestamp = 0; + break; + case 'rt': + tmbUI.rt = 0; + break; + case 'upTimestamp': + tmbUI.upTimestamp = 0; + break; + case 'dwell': + tmbUI.dwell = 0; + break; + default: + errorMessage += "Invalid parameter '" + key + "'. "; + } + } + } + + // need event "keys" for valid keys + if (tmbUI.UIkeys.length > 0 && !tmbUI.UIevents.includes('keys')) + errorMessage += "Need 'keys' in UIevents for valid keys. "; + // valid keys and elements must be same number + if (tmbUI.UIkeys.length && tmbUI.UIelements.length && tmbUI.UIelements.length < tmbUI.UIkeys.length) + errorMessage += 'Invalid number of UIelements, ' + "more 'keys' than 'UIelements'. "; + // elements must be specified for highlighting + if (tmbUI.UIelements.length === 0 && tmbUI.highlight !== '') errorMessage += 'No elements to highlight. '; + + // error handler + if (errorMessage) { + tmbUI.status = 'error'; + tmbUI.message = errorMessage; + + // fire readyUI event + var readyUI = new CustomEvent('readyUI'); + document.addEventListener('readyUI', tmbUI.onreadyUI, true); + document.dispatchEvent(readyUI); + document.removeEventListener('readyUI', tmbUI.onreadyUI, true); + + return false; + } + + // down event listener + function downResponseHandler(e) { + var responseEvent, r; + + responseEvent = e; //|| window.event; + + // prevent bubbling + if (responseEvent.cancelable) responseEvent.preventDefault(); + responseEvent.stopPropagation(); + + // process input only on first hit (i.e. debounce) + if (downDebounce === false) { + // process keyboard input for keys + if (tmbUI.UIevents.includes('keys') && responseEvent.type === 'keydown') { + r = responseEvent.charCode || responseEvent.keyCode; + + // key must be valid + if (tmbUI.UIkeys.includes(r) || tmbUI.UIkeys.length === 0) { + // determine response identity + tmbUI.response = codeToKey(r); + + // determine the element to highlight + if (tmbUI.highlight !== '' && tmbUI.UIkeys.length > 0) + highlightEl = getID(tmbUI.UIelements[tmbUI.UIkeys.indexOf(r)]); + + // set the debounce flags: + // - down event detected and debounced, so we don't record + // the same down event multiple times, e.g. on autorepeat + // - up event not yet detected + downDebounce = true; + upDebounce = false; + validUpEventTypes = ['keyup']; + } + } + // process mouse and pointer input for clicks + if (tmbUI.UIevents.includes('clicks')) { + if ( + responseEvent.type === 'mousedown' || + (responseEvent.type === 'pointerdown' && responseEvent.pointerType === 'mouse') || + (responseEvent.type === 'MSPointerDown' && responseEvent.pointerType === responseEvent.MSPOINTER_TYPE_MOUSE) + ) { + if (tmbUI.UIelements.length === 0) tmbUI.response = 'document'; + else tmbUI.response = responseEvent.target ? responseEvent.target.id : responseEvent.srcElement.id; + + if (tmbUI.highlight !== '') highlightEl = getID(tmbUI.response); + + downDebounce = true; + upDebounce = false; + validUpEventTypes = ['mouseup', 'pointerup-mouse', 'MSPointerUp-mouse']; + } + } + // process touch and pointer input for taps + if (tmbUI.UIevents.includes('taps')) { + if ( + responseEvent.type === 'touchstart' || + (responseEvent.type === 'pointerdown' && + (responseEvent.pointerType === 'touch' || responseEvent.pointerType === 'pen')) || + (responseEvent.type === 'MSPointerDown' && + (responseEvent.pointerType === responseEvent.MSPOINTER_TYPE_TOUCH || + responseEvent.pointerType === responseEvent.MSPOINTER_TYPE_PEN)) + ) { + if (tmbUI.UIelements.length === 0) tmbUI.response = 'document'; + else tmbUI.response = responseEvent.target ? responseEvent.target.id : responseEvent.srcElement.id; + + if (tmbUI.highlight !== '') highlightEl = getID(tmbUI.response); + + downDebounce = true; + upDebounce = false; + validUpEventTypes = ['touchend', 'pointerup-touch', 'pointerup-pen', 'MSPointerUp-touch', 'MSPointerUp-pen']; + } + } + + // if valid response, compute rt, + // clear timeout and highlight target if required + if (downDebounce === true) { + tmbUI.rt = timeStamp; + timeStamp = now(); + tmbUI.rt = timeStamp - tmbUI.rt; + tmbUI.rt = tmbUI.rt.round(2); + tmbUI.downTimestamp = timeStamp; + + if (tmbUI.timeoutRef) clearTimeout(tmbUI.timeoutRef); + + if (highlightEl) { + // HTML elements + if (['div', 'span', 'button', 'p', 'img'].includes(highlightEl.tagName.toLowerCase())) { + highlightEl.classList.add(tmbUI.highlight); + } + // SVG elements + else if ( + ['circle', 'rect', 'ellipse', 'line', 'path', 'polygon', 'polyline', 'image', 'text'].includes( + highlightEl.tagName.toLowerCase() + ) + ) { + highlightEl.classList.add(tmbUI.highlight); + } + } + } + } + } + + // up event listener + function upResponseHandler(e) { + var responseEvent; + var MSetypes = ['', '', 'touch', 'pen', 'mouse']; + var upType; + + responseEvent = e; // || window.event; + + // prevent bubbling + if (responseEvent.cancelable) responseEvent.preventDefault(); + responseEvent.stopPropagation(); + + // determine the up-event type + upType = responseEvent.type; + if (upType === 'pointerup') upType += '-' + responseEvent.pointerType; + else if (upType === 'MSPointerUp') upType += '-' + MSetypes[responseEvent.pointerType]; + + // process up-event only if preceded by valid down-event of same type + if (downDebounce === true && upDebounce === false && validUpEventTypes.includes(upType)) { + // compute dwell time + tmbUI.upTimestamp = now(); + tmbUI.dwell = tmbUI.upTimestamp - timeStamp; + tmbUI.dwell = tmbUI.dwell.round(2); + + // status returns event type + tmbUI.status = upType; + + // don't allow another up response until + // a valid down response has been made + upDebounce = true; + + removeHandlers(); + returnHandler(); + } + } + + // installs appropriate listeners depending on input type + function installHandlers() { + // listen to keyboard events + if (tmbUI.UIevents.includes('keys')) { + document.addEventListener('keydown', downResponseHandler, true); + document.addEventListener('keyup', upResponseHandler, true); + } + // listen to mouse events (mouse, touchpad and pen/stylus) + if (tmbUI.UIevents.includes('clicks')) { + if (tmbUI.UIelements.length === 0) { + if (window.PointerEvent) { + document.body.addEventListener('pointerdown', downResponseHandler, true); + document.body.addEventListener('pointerup', upResponseHandler, true); + } else if (window.MSPointerEvent) { + // IE10 + document.body.addEventListener('MSPointerDown', downResponseHandler, true); + document.body.addEventListener('MSPointerUp', upResponseHandler, true); + } else { + document.addEventListener('mousedown', downResponseHandler, true); + document.addEventListener('mouseup', upResponseHandler, true); + } + } else { + // we install the up handler on the document, so that an up + // event can be detected even on an element different from the + // target of the preceding down event + document.addEventListener('mouseup', upResponseHandler, true); + if (window.PointerEvent) document.addEventListener('pointerup', upResponseHandler, true); + else if (window.MSPointerEvent) document.addEventListener('MSPointerUp', upResponseHandler, true); // IE10 + + for (i = 0; i < tmbUI.UIelements.length; i++) { + if (window.PointerEvent) { + getID(tmbUI.UIelements[i]).addEventListener('pointerdown', downResponseHandler, true); + getID(tmbUI.UIelements[i]).addEventListener('pointerup', upResponseHandler, true); + } else if (window.MSPointerEvent) { + // IE10 + getID(tmbUI.UIelements[i]).addEventListener('MSPointerDown', downResponseHandler, true); + getID(tmbUI.UIelements[i]).addEventListener('MSPointerUp', upResponseHandler, true); + } else { + getID(tmbUI.UIelements[i]).addEventListener('mousedown', downResponseHandler, true); + getID(tmbUI.UIelements[i]).addEventListener('mouseup', upResponseHandler, true); + } + } + } + } + // listen to touch events + if (tmbUI.UIevents.includes('taps')) { + if (tmbUI.UIelements.length === 0) { + if (window.PointerEvent && !tmbUI.UIevents.includes('clicks')) { + document.addEventListener('pointerdown', downResponseHandler, true); + document.addEventListener('pointerup', upResponseHandler, true); + } else if (window.MSPointerEvent && !tmbUI.UIevents.includes('clicks')) { + // IE10 + document.addEventListener('MSPointerDown', downResponseHandler, true); + document.addEventListener('MSPointerUp', upResponseHandler, true); + } else if (hasTouch && !hasPointer) { + document.addEventListener('touchstart', downResponseHandler, true); + document.addEventListener('touchend', upResponseHandler, true); + } + } else { + if (window.PointerEvent) document.addEventListener('pointerup', upResponseHandler, true); + else if (window.MSPointerEvent) document.addEventListener('MSPointerUp', upResponseHandler, true); + if (hasTouch) document.addEventListener('touchend', upResponseHandler, true); + + for (i = 0; i < tmbUI.UIelements.length; i++) { + if (window.PointerEvent && !tmbUI.UIevents.includes('clicks')) { + getID(tmbUI.UIelements[i]).addEventListener('pointerdown', downResponseHandler, true); + getID(tmbUI.UIelements[i]).addEventListener('pointerup', upResponseHandler, true); + } else if (window.MSPointerEvent && !tmbUI.UIevents.includes('clicks')) { + // IE10 + getID(tmbUI.UIelements[i]).addEventListener('MSPointerDown', downResponseHandler, true); + getID(tmbUI.UIelements[i]).addEventListener('MSPointerUp', upResponseHandler, true); + } else if (hasTouch && !hasPointer) { + getID(tmbUI.UIelements[i]).addEventListener('touchstart', downResponseHandler, true); + getID(tmbUI.UIelements[i]).addEventListener('touchend', upResponseHandler, true); + } + } + } + } + } + + // removes installed listeners + function removeHandlers() { + if (tmbUI.UIevents.includes('keys')) { + document.removeEventListener('keydown', downResponseHandler, true); + document.removeEventListener('keyup', upResponseHandler, true); + } + if (tmbUI.UIevents.includes('clicks')) { + if (tmbUI.UIelements.length === 0) { + if (window.PointerEvent) { + document.body.removeEventListener('pointerdown', downResponseHandler, true); + document.body.removeEventListener('pointerup', upResponseHandler, true); + } else if (window.MSPointerEvent) { + // IE10 + document.body.removeEventListener('MSPointerDown', downResponseHandler, true); + document.body.removeEventListener('MSPointerUp', upResponseHandler, true); + } else { + document.removeEventListener('mousedown', downResponseHandler, true); + document.removeEventListener('mouseup', upResponseHandler, true); + } + } else { + // remove up handlers on document body + if (window.PointerEvent) document.removeEventListener('pointerup', upResponseHandler, true); + else if (window.MSPointerEvent) document.removeEventListener('MSPointerUp', upResponseHandler, true); + document.removeEventListener('mouseup', upResponseHandler, true); + + for (i = 0; i < tmbUI.UIelements.length; i++) { + if (window.PointerEvent) { + getID(tmbUI.UIelements[i]).removeEventListener('pointerdown', downResponseHandler, true); + getID(tmbUI.UIelements[i]).removeEventListener('pointerup', upResponseHandler, true); + } else if (window.MSPointerEvent) { + // IE10 + getID(tmbUI.UIelements[i]).removeEventListener('MSPointerDown', downResponseHandler, true); + getID(tmbUI.UIelements[i]).removeEventListener('MSPointerUp', upResponseHandler, true); + } else { + getID(tmbUI.UIelements[i]).removeEventListener('mousedown', downResponseHandler, true); + getID(tmbUI.UIelements[i]).removeEventListener('mouseup', upResponseHandler, true); + } + } + } + } + if (tmbUI.UIevents.includes('taps')) { + if (tmbUI.UIelements.length === 0) { + if (window.PointerEvent && !tmbUI.UIevents.includes('clicks')) { + document.removeEventListener('pointerdown', downResponseHandler, true); + document.removeEventListener('pointerup', upResponseHandler, true); + } else if (window.MSPointerEvent && !tmbUI.UIevents.includes('clicks')) { + // IE10 + document.removeEventListener('MSPointerDown', downResponseHandler, true); + document.removeEventListener('MSPointerUp', upResponseHandler, true); + } else if (hasTouch && !hasPointer) { + document.removeEventListener('touchstart', downResponseHandler, true); + document.removeEventListener('touchend', upResponseHandler, true); + } + } else { + if (window.PointerEvent) document.removeEventListener('pointerup', upResponseHandler, true); + else if (window.MSPointerEvent) document.removeEventListener('MSPointerUp', upResponseHandler, true); + if (hasTouch) document.removeEventListener('touchend', upResponseHandler, true); + + for (i = 0; i < tmbUI.UIelements.length; i++) { + if (window.PointerEvent && !tmbUI.UIevents.includes('clicks')) { + getID(tmbUI.UIelements[i]).removeEventListener('pointerdown', downResponseHandler, true); + getID(tmbUI.UIelements[i]).removeEventListener('pointerup', upResponseHandler, true); + } else if (window.MSPointerEvent && !tmbUI.UIevents.includes('clicks')) { + // IE10 + getID(tmbUI.UIelements[i]).removeEventListener('MSPointerDown', downResponseHandler, true); + getID(tmbUI.UIelements[i]).removeEventListener('MSPointerUp', upResponseHandler, true); + } else if (hasTouch && !hasPointer) { + getID(tmbUI.UIelements[i]).removeEventListener('touchstart', downResponseHandler, true); + getID(tmbUI.UIelements[i]).removeEventListener('touchend', upResponseHandler, true); + } + } + } + } + } + + function returnHandler() { + // clear the timeout trap + if (tmbUI.timeoutRef) clearTimeout(tmbUI.timeoutRef); + + // if we have highlighted something, wait to switch it off + // then fire readyUI event + if (highlightEl) { + setTimeout(function () { + if (['div', 'span', 'button', 'p', 'img'].includes(highlightEl.tagName.toLowerCase())) { + highlightEl.classList.remove(tmbUI.highlight); + } else if ( + ['circle', 'rect', 'ellipse', 'line', 'path', 'polygon', 'polyline', 'image', 'text'].includes( + highlightEl.tagName.toLowerCase() + ) + ) { + highlightEl.classList.remove(tmbUI.highlight); + } + + // zero timeoutRef, so we can listen to a new response + tmbUI.timeoutRef = 0; + + // fire readyUI event + var readyUI = new CustomEvent('readyUI'); + document.addEventListener('readyUI', tmbUI.onreadyUI, true); + document.dispatchEvent(readyUI); + document.removeEventListener('readyUI', tmbUI.onreadyUI, true); + }, 250); + } else { + // zero timeoutRef, so we can listen to a new response + tmbUI.timeoutRef = 0; + + var readyUI = new CustomEvent('readyUI'); + document.addEventListener('readyUI', tmbUI.onreadyUI, true); + document.dispatchEvent(readyUI); + document.removeEventListener('readyUI', tmbUI.onreadyUI, true); + } + } + + // set a timeout trap + // N.B. we start listening for a new response only when timeoutRef === 0 + tmbUI.timeoutRef = setTimeout(function () { + tmbUI.status = 'timeout'; + tmbUI.message += 'Timeout: no response in ' + tmbUI.timeout + ' ms.'; + removeHandlers(); + returnHandler(); + }, tmbUI.timeout); + + // finally, start listening! + installHandlers(); + + return false; +}; + +function mb_strwidth(s) { + // Returns the length of string 's', taking into account + // full- and half-width characters, e.g. in Asian and Latin alphabets + // Equivalent to homonymous PHP function + + var l = 0; + var chars = Array.from(s); + for (var char of chars) { + var c = char.codePointAt(0); + if (c === undefined) continue; + + if (0x1100 <= c && c <= 0x115f) { + l += 2; + } else if (0x11a3 <= c && c <= 0x11a7) { + l += 2; + } else if (0x11fa <= c && c <= 0x11ff) { + l += 2; + } else if (0x2329 <= c && c <= 0x232a) { + l += 2; + } else if (0x2e80 <= c && c <= 0x2e99) { + l += 2; + } else if (0x2e9b <= c && c <= 0x2ef3) { + l += 2; + } else if (0x2f00 <= c && c <= 0x2fd5) { + l += 2; + } else if (0x2ff0 <= c && c <= 0x2ffb) { + l += 2; + } else if (0x3000 <= c && c <= 0x303e) { + l += 2; + } else if (0x3041 <= c && c <= 0x3096) { + l += 2; + } else if (0x3099 <= c && c <= 0x30ff) { + l += 2; + } else if (0x3105 <= c && c <= 0x312d) { + l += 2; + } else if (0x3131 <= c && c <= 0x318e) { + l += 2; + } else if (0x3190 <= c && c <= 0x31ba) { + l += 2; + } else if (0x31c0 <= c && c <= 0x31e3) { + l += 2; + } else if (0x31f0 <= c && c <= 0x321e) { + l += 2; + } else if (0x3220 <= c && c <= 0x3247) { + l += 2; + } else if (0x3250 <= c && c <= 0x32fe) { + l += 2; + } else if (0x3300 <= c && c <= 0x4dbf) { + l += 2; + } else if (0x4e00 <= c && c <= 0xa48c) { + l += 2; + } else if (0xa490 <= c && c <= 0xa4c6) { + l += 2; + } else if (0xa960 <= c && c <= 0xa97c) { + l += 2; + } else if (0xac00 <= c && c <= 0xd7a3) { + l += 2; + } else if (0xd7b0 <= c && c <= 0xd7c6) { + l += 2; + } else if (0xd7cb <= c && c <= 0xd7fb) { + l += 2; + } else if (0xf900 <= c && c <= 0xfaff) { + l += 2; + } else if (0xfe10 <= c && c <= 0xfe19) { + l += 2; + } else if (0xfe30 <= c && c <= 0xfe52) { + l += 2; + } else if (0xfe54 <= c && c <= 0xfe66) { + l += 2; + } else if (0xfe68 <= c && c <= 0xfe6b) { + l += 2; + } else if (0xff01 <= c && c <= 0xff60) { + l += 2; + } else if (0xffe0 <= c && c <= 0xffe6) { + l += 2; + } else if (0x1b000 <= c && c <= 0x1b001) { + l += 2; + } else if (0x1f200 <= c && c <= 0x1f202) { + l += 2; + } else if (0x1f210 <= c && c <= 0x1f23a) { + l += 2; + } else if (0x1f240 <= c && c <= 0x1f248) { + l += 2; + } else if (0x1f250 <= c && c <= 0x1f251) { + l += 2; + } else if (0x20000 <= c && c <= 0x2fffd) { + l += 2; + } else if (0x30000 <= c && c <= 0x3fffd) { + l += 2; + } else { + l += 1; + } + } + return l; +} + +function showAlert(alertMessage, alertButtonText, action, fontSize, timeout, useSpaceBar, hideCursor) { + var alertBox, alertContent, alertButton, alertSpaceBar, bodyCursorStyle, buttonCursorStyle; + + // save the current body cursor style and set the required one + bodyCursorStyle = window.getComputedStyle(document.body)['cursor']; + if (!hideCursor && bodyCursorStyle === 'none') document.body.style.cursor = 'auto'; + else if (hideCursor && bodyCursorStyle !== 'none') document.body.style.cursor = 'none'; + + // create the container div if necessary + if (!(alertBox = getID('alertBox'))) { + // set sizes to inherit parent's + alertBox = document.createElement('div'); + alertBox.id = 'alertBox'; + alertBox.style.margin = 'auto'; + alertBox.style.height = 'inherit'; //document.body.clientHeight+'px'; + alertBox.style.width = 'inherit'; //document.body.clientWidth+'px'; + alertBox.style.verticalAlign = 'middle'; + alertBox.style.textAlign = 'center'; + document.body.appendChild(alertBox); + } + + // set the required font size + if (fontSize) alertBox.style.fontSize = fontSize; + + // create the message span if necessary, + // then set the message to display + if (!(alertContent = getID('alertContent'))) { + alertContent = document.createElement('span'); + alertContent.id = 'alertContent'; + alertContent.style.margin = 'auto'; + alertContent.style.display = 'inline'; + alertBox.appendChild(alertContent); + } + alertContent.innerHTML = alertMessage; + + // create the button if necessary + if (!(alertButton = getID('alertButton'))) { + alertButton = document.createElement('button'); + alertButton.id = 'alertButton'; + alertButton.className = 'button'; + alertButton.style.margin = 'auto'; + alertButton.style.maxWidth = '100%'; + alertButton.style.lineHeight = '1.5em'; + alertButton.style.textAlign = 'center'; + alertButton.style.fontSize = '1.2em'; + alertButton.style.padding = '0 1ch'; + alertButton.style.display = 'inline'; + alertBox.appendChild(alertButton); + } + // if args contain button text, + // show the button and set the required action for it, + // otherwise hide the button + if (alertButtonText && !useSpaceBar && !timeout) { + // save the current button cursor style and set the required one + buttonCursorStyle = window.getComputedStyle(alertButton)['cursor']; + if (!hideCursor && buttonCursorStyle === 'none') alertButton.style.cursor = 'pointer'; + else if (hideCursor && buttonCursorStyle !== 'none') alertButton.style.cursor = 'none'; + + alertButton.innerHTML = alertButtonText; + alertButton.onclick = function () { + document.body.style.cursor = bodyCursorStyle; + alertButton.style.cursor = buttonCursorStyle; + action(); + }; + alertButton.style.display = 'inline'; + } else alertButton.style.display = 'none'; + + // create the spaceBar span if necessary + if (!(alertSpaceBar = getID('alertSpaceBar'))) { + alertSpaceBar = document.createElement('span'); + alertSpaceBar.id = 'alertSpaceBar'; + alertSpaceBar.style.margin = 'auto'; + alertSpaceBar.style.display = 'inline'; + //alertSpaceBar.style.fontSize = '20px'; + alertBox.appendChild(alertSpaceBar); + } + // if args contain 'useSpaceBar', + // show the spaceBar span and set the required key listener, + // otherwise hide the span + if (useSpaceBar && !timeout) { + // alertSpaceBar.style.width = (mb_strwidth(useSpaceBar) + 3) + 'ch'; + alertSpaceBar.innerHTML = useSpaceBar; + alertSpaceBar.style.display = 'inline'; + + function spaceBarHandler(e) { + var key = e.charCode || e.keyCode; + if (key === 32) { + e.preventDefault(); + e.stopPropagation(); + if (e.type === 'keydown') { + document.removeEventListener('keydown', spaceBarHandler, true); + } else { + document.removeEventListener('keyup', spaceBarHandler, true); + document.body.style.cursor = bodyCursorStyle; + action(); + } + } + } + + document.addEventListener('keydown', spaceBarHandler, true); + document.addEventListener('keyup', spaceBarHandler, true); + } else alertSpaceBar.style.display = 'none'; + + // if args contain a timeout, + // trigger the action automatically when timeout expires + if (timeout) + setTimeout(function () { + document.body.style.cursor = bodyCursorStyle; + action(); + }, timeout); + + // hide everything else except this + showFrame(null); + alertBox.style.display = 'table-cell'; +} + +function setBodyScale(width, height) { + // Fail silently if visualViewport is not supported + if (!('visualViewport' in window)) return; + + // If the dimensions of the desired bounding box aren't specified, + // throw an error. + if (!width || !height) throw new TypeError('setBodyScale: dimensions not specified'); + + // Check if a viewport meta tag exists: if not, we create one. + var viewportMeta = document.getElementsByTagName('meta')['viewport']; + if (!viewportMeta) { + viewportMeta = document.createElement('meta'); + viewportMeta.name = 'viewport'; + viewportMeta.id = 'viewport'; + document.getElementsByTagName('head')[0].appendChild(viewportMeta); + } + + // Initialize the viewport to its ideal dimensions, in case it isn't + viewportMeta.content = 'width=device-width, initial-scale=1, viewport-fit=contain'; + + // initialize the body + var bodyStyle = document.body.style; + bodyStyle.position = 'absolute'; + bodyStyle.width = visualViewport.width + 'px'; + bodyStyle.left = visualViewport.width / 2 + 'px'; + bodyStyle.marginLeft = -visualViewport.width / 2 + 'px'; + bodyStyle.height = visualViewport.height + 'px'; + bodyStyle.top = visualViewport.height / 2 + 'px'; + bodyStyle.marginTop = -visualViewport.height / 2 + 'px'; + bodyStyle.overflow = 'hidden'; + + function bodyScaleHandler() { + // reset the body before resizing + bodyStyle.width = visualViewport.width + 'px'; + bodyStyle.height = visualViewport.height + 'px'; + bodyStyle.left = visualViewport.width / 2 + 'px'; + bodyStyle.top = visualViewport.height / 2 + 'px'; + bodyStyle.marginLeft = -visualViewport.width / 2 + 'px'; + bodyStyle.marginTop = -visualViewport.height / 2 + 'px'; + bodyStyle.overflow = 'hidden'; + bodyStyle.transform = 'scale(1)'; + + // if the body's width is smaller than the desired size, set it to + // the desired size and re-center + if (visualViewport.width < width) { + bodyStyle.width = width + 'px'; + bodyStyle.marginLeft = -width / 2 + 'px'; + } + // if the body's height is smaller than the desired size, set it to + // the desired size and re-center + if (visualViewport.height < height) { + bodyStyle.height = height + 'px'; + bodyStyle.marginTop = -height / 2 + 'px'; + } + // force reflow + document.body.offsetHeight; + + // if the viewport is smaller than the desired bounding box + // (vertically, or horizontally or both), compute the necessary + // scaling and apply to the body + if (visualViewport.width * visualViewport.scale < width || visualViewport.height * visualViewport.scale < height) { + var widthScale = (visualViewport.width * visualViewport.scale) / width; + var heightScale = (visualViewport.height * visualViewport.scale) / height; + + var scale = Math.min(widthScale, heightScale); + bodyStyle.transform = 'scale(' + scale + ')'; + } + document.body.offsetHeight; + + // recenter by adding viewport offset + bodyStyle.left = parseFloat(bodyStyle.left) + visualViewport.pageLeft + 'px'; + bodyStyle.top = parseFloat(bodyStyle.top) + visualViewport.pageTop + 'px'; + document.body.offsetHeight; + } + + // We attach listeners for the resize event to the window and + // to the viewport + // (orientationchange is added for browsers that don't fire a resize + // event on orientation change) + // the resize handler is debounced, so multiple (near-)simultaneous + // events only trigger it once + var resizeHandler = debounce(bodyScaleHandler, 1000); + window.addEventListener('resize', resizeHandler); + visualViewport.addEventListener('resize', resizeHandler); + if ('orientation' in screen) screen.orientation.addEventListener('change', resizeHandler); + else if ('onorientationchange' in window) window.addEventListener('orientationchange', resizeHandler); + + // on first call, set the desired scale + bodyScaleHandler(); +} + +function deviceScan() { + var scan = {}, + userAgent; + + userAgent = navigator.userAgent || navigator.vendor || window.opera; + scan.screenW = screen.width > screen.height ? screen.width : screen.height; + scan.screenH = screen.width < screen.height ? screen.width : screen.height; + scan.touch = + 'ontouchend' in window || + ('maxTouchPoints' in navigator && navigator.maxTouchPoints > 0) || + ('msMaxTouchPoints' in navigator && navigator.msMaxTouchPoints > 0) || + (window.matchMedia && window.matchMedia('(any-pointer: coarse)').matches) || + false; + scan.OS = /windows phone/i.test(userAgent) + ? 'WindowsPhone' + : /Kindle Fire|Silk|KFAPWA|KFSOWI|KFJWA|KFJWI|KFAPWI|KFOT|KFTT|KFTHWI|KFTHWA|KFASWI|KFTBWI|KFMEWI|KFFOWI|KFSAWA|KFSAWI|KFARWI/i.test( + userAgent + ) + ? 'KindleFire' + : /BlackBerry|BB10|PlayBook/i.test(userAgent) + ? 'BlackBerry' + : /MeeGO/i.test(userAgent) + ? 'MeeGO' + : /Bada/i.test(userAgent) + ? 'Bada' + : /Tizen/i.test(userAgent) + ? 'Tizen' + : /android/i.test(userAgent) + ? 'Android' + : /iPad|iPhone|iPod/i.test(userAgent) && !window.MSStream + ? 'iOS' + : /Win/i.test(userAgent) + ? 'Windows' + : /Mac/i.test(userAgent) + ? 'MacOS' + : /Linux|X11/i.test(userAgent) + ? 'Unix' + : 'unknown'; + scan.UTCoffset = new Date().getTimezoneOffset(); + + return scan; +} + +function parseQuery(queryStr) { + var query = {}; + var pairs = (queryStr[0] === '?' ? queryStr.substring(1) : queryStr).split('&'); + if (pairs[0] !== '') { + for (var i = 0; i < pairs.length; i++) { + var pair = pairs[i].split('='); + query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || ''); + } + } + return query; +} diff --git a/lib/interactive/TMB_DIGIT_SYMBOL_CODING/TestMyBrain.12.18.min.js b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/TestMyBrain.12.18.min.js new file mode 100644 index 0000000..a37ffbb --- /dev/null +++ b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/TestMyBrain.12.18.min.js @@ -0,0 +1,4129 @@ +/* eslint-disable */ + +/* + Copyright 2021 by the Many Brains Project, Inc. + =============================================== + + This code is made available under a GNU Lesser General Public License 3.0 + (LGPLv3). + https://www.gnu.org/licenses/lgpl-3.0.html. + + The following third party libraries and code are included in TestMyBrain.js + for convenience (copyright and licenses, where applicable, are by their + respective authors and can be found in the code or in the attached web + links): + + - rawdeflate.js at + https://github.com/dankogai/js-deflate + - rawinflate.js at + https://github.com/dankogai/js-deflate + - json2.js at + https://github.com/douglascrockford/JSON-js + - FileSaver.js at + https://github.com/ChenWenBrian/FileSaver.js + - Blob.js at + https://github.com/eligrey/Blob.js + - seedrandom.js at + https://github.com/davidbau/seedrandom/tree/master + - setImmediate.js at + https://github.com/YuzuJS/setImmediate + - requestAnimationFrame and cancelAnimationFrame at + https://github.com/darius/requestAnimationFrame + - atob and btoa at + https://github.com/davidchambers/Base64.js + - Object.create at + https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create + - Object.keys at + https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys + - Function.prototype.bind at + https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind + - Array.isArray at + https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray + - all standard HTML5 array prototype methods at + https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array + + */ + +function getID(e, t) { + return t ? (tmbObjs.elements[e] = tmbObjs.elements[e] || document.getElementById(e)) : document.getElementById(e); +} +function showFrame() { + var e, + t, + n = []; + if (1 === arguments.length && arguments[0] instanceof Array) n = arguments[0]; + else for (t = 0; t < arguments.length; t++) n[t] = arguments[t]; + for ( + tmbObjs.frames.length || (tmbObjs.frames = document.getElementsByTagName('div')), t = tmbObjs.frames.length; + t--; + ) + ((e = n.indexOf(tmbObjs.frames[t].id) > -1 ? 'block' : 'none'), + tmbObjs.frames[t].style.display !== e && (tmbObjs.frames[t].style.display = e)); +} +function showFrameClass() { + var e, + t, + n = []; + if (1 === arguments.length && arguments[0] instanceof Array) n = arguments[0]; + else for (t = 0; t < arguments.length; t++) n[t] = arguments[t]; + for ( + tmbObjs.frames.length || (tmbObjs.frames = document.getElementsByTagName('div')), t = tmbObjs.frames.length; + t--; + ) + ((e = n.indexOf(tmbObjs.frames[t].className) > -1 ? 'block' : 'none'), + tmbObjs.frames[t].style.display !== e && (tmbObjs.frames[t].style.display = e)); +} +function showSlide(e) { + tmbObjs.slides.length || (tmbObjs.slides = document.getElementsByClassName('slide')); + for (var t, n = tmbObjs.slides, r = tmbObjs.slides.length; r--; ) + ((t = n[r].id === e ? 'block' : 'none'), n[r].style.display !== t && (n[r].style.display = t)); +} +function showAlert(e, t, n, r, o) { + var i, a, s; + ((i = getID('alertBox', 1)) || + ((i = document.createElement('div')), + (i.id = 'alertBox'), + (i.style.margin = 'auto'), + (i.style.padding = '5%'), + (i.style.height = '100vh'), + (i.style.width = '100vw'), + (i.style.verticalAlign = 'middle'), + (i.style.textAlign = 'center'), + document.body.appendChild(i), + getID('alertBox', 1)), + r && (i.style.fontSize = r), + (a = getID('alertContent')) || ((a = document.createElement('span')), (a.id = 'alertContent'), i.appendChild(a)), + (a.innerHTML = e), + (s = getID('alertButton')) || + ((s = document.createElement('button')), + (s.id = 'alertButton'), + (s.className = 'button'), + (s.style.margin = '0 auto'), + (s.style.lineHeight = '1.5em'), + (s.style.textAlign = 'center'), + (s.style.fontSize = '1.2em'), + i.appendChild(s)), + t && !o + ? ((s.style.width = t.length + 'ch'), + (s.innerHTML = t), + (s.onclick = n), + (s.style.display = 'block'), + showCursor('document.body')) + : (s.style.display = 'none'), + o && setTimeout(n, o), + showFrame(null), + (i.style.display = 'table-cell')); +} +function injectScript(e, t, n) { + var r, + o = document.head || document.getElementsByTagName('head')[0]; + (t && null !== (r = document.getElementById(t)) && r.parentNode.removeChild(r), + (r = document.createElement('script')), + (r.type = 'text/javascript'), + t && (r.id = t), + n && (r.addEventListener ? r.addEventListener('load', n, !0) : r.readyState && (r.onreadystatechange = n)), + (r.src = e), + o.appendChild(r)); +} +function fixMobileOrientation(e) { + function t() { + var t; + ('orientation' in window + ? (t = 90 === Math.abs(window.orientation) ? 'landscape' : 'portrait') + : ((t = screen.orientation ? screen.orientation.type : screen.mozOrientation || screen.msOrientation), + (t = ~t.indexOf('landscape') ? 'landscape' : 'portrait')), + t !== e && alert(r)); + } + if ('orientation' in window || 'orientation' in screen || 'mozOrientation' in screen || 'msOrientation' in screen) { + if ('portrait' !== e && 'landscape' !== e) + throw new TypeError("fixMobileOrientation: specify either 'portrait' or 'landscape'"); + var n = 'portrait' === e ? 'upright' : 'sideways', + r = 'Please keep your device in ' + e + ' mode (' + n + ') for this test!'; + ('onorientationchange' in window + ? window.addEventListener('orientationchange', t, !0) + : 'orientation' in screen + ? screen.orientation.addEventListener('change', t, !0) + : 'onmsorientationchange' in screen + ? screen.addEventListener('MSOrientationChange', t, !0) + : 'onmozorientationchange' in screen && screen.addEventListener('mozorientationchange', t, !0), + t()); + } +} +function setMobileViewportScale(e, t) { + function n() { + var n, o, i, a, s, u, l, c; + ((r.content = 'width=device-width, initial-scale=1'), + 'orientation' in window + ? (i = 90 === Math.abs(window.orientation) ? 'landscape' : 'portrait') + : ((i = screen.orientation ? screen.orientation.type : screen.mozOrientation || screen.msOrientation), + (i = ~i.indexOf('landscape') ? 'landscape' : 'portrait')), + 'portrait' === i + ? ((n = Math.min(screen.width, screen.height)), (o = Math.max(screen.width, screen.height))) + : 'landscape' === i && + ((n = Math.max(screen.width, screen.height)), (o = Math.min(screen.width, screen.height))), + (a = n / e), + (s = o / t), + s > a ? ((u = a), (l = e)) : ((u = s), (l = n / u)), + (c = 'width=' + Math.round(l)), + (c += ', initial-scale=' + u), + (c += ', maximum-scale=' + u), + (r.content = c)); + } + if ('orientation' in window || 'orientation' in screen || 'mozOrientation' in screen || 'msOrientation' in screen) { + var r; + if (!e || !t) throw new TypeError('setMobileViewportScale: dimensions not specified'); + ((r = document.getElementsByTagName('meta').viewport), + r || + ((r = document.createElement('meta')), + (r.name = 'viewport'), + (r.id = 'viewport'), + document.getElementsByTagName('head')[0].appendChild(r)), + n(), + 'onorientationchange' in window + ? window.addEventListener('orientationchange', n, !0) + : 'orientation' in screen + ? screen.orientation.addEventListener('change', n, !0) + : 'onmsorientationchange' in screen + ? screen.addEventListener('MSOrientationChange', n, !0) + : 'onmozorientationchange' in screen && screen.addEventListener('mozorientationchange', n, !0)); + } +} +function showCursor(e) { + 'document.body' === e ? (document.body.style.cursor = 'auto') : (getID(e).style.cursor = 'auto'); +} +function hideCursor(e) { + 'document.body' === e ? (document.body.style.cursor = 'none') : (getID(e).style.cursor = 'none'); +} +function tmbSubmitToServer(e, t, n, r) { + var o, i, a, s; + ((r = r ? r : '/run'), + document.createElement && + (o = document.createElement('FORM')) && + (i = document.createElement('INPUT')) && + (a = document.createElement('INPUT')) && + (s = document.createElement('INPUT')) && + ((o.name = 'form'), + (o.method = 'post'), + (o.action = r), + (o.onsubmit = function () { + return !1; + }), + (i.type = 'hidden'), + (i.name = 'data'), + (i.value = JSON.stringify(e)), + o.appendChild(i), + (a.type = 'hidden'), + (a.name = 'score'), + (a.value = t), + o.appendChild(a), + (s.type = 'hidden'), + (s.name = 'outcomes'), + (s.value = JSON.stringify(n)), + o.appendChild(s), + document.body.appendChild(o), + o.submit())); +} +function tmbSubmitToURL(e, t) { + var n; + if (null === t || 'object' != typeof t) throw new TypeError("tmbSubmitToURL: 'tmbData' is not an object."); + if (document.createElement && (n = document.createElement('FORM'))) { + ((n.name = 'form'), + (n.method = 'post'), + (n.action = e), + (n.onsubmit = function () { + return !1; + })); + for (var r in t) + if (t.hasOwnProperty(r)) { + var o = document.createElement('INPUT'); + ((o.type = 'hidden'), (o.name = r), (o.value = t[r]), n.appendChild(o)); + } + (document.body.appendChild(n), n.submit(), document.body.removeChild(n)); + } +} +function tmbSubmitToFile(e, t, n) { + for (var r = [], o = '', i = '', a = !0, s = 0; s < e.length; s++) + for (var u in e[s]) e[s].hasOwnProperty(u) && -1 === r.indexOf(u) && (r.push(u), (i += '"' + u + '",')); + for (i = i.substring(0, i.length - 1), i += '\r\n', s = 0; s < e.length; s++) { + o = ''; + for (var l = 0; l < r.length; l++) + ('undefined' != typeof e[s][r[l]] && + null !== e[s][r[l]] && + (o += + e[s][r[l]] instanceof Object + ? '"' + JSON.stringify(e[s][r[l]]).replace(/\"/g, '""') + '"' + : '"' + e[s][r[l]] + '"'), + (o += ',')); + ((o = o.substring(0, o.length - 1)), (i += o + '\r\n')); + } + if (n) { + a = !saveTextAs(i, t); + try { + a ? alert('Could not save the data!!') : alert('Data have been saved in ' + t); + } catch (c) { + a ? console.log('Could not save the data!!') : console.log('Data have been saved in ' + t); + } + } + try { + var d = window.open('', '', 'width=500,height=500,menubar=yes,toolbar=yes,scrollbars=yes,status=yes,resizable=yes'); + if (null === d || 'undefined' == typeof d) throw new TypeError(); + } catch (c) { + (alert('Could not open data window. Try disabling popup blockers before closing this.'), + (d = window.open( + '', + '', + 'width=500,height=500,menubar=yes,toolbar=yes,scrollbars=yes,status=yes,resizable=yes' + ))); + } finally { + if (null === d || 'undefined' == typeof d) alert('Tried again and failed opening data window.'); + else { + d.document.write('
' + i + '

'); + var f = d.document.createElement('INPUT'); + ((f.type = 'text'), (f.value = t), d.document.body.appendChild(f)); + var m = d.document.createElement('BUTTON'), + p = d.document.createTextNode('Save'); + (m.appendChild(p), + d.document.body.appendChild(m), + (d.onbeforeunload = function () { + return a ? 'Have you saved the data?' : void 0; + }), + (m.onclick = function () { + ((t = f.value), (a = !saveTextAs(i, t)), a && alert('Could not save the data!!')); + }), + (d.document.title = t), + d.document.close()); + } + } +} +function logResults(e, t) { + if (e && e[0]) { + var n, + r = '', + o = e.length; + if ('cum' === t || ('cum' !== t && 1 === o)) { + for (n in e[0]) e[0].hasOwnProperty(n) && (r += n + ' '); + (console.log(r), (r = '')); + } + for (var i = t && 'inc' !== t ? 0 : o - 1; o > i; i++) { + for (n in e[i]) e[i].hasOwnProperty(n) && (r += e[i][n] + ' '); + r += '\n'; + } + console.log(r); + } +} +function getUrlParameters(e, t, n) { + var r, o, i, a; + if (((r = t.length ? t : window.location.search), !r)) return !1; + ((o = r.split('?')[1].split('&')), (a = !0)); + for (var s = 0; s < o.length; s++) { + if (((i = o[s].split('=')), i[0] === e)) return ((a = !0), n ? decodeURIComponent(i[1]) : i[1]); + a = !1; + } + return a ? void 0 : !1; +} +function urlEncode(e) { + return ( + (e = (e + '').toString()), + encodeURIComponent(e) + .replace(/!/g, '%21') + .replace(/'/g, '%27') + .replace(/\(/g, '%28') + .replace(/\)/g, '%29') + .replace(/\*/g, '%2A') + .replace(/%20/g, '+') + ); +} +function httpBuildQuery(e, t, n) { + var r, + o, + i = [], + a = this, + s = function (e, t, n) { + var r, + o = []; + if ((t === !0 ? (t = '1') : t === !1 && (t = '0'), null !== t)) { + if ('object' == typeof t) { + for (r in t) null !== t[r] && t.hasOwnProperty(r) && o.push(s(e + '[' + r + ']', t[r], n)); + return o.join(n); + } + if ('function' != typeof t) return a.urlEncode(e) + '=' + a.urlEncode(t); + throw new Error('There was an error processing for http_build_query().'); + } + return ''; + }; + n || (n = '&'); + for (o in e) + if (e.hasOwnProperty(o)) { + ((r = e[o]), t && !isNaN(o) && (o = String(t) + o)); + var u = s(o, r, n); + '' !== u && i.push(u); + } + return i.join(n); +} +function ajaxRequest(e) { + var t, + n, + r, + o, + i, + a = { + url: '.', + method: 'GET', + data: null, + async: !0, + timeout: 1e4, + user: null, + pass: null, + getHeaders: !1, + sendCredentials: !1, + callback: null + }; + (null !== e && + 'object' == typeof e && + (e.hasOwnProperty('url') && (a.url = e.url), + e.hasOwnProperty('method') && (a.method = e.method.toUpperCase()), + e.hasOwnProperty('data') && (a.data = e.data), + e.hasOwnProperty('async') && (a.async = e.async), + e.hasOwnProperty('timeout') && (a.timeout = e.timeout), + e.hasOwnProperty('user') && (a.user = e.user), + e.hasOwnProperty('pass') && (a.pass = e.pass), + e.hasOwnProperty('getHeaders') && (a.getHeaders = e.getHeaders), + e.hasOwnProperty('sendCredentials') && (a.sendCredentials = e.sendCredentials), + e.hasOwnProperty('callback') && (a.callback = e.callback)), + null !== a.data && ((r = httpBuildQuery(a.data)), 'GET' === a.method && (a.url += '?' + r)), + (t = new XMLHttpRequest())); + try { + (t.open(a.method, a.url, a.async), + a.async && + (void 0 !== t.timeout && + void 0 !== t.ontimeout && + ((t.timeout = a.timeout), + (t.ontimeout = function () { + console.log('ajaxRequest timed out.'); + })), + void 0 !== t.withCredentials && a.sendCredentials && (t.withCredentials = !0), + (t.onreadystatechange = function () { + if ( + (a.getHeaders && + 2 === t.readyState && + ((o = t.getAllResponseHeaders()), + console.log('Request Status: ' + t.status + ' ' + t.statusText), + o && console.log(o)), + 4 === t.readyState) + ) + if (t.status >= 200 && t.status < 400) { + if (((i = void 0 !== t.response ? t.response : t.responseText), null === a.callback)) return i; + a.callback(i); + } else { + if (((n = 'Error in ajaxRequest: ' + t.status + ' ' + t.statusText), console.log(n), null === a.callback)) + return null; + a.callback(null); + } + })), + t.setRequestHeader('X-Requested-With', 'XMLHttpRequest'), + a.user && a.pass && t.setRequestHeader('Authorization', 'Basic ' + btoa(a.user + ':' + a.pass)), + 'POST' === a.method && t.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')); + } catch (s) { + if (((n = "Error in ajaxRequest 'open': " + s.message), console.log(n), null === a.callback)) return null; + a.callback(null); + } + try { + 'POST' === a.method ? t.send(r) : t.send(); + } catch (s) { + if (((n = "Error in ajaxRequest 'send': " + s.message), console.log(n), null === a.callback)) return null; + a.callback(null); + } + if (!a.async) + if ( + (a.getHeaders && + ((o = t.getAllResponseHeaders()), + console.log('Request Status: ' + t.status + ' ' + t.statusText), + o && console.log(o)), + t.status >= 200 && t.status < 400) + ) { + if (((i = void 0 !== t.response ? t.response : t.responseText), null === a.callback)) return i; + a.callback(i); + } else { + if (((n = 'Error in ajaxRequest: ' + t.status + ' ' + t.statusText), console.log(n), null === a.callback)) + return null; + a.callback(null); + } +} +function imagePreLoad(e, t) { + var n = e.slice(), + r = 0, + o = { progress: !0, pipeline: !0, copy: !0, callBack: null }; + (void 0 === tmbObjs.images && (tmbObjs.images = []), + null !== t && + 'object' == typeof t && + (t.hasOwnProperty('progress') && (o.progress = t.progress), + t.hasOwnProperty('pipeline') && (o.pipeline = t.pipeline), + t.hasOwnProperty('copy') && (o.copy = t.copy), + t.hasOwnProperty('callBack') && (o.callBack = t.callBack))); + var i, + a, + s, + u, + l = o.pipeline ? 1 : n.length; + o.progress && + ((i = document.createElement('div')), + (a = document.createElement('span')), + (s = document.createElement('span')), + (u = document.createElement('progress')), + (i.id = '_preloadDiv'), + (i.style.textAlign = 'center'), + (i.style.position = 'absolute'), + (i.style.left = '50%'), + (i.style.top = '50%'), + (i.style.marginTop = '-30px'), + (i.style.marginLeft = '-150px'), + (a.id = '_preloadText'), + (a.style.textAlign = 'center'), + (a.innerHTML = 'Loading resources: '), + (s.id = '_preloadCount'), + (s.style.textAlign = 'center'), + (s.innerHTML = '0 / ' + e.length + '
'), + i.appendChild(a), + i.appendChild(s), + u && + void 0 !== u.max && + ((u.id = '_preloadBar'), + (u.style.width = '300px'), + (u.style.height = '30px'), + (u.max = 1), + (u.value = 0), + i.appendChild(u)), + document.body.appendChild(i), + (i.style.display = 'block')); + for ( + var c = function (t) { + var a = t.target; + (r++, + t.preventDefault(), + t.stopPropagation(), + a.removeEventListener('load', c, !0), + a.removeEventListener('error', c, !0), + 'error' === t.type && console.log('Error pre-loading image: ' + a.src), + o.progress && + ((s.innerHTML = r + ' / ' + e.length + '
'), u && void 0 !== u.max && (u.value = r / e.length)), + o.copy && tmbObjs.images.push(a), + o.pipeline && r < e.length && d(n.shift()), + r === e.length && (o.progress && document.body.removeChild(i), o.callBack && o.callBack())); + }, + d = function (e) { + var t = new Image(); + (t.addEventListener('load', c, !0), t.addEventListener('error', c, !0), (t.id = e), (t.src = e)); + }; + l > 0; + ) + (l--, d(n.shift())); +} +function chooseInput(e, t) { + function n(r) { + var a; + ((o = ''), + r.preventDefault(), + r.stopPropagation(), + 'keydown' === r.type + ? e.keyboard + ? (a = 'keys') + : (o = 'Keyboard') + : 'pointerdown' === r.type || 'MSPointerDown' === r.type + ? 'touch' === r.pointerType || r.pointerType === r.MSPOINTER_TYPE_TOUCH + ? e.touch + ? (a = 'taps') + : (o = 'Touch') + : 'mouse' === r.pointerType || r.pointerType === r.MSPOINTER_TYPE_MOUSE + ? e.mouse + ? (a = 'clicks') + : (o = 'Mouse/Trackpad') + : ('pen' !== r.pointerType && r.pointerType !== r.MSPOINTER_TYPE_PEN) || + (e.touch ? (a = 'taps') : (o = 'Pen')) + : 'touchstart' === r.type + ? e.touch + ? (a = 'taps') + : (o = 'Touch') + : 'mousedown' === r.type && (e.mouse ? (a = 'clicks') : (o = 'Mouse/Trackpad')), + o && (o += ' not valid for this test: try another input.'), + (document.getElementById('errMsg').innerHTML = o), + a && + (document.body.removeEventListener('keydown', n, !0), + hasTouch && document.body.removeEventListener('touchstart', n, !0), + document.body.removeEventListener('mousedown', n, !0), + hasPointer && + (window.PointerEvent + ? document.body.removeEventListener('pointerdown', n, !0) + : window.MSPointerEvent && document.body.removeEventListener('MSPointerDown', n, !0)), + 'touchAction' in document.body.style + ? (document.body.style.touchAction = i) + : 'msTouchAction' in document.body.style && (document.body.style.msTouchAction = i), + document.getElementById('centeredTable').remove(), + t && t(a))); + } + var r = '', + o = ' ', + i = ''; + if (null === e || 'object' != typeof e) throw new TypeError('chooseInput: missing or invalid inputTypes object.'); + ((r += '

Please choose how you will respond in this test:

'), + e.keyboard && (r += '- To use a keyboard, press any key now.

'), + e.mouse && (r += '- To use a mouse or track pad, click now.

'), + e.touch && (r += '- To use a touch screen, touch the screen now.

'), + 'touchAction' in document.body.style + ? ((i = document.body.style.touchAction), (document.body.style.touchAction = 'none')) + : 'msTouchAction' in document.body.style && + ((i = document.body.style.msTouchAction), (document.body.style.msTouchAction = 'none')), + document.body.addEventListener('keydown', n, !0), + document.body.addEventListener('mousedown', n, !0), + hasTouch && document.body.addEventListener('touchstart', n, !0), + hasPointer && + (window.PointerEvent + ? document.body.addEventListener('pointerdown', n, !0) + : window.MSPointerEvent && document.body.addEventListener('MSPointerDown', n, !0)), + (document.body.innerHTML += + "
" + + r + + "" + + o + + '
')); +} +function getKeyboardInput(e, t, n, r) { + if (!(e.highlight === !0 || e instanceof Array || 'any' === e)) + throw new TypeError('getKeyboardInput: invalid acceptedKeys parameter'); + var o = e.highlight === !0; + r && setTimeout(disableKeyboard, r); + var i = now(), + a = null, + s = 0, + u = function () { + if (((a = null), o)) + for (var t in e) e.hasOwnProperty(t) && 'highlight' !== t && (e[t].style.border = '5px solid transparent'); + }; + return ( + (document.onkeydown = function (t) { + s = now() - i; + var t = t || window.event, + n = t.charCode || t.keyCode, + r = codeToKey(n); + return ( + ('any' === e || (o && r in e) || (e instanceof Array && e.includes(r))) && + (a && a !== r + ? (u(), alert('Please press only one key!\n\nYour response was not recorded. Please try again.'), u()) + : ((a = r), o && e[r] && (e[r].style.border = '5px solid #afd6fd'))), + !1 + ); + }), + (document.onkeyup = function (r) { + var r = r || window.event, + i = r.charCode || r.keyCode, + l = codeToKey(i); + if ('any' === e || (o && l in e) || (e instanceof Array && e.contains(l))) { + r.preventDefault ? (r.preventDefault(), r.stopPropagation()) : ((r.returnValue = !1), (r.cancelBubble = !0)); + var c = function () { + if (l !== a) return !1; + o && (e[l].style.border = '5px solid transparent'); + var r = { response: l, rt: s }; + return (u(), n ? t(r, n) : t(r), !1); + }; + o ? window.setTimeout(c, 300) : c(); + } + }), + !1 + ); +} +function simulateMobileMouseEvent(e, t) { + var n = document.createEvent('MouseEvents'), + r = e.changedTouches[0]; + (n.initMouseEvent( + t, + !0, + !0, + window, + 1, + r.screenX, + r.screenY, + r.clientX, + r.clientY, + e.ctrlKey, + e.altKey, + e.shiftKey, + e.metaKey, + 0, + null + ), + e.target.dispatchEvent(n)); +} +function simulateKeyEvent(e, t) { + var n = null; + if (document.createEvent) { + try { + ((n = document.createEvent('KeyEvents')), n.initKeyEvent(e, !0, !0, window, !1, !1, !1, !1, t, 0)); + } catch (r) { + try { + n = document.createEvent('Events'); + } catch (o) { + n = document.createEvent('UIEvents'); + } finally { + (n.initEvent(e, !0, !0), + (n.view = window), + (n.altKey = !1), + (n.ctrlKey = !1), + (n.shiftKey = !1), + (n.metaKey = !1), + (n.keyCode = t), + (n.charCode = 0)); + } + } + document.dispatchEvent(n); + } else { + if (!document.createEventObject) throw 'simulateKeyEvent(): No event simulation framework present.'; + ((n = document.createEventObject()), + (n.bubbles = !0), + (n.cancelable = !0), + (n.view = window), + (n.ctrlKey = !1), + (n.altKey = !1), + (n.shiftKey = !1), + (n.metaKey = !1), + (n.keyCode = t), + document.fireEvent('on' + e, n)); + } +} +function codeToKey(e) { + return keyboardCodes[e] || 'nokey'; +} +function keyToCode(e) { + return keyboardKeys[e] || 0; +} +function disableKeyboard() { + ((document.onkeyup = null), (document.onkeydown = null)); +} +function disableTouch(e) { + if ('document' === e) document.ontouchend = null; + else for (var t = 0; t < e.length; t++) ((e[t].ontouchstart = null), (e[t].ontouchend = null)); +} +function disableSelect() { + var e = document.body.style; + 'undefined' != typeof e.webkitUserSelect + ? (e.webkitUserSelect = 'none') + : 'undefined' != typeof e.MozUserSelect + ? (e.MozUserSelect = 'none') + : 'undefined' != typeof e.msUserSelect + ? (e.msUserSelect = 'none') + : 'undefined' != typeof e.oUserSelect + ? (e.oUserSelect = 'none') + : 'undefined' != typeof e.userSelect + ? (e.userSelect = 'none') + : 'undefined' != typeof document.onselectstart && + (document.onselectstart = function () { + return !1; + }); +} +function disableRightClick() { + 'undefined' != typeof document.oncontextmenu && + (document.oncontextmenu = function () { + return !1; + }); +} +function disableDrag() { + 'undefined' != typeof document.ondragstart && + (document.ondragstart = function () { + return !1; + }); +} +function disableElasticScrolling() { + 'undefined' != typeof document.ontouchmove && + (document.ontouchmove = function (e) { + (e.preventDefault(), e.stopPropagation()); + }); +} +function disableDoubleTapZoom() { + 'touchAction' in document.body.style + ? (document.body.style.touchAction = 'manipulation') + : 'msTouchAction' in document.body.style && (document.body.style.msTouchAction = 'manipulation'); +} +function getWindowHeight() { + var e = 0; + return ( + self.innerHeight + ? (e = self.innerHeight) + : document.documentElement && document.documentElement.clientHeight + ? (e = document.documentElement.clientHeight) + : document.body && (e = document.body.clientHeight), + e + ); +} +function getWindowWidth() { + var e = 0; + return ( + self.innerWidth + ? (e = self.innerWidth) + : document.documentElement && document.documentElement.clientWidth + ? (e = document.documentElement.clientWidth) + : document.body && (e = document.body.clientWidth), + e + ); +} +function getAspectRatio() { + return screen.height < screen.width ? screen.width / screen.height : screen.height / screen.width; +} +function getBoundingClientRectWithScroll(e) { + var t = e.getBoundingClientRect(), + n = document.body, + r = document.documentElement, + o = window.pageYOffset || r.scrollTop || n.scrollTop, + i = window.pageXOffset || r.scrollLeft || n.scrollLeft, + a = r.clientTop || n.clientTop || 0, + s = r.clientLeft || n.clientLeft || 0, + u = t.top + o - a, + l = t.left + i - s, + c = t.right + i - s, + d = t.bottom + o - a, + f = t.bottom - t.top, + m = t.right - t.left; + return { + top: Math.round(u), + left: Math.round(l), + right: Math.round(c), + bottom: Math.round(d), + height: Math.round(f), + width: Math.round(m) + }; +} +function regularPolygon(e, t, n, r, o) { + if (!(3 > e)) { + var i = [], + a = (2 * Math.PI) / e; + o = (o * Math.PI) / 180; + for (var s = 0; e > s; s++) i.push({ x: t + r * Math.cos(s * a + o), y: n - r * Math.sin(s * a + o) }); + return i; + } +} +function svgPathString(e, t) { + var n; + n = 'M' + e[0].x + ' ' + e[0].y + 'L'; + for (var r = 1; r < e.length; r++) n = n + e[r].x + ' ' + e[r].y + ' '; + return (t && (n += 'Z'), n); +} +function randInt(e, t) { + return t ? Math.floor(Math.random() * (t - e + 1)) + e : ((e = e || 2), Math.floor(Math.random() * e)); +} +function randSign() { + return Math.random() < 0.5 ? -1 : 1; +} +function combinations(e, t) { + var n, + r, + o, + i, + a = []; + for (n = 0; n < e.length; n++) + if (1 === t) a.push([e[n]]); + else + for (o = combinations(e.slice(n + 1, e.length), t - 1), r = 0; r < o.length; r++) + ((i = o[r]), i.unshift(e[n]), a.push(i)); + return a; +} +function range(e, t) { + for (var n = [], r = e; t >= r; r++) n.push(r); + return n; +} +function linSpace(e, t, n) { + if (('undefined' == typeof n && (n = Math.max(Math.round(t - e) + 1, 1)), 2 > n)) return 1 === n ? [e] : []; + var r, + o = new Array(n); + for (n--, r = n; r >= 0; r--) o[r] = (r * t + (n - r) * e) / n; + return o; +} +function isEven(e) { + return e === parseFloat(e) ? !(e % 2) : void 0; +} +function wrapRads(e) { + for (; e > Math.PI; ) e -= 2 * Math.PI; + for (; e < -Math.PI; ) e += 2 * Math.PI; + return e; +} +function sizeToDegrees(e, t) { + return ((t = t || 57.294), (2 * Math.atan2(e, 2 * t) * 180) / Math.PI); +} +function degreesToSize(e, t) { + return ((t = t || 57.294), 2 * t * Math.tan((e * Math.PI) / 360)); +} +function euclidDistance(e, t, n, r) { + var o = e - n, + i = t - r; + return Math.sqrt(o * o + i * i); +} +function euclidDistanceSquared(e, t, n, r) { + var o, i; + return ((o = e - n), (i = t - r), o * o + i * i); +} +function vecPvector(e, t) { + var n = {}; + return ((n.x = t.x - e.x), (n.y = t.y - e.y), n); +} +function vecLength(e) { + return Math.sqrt(e.x * e.x + e.y * e.y); +} +function vecAngle(e) { + var t = Math.atan2(e.y, e.x); + return wrapRads(t); +} +function vecDotProduct(e, t) { + return e.x * t.x + e.y * t.y; +} +function vecCrossProduct(e, t) { + return e.x * t.y - e.y * t.x; +} +function vecAngleBetween(e, t) { + var n = Math.atan2(t.y, t.x) - Math.atan2(e.y, e.x); + return wrapRads(n); +} +function segmentsIntersect(e, t, n, r) { + function o(e, t) { + return e.x === t.x && e.y === t.y; + } + function i() { + for (var e = arguments[0], t = 1; t < arguments.length; t += 1) if (arguments[t] !== e) return !1; + return !0; + } + var a = vecPvector(e, n), + s = vecPvector(e, t), + u = vecPvector(n, r), + l = vecCrossProduct(s, u), + c = vecCrossProduct(a, s); + if (0 === l) { + if (0 === c) { + if ( + !i(n.x - e.x < 0, n.x - t.x < 0, r.x - e.x < 0, r.x - t.x < 0) || + !i(n.y - e.y < 0, n.y - t.y < 0, r.y - e.y < 0, r.y - t.y < 0) + ) + return 1; + if (o(e, n) || o(e, r) || o(t, n) || o(t, r)) return 2; + } + return 0; + } + var d = vecCrossProduct(a, u), + f = c / l, + m = d / l; + return (0 !== m && 1 !== m) || (0 !== f && 1 !== f) ? (m >= 0 && 1 >= m && f >= 0 && 1 >= f ? 4 : 0) : 3; +} +function pointSegmentDistance(e, t, n) { + function r(e, t) { + var n = e.x - t.x, + r = e.y - t.y; + return n * n + r * r; + } + var o = r(t, n); + if (0 === o) return Math.sqrt(r(e, t)); + var i = ((e.x - t.x) * (n.x - t.x) + (e.y - t.y) * (n.y - t.y)) / o; + return 0 > i + ? Math.sqrt(r(e, t)) + : i > 1 + ? Math.sqrt(r(e, n)) + : Math.sqrt(r(e, { x: t.x + i * (n.x - t.x), y: t.y + i * (n.y - t.y) })); +} +function polygonIsComplex(e) { + var t, n; + if ((n = e.length) > 2) { + for (var r = 1; n - 1 > r; r++) + for (var o = 0; r > o; o++) + if (((t = segmentsIntersect(e[o], e[o + 1], e[r], e[r + 1])), 0 !== t && 3 !== t)) return [t, o, r]; + for (o = 0; n - 1 > o; o++) + if (((t = segmentsIntersect(e[o], e[o + 1], e[n - 1], e[0])), 0 !== t && 3 !== t)) return [t, o, n - 1]; + } + return !1; +} +function autoCorr(e, t) { + var n, + r, + o, + i, + a, + s = 0, + u = 0, + l = []; + if (1 > t || t > e.length - 1) throw new TypeError("'hiLag' must be positive and less than 'series.length'."); + for (i = e.slice(), o = i.length, a = i.average(), n = 0; o > n; n++) ((i[n] = i[n] - a), (s += i[n] * i[n])); + for (l[0] = 1, r = 1; t + 1 > r; r++) { + for (u = 0, n = 0; o - r - 1 > n; n++) u += i[n] * i[n + r]; + l[r] = u / s; + } + return l; +} +function getTimerGrain(e, t) { + function n() { + var u, l, c, d, f; + for (c = a, f = s.length + 1, l = u = now(); c; ) ((d = now()), (s[f] = d - l) && (c--, f++, (l = d))); + ((r += l - u), (o += a), o === e ? ((d = s.median().round(7)), t(d)) : (o === e - i && (a = i), setImmediate(n))); + } + var r, + o, + i, + a, + s = []; + e && t + ? ((r = o = 0), e > 100 ? ((a = 100), (i = e % 100)) : (a = e), setImmediate(n)) + : console.log("getTimerGrain needs how many 'ticks' to measure and a 'callBack' function to return the result."); +} +function getFrameTime(e, t) { + function n() { + ((r = o), + (o = now()), + (r = o - r), + i.push(r), + e ? (e--, requestAnimationFrame(n)) : ((r = i.median().round(3)), t(r))); + } + var r, + o, + i = []; + e && t + ? requestAnimationFrame(function () { + ((o = now()), requestAnimationFrame(n)); + }) + : console.log("getFrameTime needs how many 'frames' to measure and a 'callback' function to return the result."); +} +function chainTimeouts() { + var e = arguments.length, + t = arguments[0]; + if ((1 === e && t instanceof Array && ((arguments = t), (e = arguments.length), (t = arguments[0])), e % 2 === 0)) + throw new Error('chainTimeouts(): number of arguments must be odd'); + t(); + for (var n = [], r = 2, o = arguments[1]; e > r; r += 2, o += arguments[r - 1]) n.push(setTimeout(arguments[r], o)); + return n; +} +function clearChainTimeouts(e) { + for (var t = 0, n = e.length; n > t; t++) clearTimeout(e[t]); +} +function getAllCookies() { + var e = {}; + if (document.cookie && '' != document.cookie) + for (var t = document.cookie.split('; '), n = 0; n < t.length; n++) { + var r = t[n].split(/=(.+)?/); + e[decodeURIComponent(r[0])] = decodeURIComponent(r[1]); + } + return e; +} +function createCookie(e, t, n, r, o, i) { + if (!e) return !1; + if (((t = t ? t : ''), void 0 !== n)) { + var a = new Date(); + (a.setTime(a.getTime() + 24 * n * 60 * 60 * 1e3), (n = '; expires=' + a.toUTCString())); + } else n = '; expires=0'; + ((r = r ? '; path=' + r : '; path=/'), + (o = o ? '; domain=' + o : ''), + (i = i || 'https:' === location.protocol ? ';secure' : ''), + (document.cookie = e + '=' + t + n + r + o + i)); +} +function readCookie(e) { + for (var t = e + '=', n = document.cookie.split(';'), r = 0; r < n.length; r++) { + for (var o = n[r]; ' ' === o.charAt(0); ) o = o.substring(1, o.length); + if (0 === o.indexOf(t)) return o.substring(t.length, o.length); + } + return null; +} +function eraseCookie(e, t, n) { + ((t = t ? '; path=' + t : ''), (n = n ? '; domain=' + n : ''), createCookie(e, '', -1, t, n)); +} +function safeDecode(e) { + return ((e = e.replace(/\!/g, '/').replace(/-/g, '+').replace(/\./g, '=')), atob(e)); +} +function safeEncode(e) { + return ((e = btoa(e)), (e = e.replace(/\//g, '!').replace(/\+/g, '-').replace(/\=/g, '.'))); +} +function getPastResults(e) { + return RawDeflate.inflate(safeDecode(readCookie('t.' + e))); +} +function insertAfter(e, t) { + e.parentNode.insertBefore(t, e.nextSibling); +} +function generateForm(survey, node, action, method, buttonText) { + function tag(e, t) { + var n = '<' + e + ' ', + r = []; + for (var o in t) t.hasOwnProperty(o) && 'content' !== o && r.push(o + '="' + t[o] + '"'); + return ((n += r.join(' ') + '>'), 'undefined' != typeof t.content && (n += t.content), (n += '')); + } + var self = generateForm; + 'undefined' == typeof self.numForms ? (self.numForms = 1) : self.numForms++; + var formId = '__form' + (self.numForms - 1); + ((method = void 0 === method ? 'POST' : method), (onsubmit = "alert('blart');")); + for ( + var str = "
    ", a = 0, b; + (b = survey[a]); + a++ + ) + if ('textdiv' !== b.type) { + switch ( + ('' !== b.question && + ((str += 'hidden' !== b.type ? '
  1. ' : ''), + (str += + "

    " + + b.question + + "
    ")), + b.type) + ) { + case '': + str += tag('input', { type: 'text', id: b.name }); + break; + case 'text': + str += tag('input', { type: 'text', maxlength: b.length, id: b.name, size: b.length }); + break; + case 'hidden': + ((b.optional = !0), (b.question = b.name), (str += tag('input', { type: 'hidden', id: b.name }))); + break; + case 'checkbox': + case 'radio': + b.options.map(function (e, t) { + var n = b.name + '[' + t + ']'; + str += tag('span', { + class: 'undefined' != typeof b.subtype ? 'zen_' + b.subtype : 'zen_' + b.type, + content: + tag('input', { + type: b.type, + name: b.name, + id: n, + value: 'undefined' != typeof b.values ? b.values[t] : b.options[t], + class: 'zen_' + b.type + }) + tag('label', { for: n, content: e }) + }); + }); + break; + case 'dropdown': + ((str += "')); + break; + case 'textarea': + str += tag('textarea', { + name: b.name, + rows: b.rows, + cols: b.cols, + id: b.name, + class: 'undefined' != typeof b.subtype ? ' zen_' + b.subtype : '' + }); + } + ((str += '

    '), (str += 'hidden' !== b.type ? '
  2. ' : '')); + } else + ((b.optional = !0), + (str += tag('div', { id: b.name, size: b.length, content: b.content, class: 'zen_infoblock' }))); + ((str = buttonText + ? str + + "
    ' + : str + + "
    "), + (str += ""), + (node.innerHTML += str), + (getID(formId).validate = function () { + var results = [], + score = 0, + finalCheck = !0, + error = !1, + form = getID(formId); + survey.map(function (item) { + var id = item.name, + el, + value, + answer; + if ('checkbox' === item.type || 'radio' === item.type) { + value = []; + for (var i = 0, len = item.options.length; len > i; i++) { + var option = getID(item.name + '[' + i + ']'); + option.checked && (value.push(option.value), item.values && (score += 1 * option.value)); + } + ('radio' === item.type + ? ((value = value.shift()), + (item.validate = function (e) { + return e; + })) + : (item.validate = function (e) { + return e.length; + }), + (answer = value), + (el = getID(item.name + '[' + (i - 1) + ']'))); + } else if ('dropdown' === item.type) { + for (var i = 0, len = item.options.length; len > i; i++) { + var option = getID(item.name + '[' + i + ']'); + option.selected && + ((answer = option.value), item.values && ((answer = 1 * option.value), (score += 1 * option.value))); + } + ((el = form[item.name]), + (value = getID(item.name).options[0].selected), + (value = !value), + (item.validate = function (e) { + return e; + })); + } else + ((value = []), + (el = form[item.name] ? form[item.name] : getID(item.name)), + (value = el.value), + (answer = el.value)); + if (item.optional) { + var ans = new Object(); + (eval('ans.zen_' + item.name + '= answer'), results.push(ans)); + } else { + var errorEl = getID(id + '.err'); + errorEl || + ((errorEl = document.createElement('span')), + (errorEl.id = id + '.err'), + (errorEl.className = 'zen_error'), + insertAfter(getID('zen_' + id + '_input'), errorEl)); + var notBlank = function (e) { + return !('' === e); + }, + validate = item.validate || notBlank; + if (validate(value)) { + errorEl.innerHTML = ''; + var ans = new Object(); + (eval('ans.zen_' + item.name + '= answer'), results.push(ans)); + } else ((error = !0), (finalCheck = !1), (errorEl.innerHTML = 'required')); + } + }); + var errorTot = getID(formId + '.err'); + return ( + errorTot || + ((errorTot = document.createElement('span')), + (errorTot.id = formId + '.err'), + (errorTot.className = 'zen_err_flag'), + insertAfter(getID('zen_submit'), errorTot)), + (getID('data').value = JSON.stringify(results)), + (getID('score').value = isNaN(score) ? 0 : score), + finalCheck + ? void getID(formId).submit() + : ((errorTot.innerHTML = + 'There is a problem with your form submission. Please check that you have filled out all required fields correctly.'), + finalCheck) + ); + })); +} +(Date.now || + (Date.now = function () { + return new Date().getTime(); + }), + (function () { + 'use strict'; + for (var e = ['webkit', 'moz'], t = 0; t < e.length && !window.requestAnimationFrame; ++t) { + var n = e[t]; + ((window.requestAnimationFrame = window[n + 'RequestAnimationFrame']), + (window.cancelAnimationFrame = + window[n + 'CancelAnimationFrame'] || window[n + 'CancelRequestAnimationFrame'])); + } + if ( + /iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) || + !window.requestAnimationFrame || + !window.cancelAnimationFrame + ) { + var r = 0; + ((window.requestAnimationFrame = function (e) { + var t = Date.now(), + n = Math.max(r + 16, t); + return setTimeout(function () { + e((r = n)); + }, n - t); + }), + (window.cancelAnimationFrame = clearTimeout)); + } + })(), + (function () { + function e(e) { + this.message = e; + } + var t = 'undefined' != typeof exports ? exports : this, + n = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + ((e.prototype = new Error()), + (e.prototype.name = 'InvalidCharacterError'), + t.btoa || + (t.btoa = function (t) { + for ( + var r, o, i = String(t), a = 0, s = n, u = ''; + i.charAt(0 | a) || ((s = '='), a % 1); + u += s.charAt(63 & (r >> (8 - (a % 1) * 8))) + ) { + if (((o = i.charCodeAt((a += 0.75))), o > 255)) + throw new e("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range."); + r = (r << 8) | o; + } + return u; + }), + t.atob || + (t.atob = function (t) { + var r = String(t).replace(/=+$/, ''); + if (r.length % 4 == 1) throw new e("'atob' failed: The string to be decoded is not correctly encoded."); + for ( + var o, i, a = 0, s = 0, u = ''; + (i = r.charAt(s++)); + ~i && ((o = a % 4 ? 64 * o + i : i), a++ % 4) ? (u += String.fromCharCode(255 & (o >> ((-2 * a) & 6)))) : 0 + ) + i = n.indexOf(i); + return u; + })); + })()); +var base64decode = atob, + base64encode = btoa; +(document.getElementsByClassName || + (document.getElementsByClassName = function (e) { + for ( + var t = [], + n = document, + r = n.getElementsByTagName('*'), + o = r.length, + i = new RegExp('(^|\\s)' + e + '(\\s|$)'), + a = 0, + s = 0; + o > a; + a++ + ) + i.test(r[a].className) && ((t[s] = r[a]), s++); + return t; + }), + Object.prototype.hasOwnProperty || + (Object.prototype.hasOwnProperty = function (e) { + var t = this.__proto__ || this.constructor.prototype; + return e in this && (!(e in t) || t[e] !== this[e]); + }), + 'function' != typeof Object.create && + (Object.create = (function () { + var e = function () {}; + return function (t) { + if (arguments.length > 1) throw Error('Second argument not supported'); + if ('object' != typeof t) throw TypeError('Argument must be an object'); + e.prototype = t; + var n = new e(); + return ((e.prototype = null), n); + }; + })()), + Object.keys || + (Object.keys = (function () { + 'use strict'; + var e = Object.prototype.hasOwnProperty, + t = !{ toString: null }.propertyIsEnumerable('toString'), + n = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ], + r = n.length; + return function (o) { + if ('object' != typeof o && ('function' != typeof o || null === o)) + throw new TypeError('Object.keys called on non-object'); + var i, + a, + s = []; + for (i in o) e.call(o, i) && s.push(i); + if (t) for (a = 0; r > a; a++) e.call(o, n[a]) && s.push(n[a]); + return s; + }; + })()), + Function.prototype.bind || + (Function.prototype.bind = function (e) { + if ('function' != typeof this) + throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); + var t = Array.prototype.slice.call(arguments, 1), + n = this, + r = function () {}, + o = function () { + return n.apply(this instanceof r ? this : e, t.concat(Array.prototype.slice.call(arguments))); + }; + return ((r.prototype = this.prototype), (o.prototype = new r()), o); + }), + Array.isArray || + (Array.isArray = function (e) { + return '[object Array]' === Object.prototype.toString.call(e); + }), + Array.prototype.indexOf || + (Array.prototype.indexOf = function (e, t) { + if (void 0 === this || null === this) throw new TypeError('"this" is null or not defined'); + var n = this.length >>> 0; + for (t = +t || 0, Math.abs(t) === 1 / 0 && (t = 0), 0 > t && ((t += n), 0 > t && (t = 0)); n > t; t++) + if (this[t] === e) return t; + return -1; + }), + Array.prototype.lastIndexOf || + (Array.prototype.lastIndexOf = function (e) { + 'use strict'; + if (null == this) throw new TypeError(); + var t, + n, + r = Object(this), + o = r.length >>> 0; + if (0 === o) return -1; + for ( + t = o, + arguments.length > 1 && + ((t = Number(arguments[1])), + t != t ? (t = 0) : 0 != t && t != 1 / 0 && t != -(1 / 0) && (t = (t > 0 || -1) * Math.floor(Math.abs(t)))), + n = t >= 0 ? Math.min(t, o - 1) : o - Math.abs(t); + n >= 0; + n-- + ) + if (n in r && r[n] === e) return n; + return -1; + }), + Array.prototype.every || + (Array.prototype.every = function (e) { + 'use strict'; + if (void 0 === this || null === this) throw new TypeError(); + var t = Object(this), + n = t.length >>> 0; + if ('function' != typeof e) throw new TypeError(); + for (var r = arguments.length >= 2 ? arguments[1] : void 0, o = 0; n > o; o++) + if (o in t && !e.call(r, t[o], o, t)) return !1; + return !0; + }), + Array.prototype.some || + (Array.prototype.some = function (e) { + 'use strict'; + if (void 0 === this || null === this) throw new TypeError(); + var t = Object(this), + n = t.length >>> 0; + if ('function' != typeof e) throw new TypeError(); + for (var r = arguments.length >= 2 ? arguments[1] : void 0, o = 0; n > o; o++) + if (o in t && e.call(r, t[o], o, t)) return !0; + return !1; + }), + Array.prototype.forEach || + (Array.prototype.forEach = function (e) { + 'use strict'; + if (void 0 === this || null === this) throw new TypeError(); + var t = Object(this), + n = t.length >>> 0; + if ('function' != typeof e) throw new TypeError(); + for (var r = arguments.length >= 2 ? arguments[1] : void 0, o = 0; n > o; o++) o in t && e.call(r, t[o], o, t); + }), + Array.prototype.map || + (Array.prototype.map = function (e) { + 'use strict'; + if (void 0 === this || null === this) throw new TypeError(); + var t = Object(this), + n = t.length >>> 0; + if ('function' != typeof e) throw new TypeError(); + for (var r = new Array(n), o = arguments.length >= 2 ? arguments[1] : void 0, i = 0; n > i; i++) + i in t && (r[i] = e.call(o, t[i], i, t)); + return r; + }), + Array.prototype.filter || + (Array.prototype.filter = function (e) { + 'use strict'; + if (void 0 === this || null === this) throw new TypeError(); + var t = Object(this), + n = t.length >>> 0; + if ('function' != typeof e) throw new TypeError(); + for (var r = [], o = arguments.length >= 2 ? arguments[1] : void 0, i = 0; n > i; i++) + if (i in t) { + var a = t[i]; + e.call(o, a, i, t) && r.push(a); + } + return r; + }), + 'function' != typeof Array.prototype.reduce && + (Array.prototype.reduce = function (e, t) { + 'use strict'; + if (null === this || 'undefined' == typeof this) + throw new TypeError('Array.prototype.reduce called on null or undefined'); + if ('function' != typeof e) throw new TypeError(e + ' is not a function'); + var n, + r, + o = this.length >>> 0, + i = !1; + for (1 < arguments.length && ((r = t), (i = !0)), n = 0; o > n; ++n) + this.hasOwnProperty(n) && (i ? (r = e(r, this[n], n, this)) : ((r = this[n]), (i = !0))); + if (!i) throw new TypeError('Reduce of empty array with no initial value'); + return r; + }), + 'function' != typeof Array.prototype.reduceRight && + (Array.prototype.reduceRight = function (e, t) { + 'use strict'; + if (null === this || 'undefined' == typeof this) + throw new TypeError('Array.prototype.reduceRight called on null or undefined'); + if ('function' != typeof e) throw new TypeError(e + ' is not a function'); + var n, + r, + o = this.length >>> 0, + i = !1; + for (1 < arguments.length && ((r = t), (i = !0)), n = o - 1; n > -1; --n) + this.hasOwnProperty(n) && (i ? (r = e(r, this[n], n, this)) : ((r = this[n]), (i = !0))); + if (!i) throw new TypeError('Reduce of empty array with no initial value'); + return r; + }), + (function () { + 'use strict'; + var e = Array.prototype.slice; + try { + e.call(document.documentElement); + } catch (t) { + Array.prototype.slice = function (t, n) { + if ( + ((n = 'undefined' != typeof n ? n : this.length), '[object Array]' === Object.prototype.toString.call(this)) + ) + return e.call(this, t, n); + var r, + o, + i = [], + a = this.length, + s = t || 0; + s = s >= 0 ? s : a + s; + var u = n ? n : a; + if ((0 > n && (u = a + n), (o = u - s), o > 0)) + if (((i = new Array(o)), this.charAt)) for (r = 0; o > r; r++) i[r] = this.charAt(s + r); + else for (r = 0; o > r; r++) i[r] = this[s + r]; + return i; + }; + } + })(), + this.Element && + Element.prototype.attachEvent && + !Element.prototype.addEventListener && + (function () { + function e(e, t) { + Window.prototype[e] = HTMLDocument.prototype[e] = Element.prototype[e] = t; + } + function t() { + t.interval && + document.body && + ((t.interval = clearInterval(t.interval)), document.dispatchEvent(new CustomEvent('DOMContentLoaded'))); + } + (e('addEventListener', function (e, t) { + var n = this, + r = (n._c1_listeners = n._c1_listeners || {}), + o = (r[e] = r[e] || []); + (o.length || + n.attachEvent( + 'on' + e, + (o.event = function (e) { + var t = (n.document && n.document.documentElement) || + n.documentElement || { scrollLeft: 0, scrollTop: 0 }; + ((e.currentTarget = n), + (e.pageX = e.clientX + t.scrollLeft), + (e.pageY = e.clientY + t.scrollTop), + (e.preventDefault = function () { + e.returnValue = !1; + }), + (e.relatedTarget = e.fromElement || null), + (e.stopImmediatePropagation = function () { + ((l = !1), (e.cancelBubble = !0)); + }), + (e.stopPropagation = function () { + e.cancelBubble = !0; + }), + (e.target = e.srcElement || n), + (e.timeStamp = +new Date())); + var r = {}; + for (var i in e) r[i] = e[i]; + for (var a, s = 0, u = [].concat(o), l = !0; l && (a = u[s]); ++s) + for (var c, d = 0; (c = o[d]); ++d) + if (c == a) { + c.call(n, r); + break; + } + }) + ), + o.push(t)); + }), + e('removeEventListener', function (e, t) { + for ( + var n, r = this, o = (r._c1_listeners = r._c1_listeners || {}), i = (o[e] = o[e] || []), a = i.length - 1; + (n = i[a]); + --a + ) + if (n == t) { + i.splice(a, 1); + break; + } + !i.length && i.event && r.detachEvent('on' + e, i.event); + }), + e('dispatchEvent', function (e) { + var t = this, + n = e.type, + r = (t._c1_listeners = t._c1_listeners || {}), + o = (r[n] = r[n] || []); + try { + return t.fireEvent('on' + n, e); + } catch (i) { + return void (o.event && o.event(e)); + } + })); + try { + new window.CustomEvent('?'); + } catch (n) { + Object.defineProperty(Window.prototype, 'CustomEvent', { + get: function () { + var e = this; + return function (t, n) { + n = n || {}; + var r, + o = e.document.createEventObject(); + ((o.type = t), (o.returnValue = !n.cancelable), (o.cancelBubble = !n.bubbles)); + for (r in n) o[r] = n[r]; + return o; + }; + } + }); + } + ((t.interval = setInterval(t, 1)), window.addEventListener('load', t)); + })()); +try { + new window.CustomEvent('?'); +} catch (e) { + !(function () { + window.CustomEvent = function (e, t) { + var n; + t = t || { bubbles: !1, cancelable: !1, detail: void 0 }; + try { + ((n = document.createEvent('CustomEvent')), n.initCustomEvent(e, t.bubbles, t.cancelable, t.detail)); + } catch (r) { + ((n = document.createEvent('Event')), n.initEvent(e, t.bubbles, t.cancelable), (n.detail = t.detail)); + } + return n; + }; + })(); +} +('remove' in Element.prototype || + (Element.prototype.remove = function () { + this.parentNode && this.parentNode.removeChild(this); + }), + window.Node || + (window.Node = { + ELEMENT_NODE: 1, + ATTRIBUTE_NODE: 2, + TEXT_NODE: 3, + CDATA_SECTION_NODE: 4, + ENTITY_REFERENCE_NODE: 5, + ENTITY_NODE: 6, + PROCESSING_INSTRUCTION_NODE: 7, + COMMENT_NODE: 8, + DOCUMENT_NODE: 9, + DOCUMENT_TYPE_NODE: 10, + DOCUMENT_FRAGMENT_NODE: 11, + NOTATION_NODE: 12 + }), + 'function' != typeof Number.isInteger && + (Number.isInteger = function (e) { + return 'number' == typeof e && isFinite(e) && Math.floor(e) === e; + }), + String.prototype.trim || + (String.prototype.trim = function () { + return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); + }), + (function (e) { + var t = 32768, + n = 0, + r = 1, + o = 2, + i = 6, + a = !0, + s = 32768, + u = 64, + l = 8192, + c = 2 * t, + d = 3, + f = 258, + m = 16, + p = 8192, + h = 13; + (p > s && alert('error: zip_INBUFSIZ is too small'), + t << 1 > 1 << m && alert('error: zip_WSIZE is too large'), + h > m - 1 && alert('error: zip_HASH_BITS is too large'), + (8 > h || 258 != f) && alert('error: Code too clever')); + var y, + v, + b, + g, + w, + I, + E, + U, + T, + A, + k, + O, + x, + S, + M, + _, + C, + L, + P, + D, + N, + R, + j, + B, + z, + F, + q, + H, + W, + K, + X, + J, + Y, + G, + V, + $, + Z, + Q, + ee, + te, + ne, + re, + oe, + ie, + ae, + se, + ue, + le, + ce, + de, + fe, + me, + pe, + he, + ye, + ve, + be = p, + ge = 1 << h, + we = ge - 1, + Ie = t - 1, + Ee = 0, + Ue = 4096, + Te = f + d + 1, + Ae = t - Te, + ke = 1, + Oe = 15, + xe = 7, + Se = 29, + Me = 256, + _e = 256, + Ce = Me + 1 + Se, + Le = 30, + Pe = 19, + De = 16, + Ne = 17, + Re = 18, + je = 2 * Ce + 1, + Be = parseInt((h + d - 1) / d), + ze = null, + Fe = function () { + ((this.fc = 0), (this.dl = 0)); + }, + qe = function () { + ((this.dyn_tree = null), + (this.static_tree = null), + (this.extra_bits = null), + (this.extra_base = 0), + (this.elems = 0), + (this.max_length = 0), + (this.max_code = 0)); + }, + He = function (e, t, n, r) { + ((this.good_length = e), (this.max_lazy = t), (this.nice_length = n), (this.max_chain = r)); + }, + We = function () { + ((this.next = null), (this.len = 0), (this.ptr = new Array(l)), (this.off = 0)); + }, + Ke = new Array(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0), + Xe = new Array(0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13), + Je = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7), + Ye = new Array(16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15), + Ge = new Array( + new He(0, 0, 0, 0), + new He(4, 4, 8, 4), + new He(4, 5, 16, 8), + new He(4, 6, 32, 32), + new He(4, 4, 16, 16), + new He(8, 16, 32, 32), + new He(8, 16, 128, 128), + new He(8, 32, 128, 256), + new He(32, 128, 258, 1024), + new He(32, 258, 258, 4096) + ), + Ve = function (e) { + var t; + if ((e ? (1 > e ? (e = 1) : e > 9 && (e = 9)) : (e = i), (q = e), (g = !1), (j = !1), null == ze)) { + for ( + y = v = b = null, + ze = new Array(l), + U = new Array(c), + T = new Array(be), + A = new Array(s + u), + k = new Array(1 << m), + K = new Array(je), + t = 0; + je > t; + t++ + ) + K[t] = new Fe(); + for (X = new Array(2 * Le + 1), t = 0; 2 * Le + 1 > t; t++) X[t] = new Fe(); + for (J = new Array(Ce + 2), t = 0; Ce + 2 > t; t++) J[t] = new Fe(); + for (Y = new Array(Le), t = 0; Le > t; t++) Y[t] = new Fe(); + for (G = new Array(2 * Pe + 1), t = 0; 2 * Pe + 1 > t; t++) G[t] = new Fe(); + ((V = new qe()), + ($ = new qe()), + (Z = new qe()), + (Q = new Array(Oe + 1)), + (ee = new Array(2 * Ce + 1)), + (re = new Array(2 * Ce + 1)), + (oe = new Array(f - d + 1)), + (ie = new Array(512)), + (ae = new Array(Se)), + (se = new Array(Le)), + (ue = new Array(parseInt(p / 8)))); + } + }, + $e = function (e) { + ((e.next = y), (y = e)); + }, + Ze = function () { + var e; + return (null != y ? ((e = y), (y = y.next)) : (e = new We()), (e.next = null), (e.len = e.off = 0), e); + }, + Qe = function (e) { + return k[t + e]; + }, + et = function (e, n) { + return (k[t + e] = n); + }, + tt = function (e) { + ((ze[I + w++] = e), I + w == l && Lt()); + }, + nt = function (e) { + ((e &= 65535), l - 2 > I + w ? ((ze[I + w++] = 255 & e), (ze[I + w++] = e >>> 8)) : (tt(255 & e), tt(e >>> 8))); + }, + rt = function () { + ((M = ((M << Be) ^ (255 & U[N + d - 1])) & we), (_ = Qe(M)), (k[N & Ie] = _), et(M, N)); + }, + ot = function (e, t) { + Mt(t[e].fc, t[e].dl); + }, + it = function (e) { + return 255 & (256 > e ? ie[e] : ie[256 + (e >> 7)]); + }, + at = function (e, t, n) { + return e[t].fc < e[n].fc || (e[t].fc == e[n].fc && re[t] <= re[n]); + }, + st = function (e, t, n) { + var r; + for (r = 0; n > r && ve < ye.length; r++) e[t + r] = 255 & ye.charCodeAt(ve++); + return r; + }, + ut = function () { + var e; + for (e = 0; ge > e; e++) k[t + e] = 0; + if ( + ((F = Ge[q].max_lazy), + (H = Ge[q].good_length), + a || (W = Ge[q].nice_length), + (z = Ge[q].max_chain), + (N = 0), + (S = 0), + (B = st(U, 0, 2 * t)), + 0 >= B) + ) + return ((j = !0), void (B = 0)); + for (j = !1; Te > B && !j; ) ct(); + for (M = 0, e = 0; d - 1 > e; e++) M = ((M << Be) ^ (255 & U[e])) & we; + }, + lt = function (e) { + var t, + n, + r = z, + o = N, + i = D, + s = N > Ae ? N - Ae : Ee, + u = N + f, + l = U[o + i - 1], + c = U[o + i]; + D >= H && (r >>= 2); + do + if (((t = e), U[t + i] == c && U[t + i - 1] == l && U[t] == U[o] && U[++t] == U[o + 1])) { + ((o += 2), t++); + do; + while ( + U[++o] == U[++t] && + U[++o] == U[++t] && + U[++o] == U[++t] && + U[++o] == U[++t] && + U[++o] == U[++t] && + U[++o] == U[++t] && + U[++o] == U[++t] && + U[++o] == U[++t] && + u > o + ); + if (((n = f - (u - o)), (o = u - f), n > i)) { + if (((R = e), (i = n), a)) { + if (n >= f) break; + } else if (n >= W) break; + ((l = U[o + i - 1]), (c = U[o + i])); + } + } + while ((e = k[e & Ie]) > s && 0 != --r); + return i; + }, + ct = function () { + var e, + n, + r = c - B - N; + if (-1 == r) r--; + else if (N >= t + Ae) { + for (e = 0; t > e; e++) U[e] = U[e + t]; + for (R -= t, N -= t, S -= t, e = 0; ge > e; e++) ((n = Qe(e)), et(e, n >= t ? n - t : Ee)); + for (e = 0; t > e; e++) ((n = k[e]), (k[e] = n >= t ? n - t : Ee)); + r += t; + } + j || ((e = st(U, N + B, r)), 0 >= e ? (j = !0) : (B += e)); + }, + dt = function () { + for (; 0 != B && null == v; ) { + var e; + if ((rt(), _ != Ee && Ae >= N - _ && ((P = lt(_)), P > B && (P = B)), P >= d)) + if (((e = Ot(N - R, P - d)), (B -= P), F >= P)) { + P--; + do (N++, rt()); + while (0 != --P); + N++; + } else ((N += P), (P = 0), (M = 255 & U[N]), (M = ((M << Be) ^ (255 & U[N + 1])) & we)); + else ((e = Ot(0, 255 & U[N])), B--, N++); + for (e && (kt(0), (S = N)); Te > B && !j; ) ct(); + } + }, + ft = function () { + for (; 0 != B && null == v; ) { + if ( + (rt(), + (D = P), + (C = R), + (P = d - 1), + _ != Ee && F > D && Ae >= N - _ && ((P = lt(_)), P > B && (P = B), P == d && N - R > Ue && P--), + D >= d && D >= P) + ) { + var e; + ((e = Ot(N - 1 - C, D - d)), (B -= D - 1), (D -= 2)); + do (N++, rt()); + while (0 != --D); + ((L = 0), (P = d - 1), N++, e && (kt(0), (S = N))); + } else 0 != L ? (Ot(0, 255 & U[N - 1]) && (kt(0), (S = N)), N++, B--) : ((L = 1), N++, B--); + for (; Te > B && !j; ) ct(); + } + }, + mt = function () { + j || + ((O = 0), + (x = 0), + yt(), + ut(), + (v = null), + (w = 0), + (I = 0), + (L = 0), + 3 >= q ? ((D = d - 1), (P = 0)) : ((P = d - 1), (L = 0), (L = 0)), + (E = !1)); + }, + pt = function (e, t, n) { + var r; + return g || (mt(), (g = !0), 0 != B) + ? (r = ht(e, t, n)) == n + ? n + : E + ? r + : (3 >= q ? dt() : ft(), + 0 == B && (0 != L && Ot(0, 255 & U[N - 1]), kt(1), (E = !0)), + r + ht(e, r + t, n - r)) + : ((E = !0), 0); + }, + ht = function (e, t, n) { + var r, o, i; + for (r = 0; null != v && n > r; ) { + for (o = n - r, o > v.len && (o = v.len), i = 0; o > i; i++) e[t + r + i] = v.ptr[v.off + i]; + if (((v.off += o), (v.len -= o), (r += o), 0 == v.len)) { + var a; + ((a = v), (v = v.next), $e(a)); + } + } + if (r == n) return r; + if (w > I) { + for (o = n - r, o > w - I && (o = w - I), i = 0; o > i; i++) e[t + r + i] = ze[I + i]; + ((I += o), (r += o), w == I && (w = I = 0)); + } + return r; + }, + yt = function () { + var e, t, n, r, o; + if (0 == Y[0].dl) { + for ( + V.dyn_tree = K, + V.static_tree = J, + V.extra_bits = Ke, + V.extra_base = Me + 1, + V.elems = Ce, + V.max_length = Oe, + V.max_code = 0, + $.dyn_tree = X, + $.static_tree = Y, + $.extra_bits = Xe, + $.extra_base = 0, + $.elems = Le, + $.max_length = Oe, + $.max_code = 0, + Z.dyn_tree = G, + Z.static_tree = null, + Z.extra_bits = Je, + Z.extra_base = 0, + Z.elems = Pe, + Z.max_length = xe, + Z.max_code = 0, + n = 0, + r = 0; + Se - 1 > r; + r++ + ) + for (ae[r] = n, e = 0; e < 1 << Ke[r]; e++) oe[n++] = r; + for (oe[n - 1] = r, o = 0, r = 0; 16 > r; r++) for (se[r] = o, e = 0; e < 1 << Xe[r]; e++) ie[o++] = r; + for (o >>= 7; Le > r; r++) for (se[r] = o << 7, e = 0; e < 1 << (Xe[r] - 7); e++) ie[256 + o++] = r; + for (t = 0; Oe >= t; t++) Q[t] = 0; + for (e = 0; 143 >= e; ) ((J[e++].dl = 8), Q[8]++); + for (; 255 >= e; ) ((J[e++].dl = 9), Q[9]++); + for (; 279 >= e; ) ((J[e++].dl = 7), Q[7]++); + for (; 287 >= e; ) ((J[e++].dl = 8), Q[8]++); + for (wt(J, Ce + 1), e = 0; Le > e; e++) ((Y[e].dl = 5), (Y[e].fc = _t(e, 5))); + vt(); + } + }, + vt = function () { + var e; + for (e = 0; Ce > e; e++) K[e].fc = 0; + for (e = 0; Le > e; e++) X[e].fc = 0; + for (e = 0; Pe > e; e++) G[e].fc = 0; + ((K[_e].fc = 1), (pe = he = 0), (le = ce = de = 0), (fe = 0), (me = 1)); + }, + bt = function (e, t) { + for (var n = ee[t], r = t << 1; te >= r && (te > r && at(e, ee[r + 1], ee[r]) && r++, !at(e, n, ee[r])); ) + ((ee[t] = ee[r]), (t = r), (r <<= 1)); + ee[t] = n; + }, + gt = function (e) { + var t, + n, + r, + o, + i, + a, + s = e.dyn_tree, + u = e.extra_bits, + l = e.extra_base, + c = e.max_code, + d = e.max_length, + f = e.static_tree, + m = 0; + for (o = 0; Oe >= o; o++) Q[o] = 0; + for (s[ee[ne]].dl = 0, t = ne + 1; je > t; t++) + ((n = ee[t]), + (o = s[s[n].dl].dl + 1), + o > d && ((o = d), m++), + (s[n].dl = o), + n > c || + (Q[o]++, + (i = 0), + n >= l && (i = u[n - l]), + (a = s[n].fc), + (pe += a * (o + i)), + null != f && (he += a * (f[n].dl + i)))); + if (0 != m) { + do { + for (o = d - 1; 0 == Q[o]; ) o--; + (Q[o]--, (Q[o + 1] += 2), Q[d]--, (m -= 2)); + } while (m > 0); + for (o = d; 0 != o; o--) + for (n = Q[o]; 0 != n; ) + ((r = ee[--t]), r > c || (s[r].dl != o && ((pe += (o - s[r].dl) * s[r].fc), (s[r].fc = o)), n--)); + } + }, + wt = function (e, t) { + var n, + r, + o = new Array(Oe + 1), + i = 0; + for (n = 1; Oe >= n; n++) ((i = (i + Q[n - 1]) << 1), (o[n] = i)); + for (r = 0; t >= r; r++) { + var a = e[r].dl; + 0 != a && (e[r].fc = _t(o[a]++, a)); + } + }, + It = function (e) { + var t, + n, + r = e.dyn_tree, + o = e.static_tree, + i = e.elems, + a = -1, + s = i; + for (te = 0, ne = je, t = 0; i > t; t++) 0 != r[t].fc ? ((ee[++te] = a = t), (re[t] = 0)) : (r[t].dl = 0); + for (; 2 > te; ) { + var u = (ee[++te] = 2 > a ? ++a : 0); + ((r[u].fc = 1), (re[u] = 0), pe--, null != o && (he -= o[u].dl)); + } + for (e.max_code = a, t = te >> 1; t >= 1; t--) bt(r, t); + do + ((t = ee[ke]), + (ee[ke] = ee[te--]), + bt(r, ke), + (n = ee[ke]), + (ee[--ne] = t), + (ee[--ne] = n), + (r[s].fc = r[t].fc + r[n].fc), + re[t] > re[n] + 1 ? (re[s] = re[t]) : (re[s] = re[n] + 1), + (r[t].dl = r[n].dl = s), + (ee[ke] = s++), + bt(r, ke)); + while (te >= 2); + ((ee[--ne] = ee[ke]), gt(e), wt(r, a)); + }, + Et = function (e, t) { + var n, + r, + o = -1, + i = e[0].dl, + a = 0, + s = 7, + u = 4; + for (0 == i && ((s = 138), (u = 3)), e[t + 1].dl = 65535, n = 0; t >= n; n++) + ((r = i), + (i = e[n + 1].dl), + (++a < s && r == i) || + (u > a ? (G[r].fc += a) : 0 != r ? (r != o && G[r].fc++, G[De].fc++) : 10 >= a ? G[Ne].fc++ : G[Re].fc++, + (a = 0), + (o = r), + 0 == i ? ((s = 138), (u = 3)) : r == i ? ((s = 6), (u = 3)) : ((s = 7), (u = 4)))); + }, + Ut = function (e, t) { + var n, + r, + o = -1, + i = e[0].dl, + a = 0, + s = 7, + u = 4; + for (0 == i && ((s = 138), (u = 3)), n = 0; t >= n; n++) + if (((r = i), (i = e[n + 1].dl), !(++a < s && r == i))) { + if (u > a) { + do ot(r, G); + while (0 != --a); + } else + 0 != r + ? (r != o && (ot(r, G), a--), ot(De, G), Mt(a - 3, 2)) + : 10 >= a + ? (ot(Ne, G), Mt(a - 3, 3)) + : (ot(Re, G), Mt(a - 11, 7)); + ((a = 0), (o = r), 0 == i ? ((s = 138), (u = 3)) : r == i ? ((s = 6), (u = 3)) : ((s = 7), (u = 4))); + } + }, + Tt = function () { + var e; + for (Et(K, V.max_code), Et(X, $.max_code), It(Z), e = Pe - 1; e >= 3 && 0 == G[Ye[e]].dl; e--); + return ((pe += 3 * (e + 1) + 5 + 5 + 4), e); + }, + At = function (e, t, n) { + var r; + for (Mt(e - 257, 5), Mt(t - 1, 5), Mt(n - 4, 4), r = 0; n > r; r++) Mt(G[Ye[r]].dl, 3); + (Ut(K, e - 1), Ut(X, t - 1)); + }, + kt = function (e) { + var t, i, a, s; + if ( + ((s = N - S), + (ue[de] = fe), + It(V), + It($), + (a = Tt()), + (t = (pe + 3 + 7) >> 3), + (i = (he + 3 + 7) >> 3), + t >= i && (t = i), + t >= s + 4 && S >= 0) + ) { + var u; + for (Mt((n << 1) + e, 3), Ct(), nt(s), nt(~s), u = 0; s > u; u++) tt(U[S + u]); + } else + i == t + ? (Mt((r << 1) + e, 3), xt(J, Y)) + : (Mt((o << 1) + e, 3), At(V.max_code + 1, $.max_code + 1, a + 1), xt(K, X)); + (vt(), 0 != e && Ct()); + }, + Ot = function (e, t) { + if ( + ((A[le++] = t), + 0 == e ? K[t].fc++ : (e--, K[oe[t] + Me + 1].fc++, X[it(e)].fc++, (T[ce++] = e), (fe |= me)), + (me <<= 1), + 0 == (7 & le) && ((ue[de++] = fe), (fe = 0), (me = 1)), + q > 2 && 0 == (4095 & le)) + ) { + var n, + r = 8 * le, + o = N - S; + for (n = 0; Le > n; n++) r += X[n].fc * (5 + Xe[n]); + if (((r >>= 3), ce < parseInt(le / 2) && r < parseInt(o / 2))) return !0; + } + return le == p - 1 || ce == be; + }, + xt = function (e, t) { + var n, + r, + o, + i, + a = 0, + s = 0, + u = 0, + l = 0; + if (0 != le) + do + (0 == (7 & a) && (l = ue[u++]), + (r = 255 & A[a++]), + 0 == (1 & l) + ? ot(r, e) + : ((o = oe[r]), + ot(o + Me + 1, e), + (i = Ke[o]), + 0 != i && ((r -= ae[o]), Mt(r, i)), + (n = T[s++]), + (o = it(n)), + ot(o, t), + (i = Xe[o]), + 0 != i && ((n -= se[o]), Mt(n, i))), + (l >>= 1)); + while (le > a); + ot(_e, e); + }, + St = 16, + Mt = function (e, t) { + x > St - t ? ((O |= e << x), nt(O), (O = e >> (St - x)), (x += t - St)) : ((O |= e << x), (x += t)); + }, + _t = function (e, t) { + var n = 0; + do ((n |= 1 & e), (e >>= 1), (n <<= 1)); + while (--t > 0); + return n >> 1; + }, + Ct = function () { + (x > 8 ? nt(O) : x > 0 && tt(O), (O = 0), (x = 0)); + }, + Lt = function () { + if (0 != w) { + var e, t; + for (e = Ze(), null == v ? (v = b = e) : (b = b.next = e), e.len = w - I, t = 0; t < e.len; t++) + e.ptr[t] = ze[I + t]; + w = I = 0; + } + }, + Pt = function (e, t) { + var n, r; + ((ye = e), (ve = 0), 'undefined' == typeof t && (t = i), Ve(t)); + for (var o = new Array(1024), a = []; (n = pt(o, 0, o.length)) > 0; ) { + var s = new Array(n); + for (r = 0; n > r; r++) s[r] = String.fromCharCode(o[r]); + a[a.length] = s.join(''); + } + return ((ye = null), a.join('')); + }; + (e.RawDeflate || (e.RawDeflate = {}), (e.RawDeflate.deflate = Pt)); + })(this), + (function (e) { + var t, + n, + r, + o, + i, + a, + s, + u, + l, + c, + d, + f, + m, + p, + h, + y, + v, + b = 32768, + g = 0, + w = 9, + I = 6, + E = null, + U = new Array(0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535), + T = new Array( + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 13, + 15, + 17, + 19, + 23, + 27, + 31, + 35, + 43, + 51, + 59, + 67, + 83, + 99, + 115, + 131, + 163, + 195, + 227, + 258, + 0, + 0 + ), + A = new Array(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99), + k = new Array( + 1, + 2, + 3, + 4, + 5, + 7, + 9, + 13, + 17, + 25, + 33, + 49, + 65, + 97, + 129, + 193, + 257, + 385, + 513, + 769, + 1025, + 1537, + 2049, + 3073, + 4097, + 6145, + 8193, + 12289, + 16385, + 24577 + ), + O = new Array(0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13), + x = new Array(16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15), + S = function () { + ((this.next = null), (this.list = null)); + }, + M = function () { + ((this.e = 0), (this.b = 0), (this.n = 0), (this.t = null)); + }, + _ = function (e, t, n, r, o, i) { + ((this.BMAX = 16), (this.N_MAX = 288), (this.status = 0), (this.root = null), (this.m = 0)); + var a, + s, + u, + l, + c, + d, + f, + m, + p, + h, + y, + v, + b, + g, + w, + I, + E, + U = new Array(this.BMAX + 1), + T = new Array(this.BMAX + 1), + A = new M(), + k = new Array(this.BMAX), + O = new Array(this.N_MAX), + x = new Array(this.BMAX + 1); + for (E = this.root = null, d = 0; d < U.length; d++) U[d] = 0; + for (d = 0; d < T.length; d++) T[d] = 0; + for (d = 0; d < k.length; d++) k[d] = null; + for (d = 0; d < O.length; d++) O[d] = 0; + for (d = 0; d < x.length; d++) x[d] = 0; + ((s = t > 256 ? e[256] : this.BMAX), (p = e), (h = 0), (d = t)); + do (U[p[h]]++, h++); + while (--d > 0); + if (U[0] == t) return ((this.root = null), (this.m = 0), void (this.status = 0)); + for (f = 1; f <= this.BMAX && 0 == U[f]; f++); + for (m = f, f > i && (i = f), d = this.BMAX; 0 != d && 0 == U[d]; d--); + for (l = d, i > d && (i = d), g = 1 << f; d > f; f++, g <<= 1) + if ((g -= U[f]) < 0) return ((this.status = 2), void (this.m = i)); + if ((g -= U[d]) < 0) return ((this.status = 2), void (this.m = i)); + for (U[d] += g, x[1] = f = 0, p = U, h = 1, b = 2; --d > 0; ) x[b++] = f += p[h++]; + ((p = e), (h = 0), (d = 0)); + do 0 != (f = p[h++]) && (O[x[f]++] = d); + while (++d < t); + for (t = x[l], x[0] = d = 0, p = O, h = 0, c = -1, v = T[0] = 0, y = null, w = 0; l >= m; m++) + for (a = U[m]; a-- > 0; ) { + for (; m > v + T[1 + c]; ) { + if (((v += T[1 + c]), c++, (w = (w = l - v) > i ? i : w), (u = 1 << (f = m - v)) > a + 1)) + for (u -= a + 1, b = m; ++f < w && !((u <<= 1) <= U[++b]); ) u -= U[b]; + for (v + f > s && s > v && (f = s - v), w = 1 << f, T[1 + c] = f, y = new Array(w), I = 0; w > I; I++) + y[I] = new M(); + ((E = null == E ? (this.root = new S()) : (E.next = new S())), + (E.next = null), + (E.list = y), + (k[c] = y), + c > 0 && + ((x[c] = d), + (A.b = T[c]), + (A.e = 16 + f), + (A.t = y), + (f = (d & ((1 << v) - 1)) >> (v - T[c])), + (k[c - 1][f].e = A.e), + (k[c - 1][f].b = A.b), + (k[c - 1][f].n = A.n), + (k[c - 1][f].t = A.t))); + } + for ( + A.b = m - v, + h >= t + ? (A.e = 99) + : p[h] < n + ? ((A.e = p[h] < 256 ? 16 : 15), (A.n = p[h++])) + : ((A.e = o[p[h] - n]), (A.n = r[p[h++] - n])), + u = 1 << (m - v), + f = d >> v; + w > f; + f += u + ) + ((y[f].e = A.e), (y[f].b = A.b), (y[f].n = A.n), (y[f].t = A.t)); + for (f = 1 << (m - 1); 0 != (d & f); f >>= 1) d ^= f; + for (d ^= f; (d & ((1 << v) - 1)) != x[c]; ) ((v -= T[c]), c--); + } + ((this.m = T[1]), (this.status = 0 != g && 1 != l ? 1 : 0)); + }, + C = function () { + return y.length == v ? -1 : 255 & y.charCodeAt(v++); + }, + L = function (e) { + for (; e > s; ) ((a |= C() << s), (s += 8)); + }, + P = function (e) { + return a & U[e]; + }, + D = function (e) { + ((a >>= e), (s -= e)); + }, + N = function (e, r, o) { + var i, a, s; + if (0 == o) return 0; + for (s = 0; ; ) { + for (L(p), a = f.list[P(p)], i = a.e; i > 16; ) { + if (99 == i) return -1; + (D(a.b), (i -= 16), L(i), (a = a.t[P(i)]), (i = a.e)); + } + if ((D(a.b), 16 != i)) { + if (15 == i) break; + for (L(i), c = a.n + P(i), D(i), L(h), a = m.list[P(h)], i = a.e; i > 16; ) { + if (99 == i) return -1; + (D(a.b), (i -= 16), L(i), (a = a.t[P(i)]), (i = a.e)); + } + for (D(a.b), L(i), d = n - a.n - P(i), D(i); c > 0 && o > s; ) + (c--, (d &= b - 1), (n &= b - 1), (e[r + s++] = t[n++] = t[d++])); + if (s == o) return o; + } else if (((n &= b - 1), (e[r + s++] = t[n++] = a.n), s == o)) return o; + } + return ((u = -1), s); + }, + R = function (e, r, o) { + var i; + if (((i = 7 & s), D(i), L(16), (i = P(16)), D(16), L(16), i != (65535 & ~a))) return -1; + for (D(16), c = i, i = 0; c > 0 && o > i; ) (c--, (n &= b - 1), L(8), (e[r + i++] = t[n++] = P(8)), D(8)); + return (0 == c && (u = -1), i); + }, + j = function (e, t, n) { + if (null == E) { + var a, + s, + u = new Array(288); + for (a = 0; 144 > a; a++) u[a] = 8; + for (; 256 > a; a++) u[a] = 9; + for (; 280 > a; a++) u[a] = 7; + for (; 288 > a; a++) u[a] = 8; + if (((o = 7), (s = new _(u, 288, 257, T, A, o)), 0 != s.status)) + return (alert('HufBuild error: ' + s.status), -1); + for (E = s.root, o = s.m, a = 0; 30 > a; a++) u[a] = 5; + if (((i = 5), (s = new _(u, 30, 0, k, O, i)), s.status > 1)) + return ((E = null), alert('HufBuild error: ' + s.status), -1); + ((r = s.root), (i = s.m)); + } + return ((f = E), (m = r), (p = o), (h = i), N(e, t, n)); + }, + B = function (e, t, n) { + var r, + o, + i, + a, + s, + u, + l, + c, + d, + y = new Array(316); + for (r = 0; r < y.length; r++) y[r] = 0; + if ((L(5), (l = 257 + P(5)), D(5), L(5), (c = 1 + P(5)), D(5), L(4), (u = 4 + P(4)), D(4), l > 286 || c > 30)) + return -1; + for (o = 0; u > o; o++) (L(3), (y[x[o]] = P(3)), D(3)); + for (; 19 > o; o++) y[x[o]] = 0; + if (((p = 7), (d = new _(y, 19, 19, null, null, p)), 0 != d.status)) return -1; + for (f = d.root, p = d.m, a = l + c, r = i = 0; a > r; ) + if ((L(p), (s = f.list[P(p)]), (o = s.b), D(o), (o = s.n), 16 > o)) y[r++] = i = o; + else if (16 == o) { + if ((L(2), (o = 3 + P(2)), D(2), r + o > a)) return -1; + for (; o-- > 0; ) y[r++] = i; + } else if (17 == o) { + if ((L(3), (o = 3 + P(3)), D(3), r + o > a)) return -1; + for (; o-- > 0; ) y[r++] = 0; + i = 0; + } else { + if ((L(7), (o = 11 + P(7)), D(7), r + o > a)) return -1; + for (; o-- > 0; ) y[r++] = 0; + i = 0; + } + if (((p = w), (d = new _(y, l, 257, T, A, p)), 0 == p && (d.status = 1), 0 != d.status)) + return (1 == d.status, -1); + for (f = d.root, p = d.m, r = 0; c > r; r++) y[r] = y[r + l]; + return ( + (h = I), + (d = new _(y, c, 0, k, O, h)), + (m = d.root), + (h = d.m), + 0 == h && l > 257 ? -1 : (1 == d.status, 0 != d.status ? -1 : N(e, t, n)) + ); + }, + z = function () { + (null == t && (t = new Array(2 * b)), (n = 0), (a = 0), (s = 0), (u = -1), (l = !1), (c = d = 0), (f = null)); + }, + F = function (e, r, o) { + var i, a; + for (i = 0; o > i; ) { + if (l && -1 == u) return i; + if (c > 0) { + if (u != g) for (; c > 0 && o > i; ) (c--, (d &= b - 1), (n &= b - 1), (e[r + i++] = t[n++] = t[d++])); + else { + for (; c > 0 && o > i; ) (c--, (n &= b - 1), L(8), (e[r + i++] = t[n++] = P(8)), D(8)); + 0 == c && (u = -1); + } + if (i == o) return i; + } + if (-1 == u) { + if (l) break; + (L(1), 0 != P(1) && (l = !0), D(1), L(2), (u = P(2)), D(2), (f = null), (c = 0)); + } + switch (u) { + case 0: + a = R(e, r + i, o - i); + break; + case 1: + a = null != f ? N(e, r + i, o - i) : j(e, r + i, o - i); + break; + case 2: + a = null != f ? N(e, r + i, o - i) : B(e, r + i, o - i); + break; + default: + a = -1; + } + if (-1 == a) return l ? 0 : -1; + i += a; + } + return i; + }, + q = function (e) { + var t, n; + (z(), (y = e), (v = 0)); + for (var r = new Array(1024), o = []; (t = F(r, 0, r.length)) > 0; ) { + var i = new Array(t); + for (n = 0; t > n; n++) i[n] = String.fromCharCode(r[n]); + o[o.length] = i.join(''); + } + return ((y = null), o.join('')); + }; + (e.RawDeflate || (e.RawDeflate = {}), (e.RawDeflate.inflate = q)); + })(this), + 'object' != typeof JSON && (JSON = {}), + (function () { + 'use strict'; + function f(e) { + return 10 > e ? '0' + e : e; + } + function this_value() { + return this.valueOf(); + } + function quote(e) { + return ( + (escapable.lastIndex = 0), + escapable.test(e) + ? '"' + + e.replace(escapable, function (e) { + var t = meta[e]; + return 'string' == typeof t ? t : '\\u' + ('0000' + e.charCodeAt(0).toString(16)).slice(-4); + }) + + '"' + : '"' + e + '"' + ); + } + function str(e, t) { + var n, + r, + o, + i, + a, + s = gap, + u = t[e]; + switch ( + (u && 'object' == typeof u && 'function' == typeof u.toJSON && (u = u.toJSON(e)), + 'function' == typeof rep && (u = rep.call(t, e, u)), + typeof u) + ) { + case 'string': + return quote(u); + case 'number': + return isFinite(u) ? String(u) : 'null'; + case 'boolean': + case 'null': + return String(u); + case 'object': + if (!u) return 'null'; + if (((gap += indent), (a = []), '[object Array]' === Object.prototype.toString.apply(u))) { + for (i = u.length, n = 0; i > n; n += 1) a[n] = str(n, u) || 'null'; + return ( + (o = + 0 === a.length + ? '[]' + : gap + ? '[\n' + gap + a.join(',\n' + gap) + '\n' + s + ']' + : '[' + a.join(',') + ']'), + (gap = s), + o + ); + } + if (rep && 'object' == typeof rep) + for (i = rep.length, n = 0; i > n; n += 1) + 'string' == typeof rep[n] && + ((r = rep[n]), (o = str(r, u)), o && a.push(quote(r) + (gap ? ': ' : ':') + o)); + else + for (r in u) + Object.prototype.hasOwnProperty.call(u, r) && + ((o = str(r, u)), o && a.push(quote(r) + (gap ? ': ' : ':') + o)); + return ( + (o = + 0 === a.length + ? '{}' + : gap + ? '{\n' + gap + a.join(',\n' + gap) + '\n' + s + '}' + : '{' + a.join(',') + '}'), + (gap = s), + o + ); + } + } + 'function' != typeof Date.prototype.toJSON && + ((Date.prototype.toJSON = function () { + return isFinite(this.valueOf()) + ? this.getUTCFullYear() + + '-' + + f(this.getUTCMonth() + 1) + + '-' + + f(this.getUTCDate()) + + 'T' + + f(this.getUTCHours()) + + ':' + + f(this.getUTCMinutes()) + + ':' + + f(this.getUTCSeconds()) + + 'Z' + : null; + }), + (Boolean.prototype.toJSON = this_value), + (Number.prototype.toJSON = this_value), + (String.prototype.toJSON = this_value)); + var cx, escapable, gap, indent, meta, rep; + ('function' != typeof JSON.stringify && + ((escapable = + /[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g), + (meta = { '\b': '\\b', ' ': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"': '\\"', '\\': '\\\\' }), + (JSON.stringify = function (e, t, n) { + var r; + if (((gap = ''), (indent = ''), 'number' == typeof n)) for (r = 0; n > r; r += 1) indent += ' '; + else 'string' == typeof n && (indent = n); + if (((rep = t), t && 'function' != typeof t && ('object' != typeof t || 'number' != typeof t.length))) + throw new Error('JSON.stringify'); + return str('', { '': e }); + })), + 'function' != typeof JSON.parse && + ((cx = + /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g), + (JSON.parse = function (text, reviver) { + function walk(e, t) { + var n, + r, + o = e[t]; + if (o && 'object' == typeof o) + for (n in o) + Object.prototype.hasOwnProperty.call(o, n) && + ((r = walk(o, n)), void 0 !== r ? (o[n] = r) : delete o[n]); + return reviver.call(e, t, o); + } + var j; + if ( + ((text = String(text)), + (cx.lastIndex = 0), + cx.test(text) && + (text = text.replace(cx, function (e) { + return '\\u' + ('0000' + e.charCodeAt(0).toString(16)).slice(-4); + })), + /^[\],:{}\s]*$/.test( + text + .replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') + .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') + .replace(/(?:^|:|,)(?:\s*\[)+/g, '') + )) + ) + return ((j = eval('(' + text + ')')), 'function' == typeof reviver ? walk({ '': j }, '') : j); + throw new SyntaxError('JSON.parse'); + }))); + })()); +var saveAs = + saveAs || + (function (e) { + 'use strict'; + if ('undefined' == typeof navigator || !/MSIE [1-9]\./.test(navigator.userAgent)) { + var t = e.document, + n = function () { + return e.URL || e.webkitURL || e; + }, + r = t.createElementNS('http://www.w3.org/1999/xhtml', 'a'), + o = 'download' in r, + i = function (e) { + var t = new MouseEvent('click'); + e.dispatchEvent(t); + }, + a = /Version\/[\d\.]+.*Safari/.test(navigator.userAgent), + s = e.webkitRequestFileSystem, + u = e.requestFileSystem || s || e.mozRequestFileSystem, + l = function (t) { + (e.setImmediate || e.setTimeout)(function () { + throw t; + }, 0); + }, + c = 'application/octet-stream', + d = 0, + f = 4e4, + m = function (e) { + var t = function () { + 'string' == typeof e ? n().revokeObjectURL(e) : e.remove(); + }; + setTimeout(t, f); + }, + p = function (e, t, n) { + t = [].concat(t); + for (var r = t.length; r--; ) { + var o = e['on' + t[r]]; + if ('function' == typeof o) + try { + o.call(e, n || e); + } catch (i) { + l(i); + } + } + }, + h = function (e) { + return /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type) + ? new Blob(['\ufeff', e], { type: e.type }) + : e; + }, + y = function (t, l, f) { + f || (t = h(t)); + var y, + v, + b, + g = this, + w = t.type, + I = !1, + E = function () { + p(g, 'writestart progress write writeend'.split(' ')); + }, + U = function () { + if (v && a && 'undefined' != typeof FileReader) { + var r = new FileReader(); + return ( + (r.onloadend = function () { + var e = r.result; + ((v.location.href = 'data:attachment/file' + e.slice(e.search(/[,;]/))), + (g.readyState = g.DONE), + E()); + }), + r.readAsDataURL(t), + void (g.readyState = g.INIT) + ); + } + if (((!I && y) || (y = n().createObjectURL(t)), v)) v.location.href = y; + else { + var o = e.open(y, '_blank'); + void 0 === o && a && (e.location.href = y); + } + ((g.readyState = g.DONE), E(), m(y)); + }, + T = function (e) { + return function () { + return g.readyState !== g.DONE ? e.apply(this, arguments) : void 0; + }; + }, + A = { create: !0, exclusive: !1 }; + return ( + (g.readyState = g.INIT), + l || (l = 'download'), + o + ? ((y = n().createObjectURL(t)), + void setTimeout(function () { + ((r.href = y), (r.download = l), i(r), E(), m(y), (g.readyState = g.DONE)); + })) + : (e.chrome && w && w !== c && ((b = t.slice || t.webkitSlice), (t = b.call(t, 0, t.size, c)), (I = !0)), + s && 'download' !== l && (l += '.download'), + (w === c || s) && (v = e), + u + ? ((d += t.size), + void u( + e.TEMPORARY, + d, + T(function (e) { + e.root.getDirectory( + 'saved', + A, + T(function (e) { + var n = function () { + e.getFile( + l, + A, + T(function (e) { + e.createWriter( + T(function (n) { + ((n.onwriteend = function (t) { + ((v.location.href = e.toURL()), + (g.readyState = g.DONE), + p(g, 'writeend', t), + m(e)); + }), + (n.onerror = function () { + var e = n.error; + e.code !== e.ABORT_ERR && U(); + }), + 'writestart progress write abort'.split(' ').forEach(function (e) { + n['on' + e] = g['on' + e]; + }), + n.write(t), + (g.abort = function () { + (n.abort(), (g.readyState = g.DONE)); + }), + (g.readyState = g.WRITING)); + }), + U + ); + }), + U + ); + }; + e.getFile( + l, + { create: !1 }, + T(function (e) { + (e.remove(), n()); + }), + T(function (e) { + e.code === e.NOT_FOUND_ERR ? n() : U(); + }) + ); + }), + U + ); + }), + U + )) + : void U()) + ); + }, + v = y.prototype, + b = function (e, t, n) { + return new y(e, t, n); + }; + return 'undefined' != typeof navigator && navigator.msSaveOrOpenBlob + ? function (e, t, n) { + return (n || (e = h(e)), navigator.msSaveOrOpenBlob(e, t || 'download')); + } + : ((v.abort = function () { + var e = this; + ((e.readyState = e.DONE), p(e, 'abort')); + }), + (v.readyState = v.INIT = 0), + (v.WRITING = 1), + (v.DONE = 2), + (v.error = v.onwritestart = v.onprogress = v.onwrite = v.onabort = v.onerror = v.onwriteend = null), + b); + } + })(('undefined' != typeof self && self) || ('undefined' != typeof window && window) || this.content); +('undefined' != typeof module && module.exports + ? (module.exports.saveAs = saveAs) + : 'undefined' != typeof define && + null !== define && + null !== define.amd && + define([], function () { + return saveAs; + }), + String.prototype.endsWithAny || + (String.prototype.endsWithAny = function () { + for (var e = Array.prototype.slice.call(arguments), t = this.toLowerCase().toString(), n = 0; n < e.length; n++) + if (-1 !== t.indexOf(e[n], t.length - e[n].length)) return !0; + return !1; + })); +var saveTextAs = + saveTextAs || + function (e, t, n) { + if (((t = t || 'download.txt'), (n = n || 'utf-8'), (e = (e || '').replace(/\r?\n/g, '\r\n')), saveAs && Blob)) { + var r = new Blob([e], { type: 'text/plain;charset=' + n }); + return (saveAs(r, t), !0); + } + var o = window.frames.saveTxtWindow; + if ( + !o && + ((o = document.createElement('iframe')), + (o.id = 'saveTxtWindow'), + (o.style.display = 'none'), + document.body.insertBefore(o, null), + (o = window.frames.saveTxtWindow), + !o && ((o = window.open('', '_temp', 'width=100,height=100')), !o)) + ) + return (window.alert('Sorry, download file could not be created.'), !1); + var i = o.document; + (i.open('text/plain', 'replace'), + (i.charset = n), + t.endsWithAny('.htm', '.html') + ? (i.close(), (i.body.innerHTML = '\r\n' + e + '\r\n')) + : (t.endsWithAny('.txt') || (t += '.txt'), i.write(e), i.close())); + var a = i.execCommand('SaveAs', null, t); + return (o.close(), a); + }; +(!(function (e) { + 'use strict'; + if (((e.URL = e.URL || e.webkitURL), e.Blob && e.URL)) + try { + return void new Blob(); + } catch (t) {} + var n = + e.BlobBuilder || + e.WebKitBlobBuilder || + e.MozBlobBuilder || + (function (e) { + var t = function (e) { + return Object.prototype.toString.call(e).match(/^\[object\s(.*)\]$/)[1]; + }, + n = function () { + this.data = []; + }, + r = function (e, t, n) { + ((this.data = e), (this.size = e.length), (this.type = t), (this.encoding = n)); + }, + o = n.prototype, + i = r.prototype, + a = e.FileReaderSync, + s = function (e) { + this.code = this[(this.name = e)]; + }, + u = + 'NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR'.split( + ' ' + ), + l = u.length, + c = e.URL || e.webkitURL || e, + d = c.createObjectURL, + f = c.revokeObjectURL, + m = c, + p = e.btoa, + h = e.atob, + y = e.ArrayBuffer, + v = e.Uint8Array, + b = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/; + for (r.fake = i.fake = !0; l--; ) s.prototype[u[l]] = l + 1; + return ( + c.createObjectURL || + (m = e.URL = + function (e) { + var t, + n = document.createElementNS('http://www.w3.org/1999/xhtml', 'a'); + return ( + (n.href = e), + 'origin' in n || + ('data:' === n.protocol.toLowerCase() + ? (n.origin = null) + : ((t = e.match(b)), (n.origin = t && t[1]))), + n + ); + }), + (m.createObjectURL = function (e) { + var t, + n = e.type; + return ( + null === n && (n = 'application/octet-stream'), + e instanceof r + ? ((t = 'data:' + n), + 'base64' === e.encoding + ? t + ';base64,' + e.data + : 'URI' === e.encoding + ? t + ',' + decodeURIComponent(e.data) + : p + ? t + ';base64,' + p(e.data) + : t + ',' + encodeURIComponent(e.data)) + : d + ? d.call(c, e) + : void 0 + ); + }), + (m.revokeObjectURL = function (e) { + 'data:' !== e.substring(0, 5) && f && f.call(c, e); + }), + (o.append = function (e) { + var n = this.data; + if (v && (e instanceof y || e instanceof v)) { + for (var o = '', i = new v(e), u = 0, l = i.length; l > u; u++) o += String.fromCharCode(i[u]); + n.push(o); + } else if ('Blob' === t(e) || 'File' === t(e)) { + if (!a) throw new s('NOT_READABLE_ERR'); + var c = new a(); + n.push(c.readAsBinaryString(e)); + } else + e instanceof r + ? 'base64' === e.encoding && h + ? n.push(h(e.data)) + : 'URI' === e.encoding + ? n.push(decodeURIComponent(e.data)) + : 'raw' === e.encoding && n.push(e.data) + : ('string' != typeof e && (e += ''), n.push(unescape(encodeURIComponent(e)))); + }), + (o.getBlob = function (e) { + return (arguments.length || (e = null), new r(this.data.join(''), e, 'raw')); + }), + (o.toString = function () { + return '[object BlobBuilder]'; + }), + (i.slice = function (e, t, n) { + var o = arguments.length; + return (3 > o && (n = null), new r(this.data.slice(e, o > 1 ? t : this.data.length), n, this.encoding)); + }), + (i.toString = function () { + return '[object Blob]'; + }), + (i.close = function () { + ((this.size = 0), delete this.data); + }), + n + ); + })(e); + e.Blob = function (e, t) { + var r = t ? t.type || '' : '', + o = new n(); + if (e) + for (var i = 0, a = e.length; a > i; i++) + Uint8Array && e[i] instanceof Uint8Array ? o.append(e[i].buffer) : o.append(e[i]); + var s = o.getBlob(r); + return (!s.slice && s.webkitSlice && (s.slice = s.webkitSlice), s); + }; + var r = + Object.getPrototypeOf || + function (e) { + return e.__proto__; + }; + e.Blob.prototype = r(new e.Blob()); +})(('undefined' != typeof self && self) || ('undefined' != typeof window && window) || this.content || this), + (function (e, t) { + function n(n, l, c) { + var m = []; + l = 1 == l ? { entropy: !0 } : l || {}; + var b = a(i(l.entropy ? [n, u(e)] : null == n ? s() : n, 3), m), + g = new r(m), + w = function () { + for (var e = g.g(f), t = h, n = 0; y > e; ) ((e = (e + n) * d), (t *= d), (n = g.g(1))); + for (; e >= v; ) ((e /= 2), (t /= 2), (n >>>= 1)); + return (e + n) / t; + }; + return ( + (w.int32 = function () { + return 0 | g.g(4); + }), + (w.quick = function () { + return g.g(4) / (4 * (1 << 30)); + }), + (w['double'] = w), + a(u(g.S), e), + ( + l.pass || + c || + function (e, n, r, i) { + return ( + i && + (i.S && o(i, g), + (e.state = function () { + return o(g, {}); + })), + r ? ((t[p] = e), n) : e + ); + } + )(w, b, 'global' in l ? l.global : this == t, l.state) + ); + } + function r(e) { + var t, + n = e.length, + r = this, + o = 0, + i = (r.i = r.j = 0), + a = (r.S = []); + for (n || (e = [n++]); d > o; ) a[o] = o++; + for (o = 0; d > o; o++) ((a[o] = a[(i = b & (i + e[o % n] + (t = a[o])))]), (a[i] = t)); + (r.g = function (e) { + for (var t, n = 0, o = r.i, i = r.j, a = r.S; e--; ) + ((t = a[(o = b & (o + 1))]), (n = n * d + a[b & ((a[o] = a[(i = b & (i + t))]) + (a[i] = t))])); + return ((r.i = o), (r.j = i), n); + })(d); + } + function o(e, t) { + return ((t.i = e.i), (t.j = e.j), (t.S = e.S.slice()), t); + } + function i(e, t) { + var n, + r = [], + o = typeof e; + if (t && 'object' == o) + for (n in e) + try { + r.push(i(e[n], t - 1)); + } catch (a) {} + return r.length ? r : 'string' == o ? e : e + '\x00'; + } + function a(e, t) { + for (var n, r = e + '', o = 0; o < r.length; ) t[b & o] = b & ((n ^= 19 * t[b & o]) + r.charCodeAt(o++)); + return u(t); + } + function s() { + try { + if (l) return u(l.randomBytes(d)); + var t = new Uint8Array(d); + return (c.crypto.getRandomValues(t), u(t)); + } catch (n) { + var r = c.navigator, + o = r && r.plugins; + return [+new Date(), c, o, c.screen, u(e)]; + } + } + function u(e) { + return String.fromCharCode.apply(0, e); + } + var l, + c = this, + d = 256, + f = 6, + m = 52, + p = 'random', + h = t.pow(d, f), + y = t.pow(2, m), + v = 2 * y, + b = d - 1; + if (((t['seed' + p] = n), a(t.random(), e), 'object' == typeof module && module.exports)) { + module.exports = n; + try { + l = require('crypto'); + } catch (g) {} + } else + 'function' == typeof define && + define.amd && + define(function () { + return n; + }); + })([], Math), + Math.seedrandom('TestMyBrain'), + (function (e, t) { + 'use strict'; + function n(e) { + return ((p[m] = r.apply(t, e)), m++); + } + function r(e) { + var n = [].slice.call(arguments, 1); + return function () { + 'function' == typeof e ? e.apply(t, n) : new Function('' + e)(); + }; + } + function o(e) { + if (h) setTimeout(r(o, e), 0); + else { + var t = p[e]; + if (t) { + h = !0; + try { + t(); + } finally { + (i(e), (h = !1)); + } + } + } + } + function i(e) { + delete p[e]; + } + function a() { + f = function () { + var e = n(arguments); + return (process.nextTick(r(o, e)), e); + }; + } + function s() { + if (e.postMessage && !e.importScripts) { + var t = !0, + n = e.onmessage; + return ( + (e.onmessage = function () { + t = !1; + }), + e.postMessage('', '*'), + (e.onmessage = n), + t + ); + } + } + function u() { + var t = 'setImmediate$' + Math.random() + '$', + r = function (n) { + n.source === e && 'string' == typeof n.data && 0 === n.data.indexOf(t) && o(+n.data.slice(t.length)); + }; + (e.addEventListener ? e.addEventListener('message', r, !1) : e.attachEvent('onmessage', r), + (f = function () { + var r = n(arguments); + return (e.postMessage(t + r, '*'), r); + })); + } + function l() { + var e = new MessageChannel(); + ((e.port1.onmessage = function (e) { + var t = e.data; + o(t); + }), + (f = function () { + var t = n(arguments); + return (e.port2.postMessage(t), t); + })); + } + function c() { + var e = y.documentElement; + f = function () { + var t = n(arguments), + r = y.createElement('script'); + return ( + (r.onreadystatechange = function () { + (o(t), (r.onreadystatechange = null), e.removeChild(r), (r = null)); + }), + e.appendChild(r), + t + ); + }; + } + function d() { + f = function () { + var e = n(arguments); + return (setTimeout(r(o, e), 0), e); + }; + } + if (!e.setImmediate) { + var f, + m = 1, + p = {}, + h = !1, + y = e.document, + v = Object.getPrototypeOf && Object.getPrototypeOf(e); + ((v = v && v.setTimeout ? v : e), + '[object process]' === {}.toString.call(e.process) + ? a() + : s() + ? u() + : e.MessageChannel + ? l() + : y && 'onreadystatechange' in y.createElement('script') + ? c() + : d(), + (v.setImmediate = f), + (v.clearImmediate = i)); + } + })(new Function('return this')()), + Array.prototype.shuffle || + (Array.prototype.shuffle = function () { + for ( + var e, t, n = this.length; + n; + e = parseInt(Math.random() * n), t = this[--n], this[n] = this[e], this[e] = t + ); + return this; + }), + Array.prototype.random || + (Array.prototype.random = function () { + return this[randInt(this.length)]; + }), + Array.prototype.invoke || + (Array.prototype.invoke = function (e) { + var t = this.length >>> 0; + if ('function' != typeof e) throw new TypeError('Argument is not a function.', 'Array.prototype.invoke'); + for (var n = arguments[1], r = [], o = 0; t > o; o++) o in this && r.push(e.call(n, this[o])); + return r; + }), + Array.prototype.pluck || + (Array.prototype.pluck = function (e) { + 'use strict'; + if (!e || 'string' != typeof e) throw new TypeError('Argument must be a string.'); + return this.map(function (t) { + var n; + return (n = void 0 !== t[e] ? ('function' == typeof t[e] ? t[e]() : t[e]) : void 0); + }); + }), + Array.prototype.unique || + (Array.prototype.unique = function () { + 'use strict'; + return this.reduce(function (e, t) { + return (-1 === e.indexOf(t) && e.push(t), e); + }, []); + }), + Array.prototype.includes || + (Array.prototype.includes = function (e) { + 'use strict'; + var t = Object(this), + n = parseInt(t.length) || 0; + if (0 === n) return !1; + var r, + o = parseInt(arguments[1]) || 0; + o >= 0 ? (r = o) : ((r = n + o), 0 > r && (r = 0)); + for (var i; n > r; ) { + if (((i = t[r]), e === i || (e !== e && i !== i))) return !0; + r++; + } + return !1; + }), + Array.prototype.contains || (Array.prototype.contains = Array.prototype.includes), + Array.prototype.fill || + (Array.prototype.fill = function (e) { + if (null === this) throw new TypeError("'this' is null or not defined"); + for ( + var t = Object(this), + n = t.length >>> 0, + r = arguments[1], + o = r >> 0, + i = 0 > o ? Math.max(n + o, 0) : Math.min(o, n), + a = arguments[2], + s = void 0 === a ? n : a >> 0, + u = 0 > s ? Math.max(n + s, 0) : Math.min(s, n); + u > i; + ) + ((t[i] = e), i++); + return t; + }), + Array.prototype.flatten || + (Array.prototype.flatten = function e() { + for (var t = [], n = 0, r = this.length; r > n; n++) { + var o = Object.prototype.toString.call(this[n]).split(' ').pop().split(']').shift().toLowerCase(); + o && (t = t.concat(/^(array|collection|arguments)$/.test(o) ? e.call(this[n]) : this[n])); + } + return t; + }), + Array.prototype.partition || + (Array.prototype.partition = function (e) { + if ('function' != typeof e) throw new TypeError('Argument of Array.prototype.partition must be a function.'); + for (var t, n = [], r = [], o = 0, i = this.length; i > o; o++) ((t = this[o]), e(t) ? n.push(t) : r.push(t)); + return [n, r]; + }), + Array.prototype.zip || + (Array.prototype.zip = function (e) { + var t = []; + if (e.length !== this.length) throw new TypeError('Array.prototype.zip: arrays must be equal length'); + for (var n = 0, r = this.length; r > n; n++) t.push([this[n], e[n]]); + return t; + }), + Array.prototype.sum || + (Array.prototype.sum = function () { + for (var e = this.length, t = 0; e--; ) t += this[e]; + return t; + }), + Array.prototype.average || + (Array.prototype.average = function () { + return this.length ? this.sum() / this.length : null; + }), + Array.prototype.variance || + (Array.prototype.variance = function () { + if (!this.length) return null; + var e, + t, + n, + r, + o = 0, + i = 0; + for (t = this.average(), n = this.length, e = 0; n > e; e++) ((r = this[e] - t), (o += r * r), (i += r)); + return ((i *= i / n), (o - i) / (n - 1)); + }), + Array.prototype.sd || + (Array.prototype.sd = function () { + if (!this.length) return null; + var e = this.variance(); + return Math.sqrt(e); + }), + Array.prototype.median || + (Array.prototype.median = function () { + if (!this.length) return null; + var e = this.slice(), + t = Math.floor(e.length / 2); + return ( + e.sort(function (e, t) { + return e - t; + }), + e.length % 2 === 1 ? e[t] : (e[t - 1] + e[t]) / 2 + ); + })); +var tmbObjs = { params: {}, elements: {}, frames: {}, slides: {} }; +tmbObjs.params = location.href.split('?')[1] + ? location.href + .split('?')[1] + .split('&') + .reduce(function (e, t) { + return ((e[t.split('=')[0]] = t.split('=')[1]), e); + }, {}) + : {}; +var zen = tmbObjs, + hasTouch = 'ontouchend' in window || navigator.maxTouchPoints || navigator.msMaxTouchPoints || !1, + hasPointer = window.PointerEvent || window.MSPointerEvent || !1; +(!(function () { + for ( + var e, + t = function () {}, + n = [ + 'assert', + 'clear', + 'count', + 'debug', + 'dir', + 'dirxml', + 'error', + 'exception', + 'group', + 'groupCollapsed', + 'groupEnd', + 'info', + 'log', + 'markTimeline', + 'profile', + 'profileEnd', + 'table', + 'time', + 'timeEnd', + 'timeline', + 'timelineEnd', + 'timeStamp', + 'trace', + 'warn' + ], + r = n.length, + o = (window.console = window.console || {}); + r--; + ) + ((e = n[r]), o[e] || (o[e] = t)); +})(), + (function () { + var e, t; + document.createElement && + (e = document.createElement('div')) && + ((e.id = '____loading_slide'), + (e.style.display = 'none'), + (e.style.textAlign = 'center'), + (e.style.paddingTop = '40px'), + (e.style.fontWeight = 'bold'), + (e.style.fontSize = 'x-large'), + (e.innerHTML = 'Working....'), + (t = setInterval(function () { + 'loading' !== document.readyState && (clearInterval(t), document.body.appendChild(e)); + }, 100)), + window.addEventListener( + 'beforeunload', + function () { + showFrame('____loading_slide'); + }, + !0 + )); + })()); +var $$$ = getID, + fixOrientation = fixMobileOrientation, + tmbUI = { + UIevents: [], + UIkeys: [], + UIelements: [], + highlight: '', + timeout: 1e4, + timeoutRef: 0, + onreadyUI: function () {}, + getInput: function () {}, + status: '', + message: '', + response: '', + downTimestamp: 0, + rt: 0, + upTimestamp: 0, + dwell: 0 + }; +tmbUI.getInput = function () { + function e(e) { + var t, n; + ((t = e), + t.preventDefault(), + t.stopPropagation(), + d === !1 && + (tmbUI.UIevents.includes('keys') && + 'keydown' === t.type && + ((n = t.charCode || t.keyCode), + (tmbUI.UIkeys.includes(n) || 0 === tmbUI.UIkeys.length) && + ((tmbUI.response = codeToKey(n)), + '' !== tmbUI.highlight && tmbUI.UIkeys.length > 0 && (a = getID(tmbUI.UIelements[tmbUI.UIkeys.indexOf(n)])), + (d = !0))), + tmbUI.UIevents.includes('clicks') && + ('mousedown' === t.type || + ('pointerdown' === t.type && 'mouse' === t.pointerType) || + ('MSPointerDown' === t.type && t.pointerType === t.MSPOINTER_TYPE_MOUSE)) && + (0 === tmbUI.UIelements.length + ? (tmbUI.response = 'document') + : (tmbUI.response = t.target ? t.target.id : t.srcElement.id), + '' !== tmbUI.highlight && (a = getID(tmbUI.response)), + (d = !0)), + tmbUI.UIevents.includes('taps') && + (('touchstart' !== t.type && + ('pointerdown' !== t.type || ('touch' !== t.pointerType && 'pen' !== t.pointerType)) && + ('MSPointerDown' !== t.type || + (t.pointerType !== t.MSPOINTER_TYPE_TOUCH && t.pointerType !== t.MSPOINTER_TYPE_PEN))) || + (0 === tmbUI.UIelements.length + ? (tmbUI.response = 'document') + : (tmbUI.response = t.target ? t.target.id : t.srcElement.id), + '' !== tmbUI.highlight && (a = getID(tmbUI.response)), + (d = !0))), + d === !0 && + ((tmbUI.rt = c), + (c = now()), + (tmbUI.rt = c - tmbUI.rt), + (tmbUI.rt = tmbUI.rt.round(2)), + (tmbUI.downTimestamp = c), + tmbUI.timeoutRef && clearTimeout(tmbUI.timeoutRef), + a && + (['div', 'span', 'button', 'p', 'img'].includes(a.tagName.toLowerCase()) + ? ((s = a.style.border), (a.style.border = '5px solid ' + tmbUI.highlight)) + : ['circle', 'rect', 'ellipse', 'line', 'path', 'polygon', 'polyline', 'image', 'text'].includes( + a.tagName.toLowerCase() + ) + ? ((u = a.style.stroke), + (l = a.style.strokeWidth), + (a.style.stroke = tmbUI.highlight), + (a.style.strokeWidth = 5)) + : ['shape'].includes(a.tagName.toLowerCase()) && + ((u = a.strokecolor), + (l = a.strokeweight), + (a.strokecolor = tmbUI.highlight), + (a.strokeweight = 5)))))); + } + function t(e) { + var t, + n = ['', '', 'touch', 'pen', 'mouse']; + ((t = e), + t.preventDefault(), + t.stopPropagation(), + d === !0 && + ((tmbUI.upTimestamp = now()), + (tmbUI.dwell = tmbUI.upTimestamp - c), + (tmbUI.dwell = tmbUI.dwell.round(2)), + (tmbUI.status = t.type), + 'pointerup' === t.type + ? (tmbUI.status += '-' + t.pointerType) + : 'MSPointerUp' === t.type && (tmbUI.status += '-' + n[t.pointerType]), + r(), + o())); + } + function n() { + if ( + (tmbUI.UIevents.includes('keys') && + (document.addEventListener('keydown', e, !0), document.addEventListener('keyup', t, !0)), + tmbUI.UIevents.includes('clicks')) + ) + if (0 === tmbUI.UIelements.length) + window.PointerEvent + ? (document.body.addEventListener('pointerdown', e, !0), document.body.addEventListener('pointerup', t, !0)) + : window.MSPointerEvent + ? (document.body.addEventListener('MSPointerDown', e, !0), + document.body.addEventListener('MSPointerUp', t, !0)) + : (document.addEventListener('mousedown', e, !0), document.addEventListener('mouseup', t, !0)); + else + for (i = 0; i < tmbUI.UIelements.length; i++) + window.PointerEvent + ? (getID(tmbUI.UIelements[i]).addEventListener('pointerdown', e, !0), + getID(tmbUI.UIelements[i]).addEventListener('pointerup', t, !0)) + : window.MSPointerEvent + ? (getID(tmbUI.UIelements[i]).addEventListener('MSPointerDown', e, !0), + getID(tmbUI.UIelements[i]).addEventListener('MSPointerUp', t, !0)) + : (getID(tmbUI.UIelements[i]).addEventListener('mousedown', e, !0), + getID(tmbUI.UIelements[i]).addEventListener('mouseup', t, !0)); + if (tmbUI.UIevents.includes('taps')) + if (0 === tmbUI.UIelements.length) + window.PointerEvent && !tmbUI.UIevents.includes('clicks') + ? (document.addEventListener('pointerdown', e, !0), document.addEventListener('pointerup', t, !0)) + : window.MSPointerEvent && !tmbUI.UIevents.includes('clicks') + ? (document.addEventListener('MSPointerDown', e, !0), document.addEventListener('MSPointerUp', t, !0)) + : hasTouch && + !hasPointer && + (document.addEventListener('touchstart', e, !0), document.addEventListener('touchend', t, !0)); + else + for (i = 0; i < tmbUI.UIelements.length; i++) + window.PointerEvent && !tmbUI.UIevents.includes('clicks') + ? (getID(tmbUI.UIelements[i]).addEventListener('pointerdown', e, !0), + getID(tmbUI.UIelements[i]).addEventListener('pointerup', t, !0)) + : window.MSPointerEvent && !tmbUI.UIevents.includes('clicks') + ? (getID(tmbUI.UIelements[i]).addEventListener('MSPointerDown', e, !0), + getID(tmbUI.UIelements[i]).addEventListener('MSPointerUp', t, !0)) + : hasTouch && + !hasPointer && + (getID(tmbUI.UIelements[i]).addEventListener('touchstart', e, !0), + getID(tmbUI.UIelements[i]).addEventListener('touchend', t, !0)); + } + function r() { + if ( + (tmbUI.UIevents.includes('keys') && + (document.removeEventListener('keydown', e, !0), document.removeEventListener('keyup', t, !0)), + tmbUI.UIevents.includes('clicks')) + ) + if (0 === tmbUI.UIelements.length) + window.PointerEvent + ? (document.body.removeEventListener('pointerdown', e, !0), + document.body.removeEventListener('pointerup', t, !0)) + : window.MSPointerEvent + ? (document.body.removeEventListener('MSPointerDown', e, !0), + document.body.removeEventListener('MSPointerUp', t, !0)) + : (document.removeEventListener('mousedown', e, !0), document.removeEventListener('mouseup', t, !0)); + else + for (i = 0; i < tmbUI.UIelements.length; i++) + window.PointerEvent + ? (getID(tmbUI.UIelements[i]).removeEventListener('pointerdown', e, !0), + getID(tmbUI.UIelements[i]).removeEventListener('pointerup', t, !0)) + : window.MSPointerEvent + ? (getID(tmbUI.UIelements[i]).removeEventListener('MSPointerDown', e, !0), + getID(tmbUI.UIelements[i]).removeEventListener('MSPointerUp', t, !0)) + : (getID(tmbUI.UIelements[i]).removeEventListener('mousedown', e, !0), + getID(tmbUI.UIelements[i]).removeEventListener('mouseup', t, !0)); + if (tmbUI.UIevents.includes('taps')) + if (0 === tmbUI.UIelements.length) + window.PointerEvent && !tmbUI.UIevents.includes('clicks') + ? (document.removeEventListener('pointerdown', e, !0), document.removeEventListener('pointerup', t, !0)) + : window.MSPointerEvent && !tmbUI.UIevents.includes('clicks') + ? (document.removeEventListener('MSPointerDown', e, !0), document.removeEventListener('MSPointerUp', t, !0)) + : hasTouch && + !hasPointer && + (document.removeEventListener('touchstart', e, !0), document.removeEventListener('touchend', t, !0)); + else + for (i = 0; i < tmbUI.UIelements.length; i++) + window.PointerEvent && !tmbUI.UIevents.includes('clicks') + ? (getID(tmbUI.UIelements[i]).removeEventListener('pointerdown', e, !0), + getID(tmbUI.UIelements[i]).removeEventListener('pointerup', t, !0)) + : window.MSPointerEvent && !tmbUI.UIevents.includes('clicks') + ? (getID(tmbUI.UIelements[i]).removeEventListener('MSPointerDown', e, !0), + getID(tmbUI.UIelements[i]).removeEventListener('MSPointerUp', t, !0)) + : hasTouch && + !hasPointer && + (getID(tmbUI.UIelements[i]).removeEventListener('touchstart', e, !0), + getID(tmbUI.UIelements[i]).removeEventListener('touchend', t, !0)); + } + function o() { + if ((tmbUI.timeoutRef && (clearTimeout(tmbUI.timeoutRef), (tmbUI.timeoutRef = 0)), a)) + setTimeout(function () { + ['div', 'span', 'button', 'p', 'img'].includes(a.tagName.toLowerCase()) + ? (a.style.border = s) + : ['circle', 'rect', 'ellipse', 'line', 'path', 'polygon', 'polyline', 'image', 'text'].includes( + a.tagName.toLowerCase() + ) + ? ((a.style.stroke = u), (a.style.strokeWidth = l)) + : ['shape'].includes(a.tagName.toLowerCase()) && ((a.strokecolor = u), (a.strokeweight = l)); + var e = new CustomEvent('readyUI'); + (document.addEventListener('readyUI', tmbUI.onreadyUI, !0), + document.dispatchEvent(e), + document.removeEventListener('readyUI', tmbUI.onreadyUI, !0)); + }, 250); + else { + var e = new CustomEvent('readyUI'); + (document.addEventListener('readyUI', tmbUI.onreadyUI, !0), + document.dispatchEvent(e), + document.removeEventListener('readyUI', tmbUI.onreadyUI, !0)); + } + } + var i, + a, + s, + u, + l, + c = now(), + d = !1, + f = ''; + for (var m in tmbUI) + if (tmbUI.hasOwnProperty(m)) + switch (m) { + case 'UIevents': + for ( + 0 === tmbUI.UIevents.length && (f += "Must specify UIevents: 'keys', 'clicks' or 'taps'. "), + tmbUI.UIevents instanceof Array || (tmbUI.UIevents = [tmbUI.UIevents]), + i = 0; + i < tmbUI.UIevents.length; + i++ + ) + ['keys', 'clicks', 'taps'].includes(tmbUI.UIevents[i]) || + (f += "'" + tmbUI.UIevents[i] + "' is not a valid event. "); + !tmbUI.UIevents.includes('taps') || hasTouch || hasPointer || (f += "'taps' is not a valid event. "); + break; + case 'UIkeys': + for (tmbUI.UIkeys instanceof Array || (tmbUI.UIkeys = [tmbUI.UIkeys]), i = 0; i < tmbUI.UIkeys.length; i++) + keyboardCodes[tmbUI.UIkeys[i]] || (f += "'" + tmbUI.UIkeys[i] + "' is not a valid keyboard code. "); + break; + case 'UIelements': + for ( + tmbUI.UIelements instanceof Array || (tmbUI.UIelements = [tmbUI.UIelements]), i = 0; + i < tmbUI.UIelements.length; + i++ + ) + getID(tmbUI.UIelements[i]) || (f += "'" + tmbUI.UIelements[i] + "' is not a valid element. "); + break; + case 'timeout': + tmbUI.timeout < 150 && (f += 'Timeout is ' + tmbUI.timeout + ' ms, must be > 150 ms. '); + break; + case 'timeoutRef': + if (0 !== tmbUI.timeoutRef) return ((tmbUI.message += "'getInput' called again while still busy. "), !1); + break; + case 'highlight': + if ('' !== tmbUI.highlight) { + var p = document.createElement('div'); + ((p.style.color = 'rgb(0, 0, 0)'), + (p.style.color = tmbUI.highlight), + 'rgb(0, 0, 0)' === p.style.color && + ((p.style.color = 'rgb(255, 255, 255)'), + (p.style.color = tmbUI.highlight), + 'rgb(255, 255, 255)' === p.style.color && + (f += "'highlight' must be empty string or valid CSS color. "))); + } + break; + case 'onreadyUI': + break; + case 'getInput': + break; + case 'status': + tmbUI.status = ''; + break; + case 'message': + tmbUI.message = ''; + break; + case 'response': + tmbUI.response = ''; + break; + case 'downTimestamp': + tmbUI.downTimestamp = 0; + break; + case 'rt': + tmbUI.rt = 0; + break; + case 'upTimestamp': + tmbUI.upTimestamp = 0; + break; + case 'dwell': + tmbUI.dwell = 0; + break; + default: + f += "Invalid parameter '" + m + "'. "; + } + if ( + (tmbUI.UIkeys.length > 0 && !tmbUI.UIevents.includes('keys') && (f += "Need 'keys' in UIevents for valid keys. "), + tmbUI.UIkeys.length && + tmbUI.UIelements.length && + tmbUI.UIelements.length < tmbUI.UIkeys.length && + (f += "Invalid number of UIelements, more 'keys' than 'UIelements'. "), + 0 === tmbUI.UIelements.length && '' !== tmbUI.highlight && (f += 'No elements to highlight. '), + f) + ) { + ((tmbUI.status = 'error'), (tmbUI.message = f)); + var h = new CustomEvent('readyUI'); + return ( + document.addEventListener('readyUI', tmbUI.onreadyUI, !0), + document.dispatchEvent(h), + document.removeEventListener('readyUI', tmbUI.onreadyUI, !0), + !1 + ); + } + return ( + (tmbUI.timeoutRef = setTimeout(function () { + ((tmbUI.status = 'timeout'), (tmbUI.message += 'Timeout: no response in ' + tmbUI.timeout + ' ms.'), r(), o()); + }, tmbUI.timeout)), + n(), + !1 + ); +}; +var simulateMobileMouse = function (e) { + (e.addEventListener('touchstart', mobileTouchHandler), + e.addEventListener('touchmove', mobileTouchHandler), + e.addEventListener('touchend', mobileTouchHandler), + e.addEventListener('touchcancel', mobileTouchHandler)); + }, + mobileTouchHandler = function (e) { + switch ((e.preventDefault(), e.type)) { + case 'touchstart': + if (1 !== e.changedTouches.length) return; + ((this.touchMoved = !1), + simulateMobileMouseEvent(e, 'mouseover'), + simulateMobileMouseEvent(e, 'mousemove'), + simulateMobileMouseEvent(e, 'mousedown')); + break; + case 'touchmove': + if (1 !== e.changedTouches.length) return; + ((this.touchMoved = !0), simulateMobileMouseEvent(e, 'mousemove')); + break; + case 'touchend': + if (1 !== e.changedTouches.length) return; + (simulateMobileMouseEvent(e, 'mouseup'), + simulateMobileMouseEvent(e, 'mouseout'), + this.touchMoved || simulateMobileMouseEvent(e, 'click')); + break; + default: + return; + } + }, + keyboardCodes = { + 8: 'backspace', + 9: 'tab', + 13: 'enter', + 16: 'shift', + 17: 'control', + 18: 'alt', + 19: 'pause', + 20: 'capslock', + 27: 'escape', + 32: 'space', + 33: 'pageup', + 34: 'pagedown', + 35: 'end', + 36: 'home', + 37: 'left', + 38: 'up', + 39: 'right', + 40: 'down', + 45: 'insert', + 46: 'delete', + 48: '0', + 49: '1', + 50: '2', + 51: '3', + 52: '4', + 53: '5', + 54: '6', + 55: '7', + 56: '8', + 57: '9', + 59: ';', + 61: '=', + 65: 'a', + 66: 'b', + 67: 'c', + 68: 'd', + 69: 'e', + 70: 'f', + 71: 'g', + 72: 'h', + 73: 'i', + 74: 'j', + 75: 'k', + 76: 'l', + 77: 'm', + 78: 'n', + 79: 'o', + 80: 'p', + 81: 'q', + 82: 'r', + 83: 's', + 84: 't', + 85: 'u', + 86: 'v', + 87: 'w', + 88: 'x', + 89: 'y', + 90: 'z', + 91: 'OSleft', + 92: 'OSright', + 93: 'OSright', + 96: 'numpad0', + 97: 'numpad1', + 98: 'numpad2', + 99: 'numpad3', + 100: 'numpad4', + 101: 'numpad5', + 102: 'numpad6', + 103: 'numpad7', + 104: 'numpad8', + 105: 'numpad9', + 106: 'numpadmultiply', + 107: 'numpadadd', + 109: 'numpadsubtract', + 110: 'numpaddecimal', + 111: 'numpaddivide', + 112: 'f1', + 113: 'f2', + 114: 'f3', + 115: 'f4', + 116: 'f5', + 117: 'f6', + 118: 'f7', + 119: 'f8', + 120: 'f9', + 121: 'f10', + 122: 'f11', + 123: 'f12', + 124: 'f13', + 125: 'f14', + 126: 'f15', + 144: 'numlock', + 145: 'scrolllock', + 173: '-', + 186: ';', + 187: '=', + 188: ',', + 189: '-', + 190: '.', + 191: '/', + 192: '`', + 219: '[', + 220: '\\', + 221: ']', + 222: "'", + 224: 'command' + }, + keyValue = codeToKey, + keyboardKeys = { + backspace: 8, + tab: 9, + enter: 13, + return: 13, + shift: 16, + control: 17, + ctrl: 17, + alt: 18, + pause: 19, + capslock: 20, + escape: 27, + esc: 27, + space: 32, + spacebar: 32, + ' ': 32, + pageup: 33, + pagedown: 34, + end: 35, + home: 36, + leftarrow: 37, + left: 37, + uparrow: 38, + up: 38, + rightarrow: 39, + right: 39, + downarrow: 40, + down: 40, + insert: 45, + delete: 46, + 0: 48, + 1: 49, + 2: 50, + 3: 51, + 4: 52, + 5: 53, + 6: 54, + 7: 55, + 8: 56, + 9: 57, + a: 65, + b: 66, + c: 67, + d: 68, + e: 69, + f: 70, + g: 71, + h: 72, + i: 73, + j: 74, + k: 75, + l: 76, + m: 77, + n: 78, + o: 79, + p: 80, + q: 81, + r: 82, + s: 83, + t: 84, + u: 85, + v: 86, + w: 87, + x: 88, + y: 89, + z: 90, + A: 65, + B: 66, + C: 67, + D: 68, + E: 69, + F: 70, + G: 71, + H: 72, + I: 73, + J: 74, + K: 75, + L: 76, + M: 77, + N: 78, + O: 79, + P: 80, + Q: 81, + R: 82, + S: 83, + T: 84, + U: 85, + V: 86, + W: 87, + X: 88, + Y: 89, + Z: 90, + OSleft: 91, + commandleft: 91, + Windows: 91, + OSright: 92, + commandright: 93, + numpad0: 96, + numpad1: 97, + numpad2: 98, + numpad3: 99, + numpad4: 100, + numpad5: 101, + numpad6: 102, + numpad7: 103, + numpad8: 104, + numpad9: 105, + numpadmultiply: 106, + numpadadd: 107, + numpadsubtract: 109, + numpaddecimal: 110, + numpaddivide: 111, + f1: 112, + f2: 113, + f3: 114, + f4: 115, + f5: 116, + f6: 117, + f7: 118, + f8: 119, + f9: 120, + f10: 121, + f11: 122, + f12: 123, + f13: 124, + f14: 125, + f15: 126, + numlock: 144, + scrolllock: 145, + semicolon: 186, + ';': 186, + equal: 187, + '=': 187, + comma: 188, + ',': 188, + minus: 189, + '-': 189, + period: 190, + '.': 190, + slash: 191, + '/': 191, + backquote: 192, + '`': 192, + bracketleft: 219, + '[': 219, + backslash: 220, + '\\': 220, + bracketright: 221, + ']': 221, + quote: 222, + "'": 222, + command: 224 + }, + coinFlip = randInt; +Number.prototype.round || + (Number.prototype.round = function (e) { + if (('undefined' == typeof e && (e = 0), 'number' != typeof e || (e + 1) % 1 !== 0 || !(e + 1 > 0))) + throw new TypeError('Numer.prototype.round requires 0 or a natural number for precision argument'); + var t = Math.pow(10, e); + return Math.round(this * t) / t; + }); +var centimetersToDegrees = sizeToDegrees, + degreesToCentimeters = degreesToSize, + now = function () { + var e = window.performance || {}; + return ( + (e.now = (function () { + return ( + e.now || + e.webkitNow || + e.msNow || + e.oNow || + e.mozNow || + function () { + return new Date().getTime(); + } + ); + })()), + e.now() + ); + }, + chain = chainTimeouts, + clearChain = clearChainTimeouts, + urlsafedecode = safeDecode; diff --git a/lib/interactive/TMB_DIGIT_SYMBOL_CODING/_1.webp b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/_1.webp new file mode 100644 index 0000000000000000000000000000000000000000..9d6e4b93a3379ac3524ce7ce98b0671c82f78752 GIT binary patch literal 800 zcmV+*1K<2oNk&E(0{{S5MM6+kP&gnA0{{RJ5&)e6Dr5j;06vjMoJysnBO#;pTUf9X z326Wp)9lFnB#blEZiB$BBU3H?j`OYbr=xGBC$Nv(e`d11M3<9jrI0bD|6-Ns_@AH| zuk<3B<`QR99N@KLn_wKl0Px=kcW% zfht2BJv#Z+ueP(QyL~mjNZB`Wh|kCX0RHs_Abt=^VQXA9 zmFttUiLc;mh?mn zoRlyCQdHg1K!h)BJ4|4$*hIhQtNw zmkVGL+$MShvnBdD4z*BMVW2FBXCbHiOUTRV80rlZZc&Bl>F+%Ljy-+%wsn+~TVb1S zOJqPK{*renc)m!x+=t9K=HWUeP24-|pLj9{u9eZ4Umwr+-s}X zm-@hZ<5T%wC##t+Da_|{0JZpyx6af*sGgTX0`s>Tn}J5pRto-)7avDEMPD*}u<6&0 zSlD7G;8)w3f-{cyG|rmiaa+4Na8j-g+@rJ4n8of*&>8Kt%Z&Li;zE^MeRReHKwv7> ezB!;D{koaYiyOId;vUnqDY#D=w0%SX0001uTZ^aw literal 0 HcmV?d00001 diff --git a/lib/interactive/TMB_DIGIT_SYMBOL_CODING/_2.webp b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/_2.webp new file mode 100644 index 0000000000000000000000000000000000000000..408590a901afb84cb34ede0864eba664c78411ab GIT binary patch literal 1238 zcmV;{1S$JcNk&G_1ONb6MM6+kP&gpM1ONa~7yz9CDr5j;06vjGn@FXkBB3gI`lzrH z326Wo=Kt4wF8@Q&yX(0QoKMg9+<8gfe%Je`oU??zBe?nXUjC=Xhtj^mAFckAKEyv| zeTTnnj-yiSguJg@ccr?V0Zpta3zl9a-oEWPCu41?3Pxs2-wJ?QcEoi>sTc`1FZi|` z0*GQ5HI^H-1x{mCBTMN%d%wb3Jff}K=B_D^zUSI2K%1Z~_24_PM*)5RCp z(hynnzhb-ETc=y}`Xe^;a`)oL)&Kzh`yqf_Rtvd`d$^>n6>0avVb}F_??1E5UYMcI-XCaAJ%AvmbNtMh z{i8!w|5ZVzp3uPgI)38Vsl{xx^F85G(67d)X>LTu;}y(DTlfAb-;!)(;b92i|A~`5 zHH#V`fpo(e^mX_l0k?@!fiGN%espgX{S;tiSRvY?bB4Ixbj9&}V^%@GV?>{=YeZdw zU~t9mMCU3*Nndx@YvlXK=ogt8qN}bP2mgii(ov%vy7tLI)e`n2yC z3ob0=jzi&HCdr+m+F@HDP2NeaPqghR&|xR$t0J~ed4M)wr| zv&(wXUIy|4WYO*r5}S6?){9)vcQb08x!JTTi9|JNN&B+O7~Vx}T=6j5VFtTYj>*Fa z)%i>?l75kXBcB)?08H>;MY8LXx4swSEO_4O2_(~LH4#wc?0*2ufzxi`&BzEbrJZ8( zr%Qcg*($(K$5FIS_?8wy(+eN8V; zBIw)5@Sm-OouD+T=J^z-_XSLtR5+~==(iUtfiRW#lAY_cr>uk_=6%i0{M+DC%uUd z!UvCJrrCbq^mp7xhbKH|w}n^9g|%LG+Q6pJ?J%oLGH|nm?e&~!539c=8M;2QL@~Xa z;f<86oD9D?Hk0G)H}5ZXi1FDmHRseA4DR*LBG*i3e08yIyT#N4QAA<&S9R{jVA-Ay zeL68t7Fai1a>pDLvsieqF#bQr<)63G&b;JnajX1Jb$xER?XPq)A5}C;{ z#zWasSs5qi{apdR1qGAB0}Xs7Scu;fj5e0)!(G7L<&!a66Ne+Q%XRA4?g1a6hV08O zhqNTJ_k=8d-J+klgiMmeRi+LGs=#!9UT-zwHJdDyy^2g8d&>{_z1O#L3qD}`doOD~ zzs~R^*J)y0M%zjN^@7I>BA#RV@Q&r=gK}(jefy%iMr&w`f6)=VFe4{*zMrUIea5fN z!n!pXjjdNj7ptpQk$!nq5QV=pO^-VEuWyNa;ZJ+g-#Ht_x9che&#QKLUftw#UL7!# z)P`5tFVxrW=m-I^{M}KAOpE`YL09qVD}|b%5TItf+-4>`wQnf}*NrpQ`~Uy|04_Uo AQ~&?~ literal 0 HcmV?d00001 diff --git a/lib/interactive/TMB_DIGIT_SYMBOL_CODING/_3.webp b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/_3.webp new file mode 100644 index 0000000000000000000000000000000000000000..425d712c33487ca115b06193b8da3d8e5450bf6b GIT binary patch literal 548 zcmV+<0^9vkNk&E-0ssJ4MM6+kP&il$0000G0001E003hE06|PpNHYKc00A$csBIgl z<G%|el&b};_CqW{#(ER09H^qAi@Cv z0B{TdodGIj0Av6@kw%_MrKBSvq?DSduo4Mr01kwVs)!NH#A8{y(?;8!qw=Pn!|xpA zXQptSfB5J|E;WixvXIni)uC88&t|`#y34nOuk}Sqtv@znCJL;GtyTFbh1!ORi6j4w zw>w#BvI%vA!Ihw8`==+^D+zYkD+r*>8?ho3yJ>VfvQdy)m^{P5>1Jm0bb+*+O(n&DCbMD(YI;2DMpXLGjlj=dP~zp zpKxDPsQ)GB*A3B?ezB!+8!h;eZC$FPvupUM>po{Qmh|bx-j+bqdhP5( zU1M_oGdi^HeFuY6Ykf?`>(+dYEqN%Feb;V`aX3msK-Jo)%1y_*>B`gFI-E8G*2G7j z=r(6B=xz>y@!@C#)c=nQ-dLZ66^$B4MJ6e#<%X`9`jk7r0D71>>kBIqzmW*DSM%q| m#VNNBlY22%6Vd}+8D4B z326Wm+BKj2j|p~mev`SKu+Q6nWv|*YydVkPI$QFw6!;MC zdFWvE)aPF3nRtsbAhVYT^W))pS;4b8sKXS|B!+tDJ;9E8^U%t7qn27NHTY7$MNY3G z^iaNdBVDfq5=#Y-jPvq72Tx&lI~qaztjrJ-@*%oT; zPU^`ToIOfrE>kN@;ua!LBBWZKRX@{skYOlj>Xz83kYpu-{c?j8!FRI>#2 z&iY%yx7h9C7u{*p!+zf<1F_%m_L>=xe$~wAn|VORA7f|!D6gDmkI_V7z;*~87Grg#U+CRv7T6V_5J+PD~xI^v% zFxGbHI_n1eUNtYuH&?NJGI}J?U-(T($N9E1rFgHDV5@xLNeP&g?JYWg9M~SX{`P=> z@i)5d-|6yK0q)|R_2&eu_x90NGBm$uetmm1Z$y(}_<`HQD*jrn_y1C)6B>Bs_=x>Q z`Rrz4BhIU|-(j`W4vOqxKD)Ah#YD}|Tz3CC_b}n%K@FFMaJZ3Fu6iX}2MQ7Gkxz}8 zp5>Q#8Cw*zo!`PIu&e!Lcwev=$LpsFoPTz%8vbM`w55@S%B2s_M1cIGT2QUv$JO&c zF;b`(LE)Y>M6>l*xe+D?rleOGf&WXba0z zhT>W|>ZUMWBze`~aujS)8*HKGY$0CY6FI1SS#gK1@@O|$yK&$2PXUDvxr^u(&UtdI zvvhjkoB?3w+K9gbK(7~kYu>9L2y2h#Y0M`I9I&gdU0maQZz~blx11wbzO3Z9%aqwZ IKmY&$0Bn}Ij{pDw literal 0 HcmV?d00001 diff --git a/lib/interactive/TMB_DIGIT_SYMBOL_CODING/_5.webp b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/_5.webp new file mode 100644 index 0000000000000000000000000000000000000000..c6a23eb23d2cb32d8749703f458c4b24073b87b0 GIT binary patch literal 1072 zcmV-01kd|YNk&E}1ONb6MM6+kP&gnQ1ONc=6abw8Dr5j;06vjMok}I7BB7>~+NiJ+ z326Wp(Ecdv!~DNQKedm@h!Mc97m({9L#zKU|Ev6;nxCQnWqtvFUi~4xasJKwDE_gQ zr-2D*$W9&yYowYDRVSav?pX*Dltlb6KvqR9BA~b1R|hX?I|x=5oR}(48)r~fA@$=U zDY7(!LFN7mUej@KmfLJAPzimdd@l`oa$v>;vzb1GO}yxd7bRrU+VY~PFlYb({`$Ca z`y<2I|NP-PmiAqrQpI<<;=Ka!8>Tiz5xP+9V2Xl+N`ggGCcBIU z?(VNFGb?CxpeBp-`pr%~o3oA#yc+hS5*kXwqAI==m zU~{Cwq0oTc-nP3rJb{=c;ec^i(6M>)*6w$cL{o&27ogGINqs~9b&F?INRm)9ANo72 z5f6HHe>8Yq&?eKed9TC^#D{(nfS(=wbnR#cwhN6;e zho0GE{3=mPy61K_^N*sR_|2*RCFg}GO`AJCTuOJ+f?<>{x`LWAT?8L3J-)LWl4(5_ zz#3g}I8GdwXbz`Cvnb(C=Ljp+=H5J~_^3bn4ElL}*tm>?lBaJB`TV=WW7$cKT&f`S zx|Z(S+i%N}jge2X5Bir6)$N*|O2(G8H<{o!+S!XtJ6h)ms;imtz1?ed9ocWsI$L=zIx-7JE=-7*IZ z36$okbLj))G?)Dkpp+y>tlo^qpF`CrICJd%ONk=MT*&f=g zn;_e8Dem0cZ4OYdo3iPQD|Q@D)>=Uxqn`E3mF84HVjPJq_C^lc<)Ldqkm+U3U+PKj zH^%q));$|aM<|J=+3>*%JUJ966VdNK*7G{TadU20cX1_8=6fx$rOl0cbSv3KY@v$y z(>S%G|1U1{4|eunX#k8l2wr#pBx*SDjpWpMA#m^md=K0CE{5yx_B$iBf>6G}ukr7N z2=;uycsv4E;Yn^<^?>6aZt3&O+NQk>cnh4?taX=D$O3@8Y9O5@ z*=@mJtKt=M%+zJ11oH!zsw>HF*NiddIf_h|Dr5j;06vjOo=T;pqamj{C;+e$ z326WW;``x@hB>g@BhH*X71 zIlN)W;Ahp$wR?mW7(C~|g>Smm+jNjE+hDDj=UBJ--Y+xYS^kntb$3KSGto*pm$f&o za$A?W_1EaP-_G<|4C-?6bc}1sm2}Lun>GR2e17too6F6SB#yMZYSGufEQe{b9PF>s z8ZRdzS(NSZ7i4>g#QUpTdzK>C+$}xEm3|}s2mofW8^6%!#lkY<6jCGrf4T0O0001S C-;vD# literal 0 HcmV?d00001 diff --git a/lib/interactive/TMB_DIGIT_SYMBOL_CODING/_7.webp b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/_7.webp new file mode 100644 index 0000000000000000000000000000000000000000..cdd4592c7c83380813698c55aa216a7f72023084 GIT binary patch literal 1310 zcmV+(1>yQqNk&E%1pok7MM6+kP&gn81pok08UUREDr5j;06vjGn@Xjlq9LY{t9Y;y z326Wo>A%~%OXsok54IUZ-#6uFcso}Agx-qfpV>Hu<4e34z~4pr+4?i~6W|Z|fA-J% z-nibqe`kG-|7S~eim8t9Q$Hl}nX~SkUV2Fd@XAp`NrVEntdU40q^C;*#~cqADDltf zgYE-X*{^f*V{zM-swa^{4J72vxs@a8bQPn!AL-z)NeDoBv9L>jSm&fZz5( zDEz9+cU$r>#as*Bl8$KfVSRmZSihi6A*JF+WZ~a}vb?8t^{@c`&Y5PX>F~De9fTM7 z0RKR3@+b$KPO*Fr4P43AI6jV&2$RHG-(X%Ok~ zQ|!Qm-@jB|c9{@7+zH{<2=(W)+WIbfLQbO=k$pdU25=^tNr=j%=zqE8-Dy8QGG>oy zsxy`^IQ5Wk6w3nBrRW3%a^}&IxhsbjuNSm>!O-DF18sfKq!-$#RqmV@^t#lP7 z-{-euDwRSo1t%FNHDhwojL_O)MwEo~uRW+_X5+w8XvqQ*e2Kh~g`LDO`>bploMSOc-^k41#hzhQ5hOp^fG?PPmsjMAZqy{g6VW^P7kKy;M9cmZN-U_LQ?|)BV ziytzsnbn@!JiTw(;Ea_37Ur>khpOxXig>xM70-SG?TOO$Wpp00{naSa-O;`;b@YZ0 zna+Oa!yDquB1%(_?i`SeFV)Ci8{YPS$QT_=uP*LnzZFqs>|M&Hh@Hkwdv^)Pg{Gll zLxek{b`b6~%>rVms5ySL6HGO#{(tRebr@Cr04vpTUd>rAZ<^(GT~+L-__U#n>^5dm z@Hs|7DmZ-2=5G{*%Ms338JRWdN7OrJUWkaT*%0I&ljUog&i!N2qlS=C{_0l?=?yEU z7h;fNa^CJJ12(3@Q0JGLHo`UkYPzf7rX7XnSm4NdC9vn-{>zT;xzLQm6A%DxYhQ6h z1-#rWVTkYe9uCkl2&k{GL_5%56YUkqJ)p?jV-kT?2jR?ZY@5EeVbq+*)7`huZ4 z%7V-NLp*jSr}ow7gaP7Y7q*_%RtW#=l_G5?-XilB3ues#^(0Rc8DNnS9aLg|oocr# z2zM{_4G-~W%%?HE5T1Lrn9_;onQhmT-3D&aGNrVnc*JJT5UeWIK5!vXE0j`Fh|QOi zJE@yJD8f``G3n~n-};CY82|B}UMA*3KZ)hEk3K>h8sPuuPDh&k^{@2e3|(Ze8#3z2 zd+^=Dh8~2(JRyRPe|>4O>2z~bbOq)AzyXvzr(cyxqice1Cs*}Gx&0=}PIb8@9R_K0 zTpd3@LSOSFI~kAtr_tbV@}chWH`Z7qJcG^`_^;OQ%>O{*e|WF*oz&PB+=;|*;ahcwYHGm@G3tO|pj~IKgrC&||WJ@hmj&m%o{sxGL&>0k=sj86T*qK@~{1TE8GJT{ne-X4r+ze{@ww*o{e0j zT&oVkSk1Y>C{J{SggFO|xF0Z(4BH_WxUB1Hq;`zAzJ zaMr~peOyko)X13_2Ib+=L!-yCn6A11lJm=1m3dVW&AjZg!$3aa3s26#M+iFw7q;{; z(^sw;QE99`#Sf*|rgYWz zmz$idfh8ZX;CNtrOleHBR?W0r-=S6FdkDx8xGwTRLWMnT60-2tE+bIijfq$)$cwP- z7ZTqZej-|)NH2_6ao;(@Acy`I&RfBrX2H)Md+_N{K*~W?a3?ynnqNL5F(+tj9xx&Nk{By&o9|s^*1!8?Ds-B{nW2k4W zWsjzYSlH>kaUaqvBqdq*l}pfY#<@Q)yl(p$CgvbboEK-4OrL*BZ@H?%ER~qUWA)tD zbn(ToUHy9FqJCD1ERt*(hC&4zjGd1a2k~xtEil7y$<8lj=~AnE@vrCBH=0S%cI5O; z`QB^(WIlV0W+<61Omfdnc})wDL#~w442xIXsf0>Q+aY6!(WRP?vZup154v!po{@R& z_S}VZ3YHWNkSdk_NGTN&T^ahTNLRg@DV){_T&AJ8xkQF_E z0Fe(<*wsHO&^1w=P|<E%0br>88hBMJyS9j~dkoCsp!`p0+U31d2xmeF*9Qm^)uBbZyl2uH%3ne|M)X1HXN zigkBWEw-`497Ba^LjL=k9iR&yTe31Q&&V)he&O4MJElTTe zv-!y5P=c2YM!T;PwsI$FNCp$vMerU^8hrOhX&@A%+B%xkRe0o#6K z0TBuKxp)~K;C4zO{|6vOL6MrLLbs=LqSJhmR2Qg*GjLXSsepRz?ORXw|7$y2kl*P$ zKvf<;X>!J1aN|mhwkB_L(QheRdguc!Goxf?b83^MyU{2ClV|0uzWxlf`vC_okr_yd zR*nHQmrBq}-SF6tiqC^`JPVF!wjBjb5uHuFobo_Sw(s5R@b_kt|M%Ruxnb#wvydOD^1gau6neI_Lt z4#pJk=XYKUs{&EWZuLj7I}efyX)~QVVoLo)Km+tck`;X1`iQ_%OxA_5cZF`7(dN6c zfpkJyLKD9}m`#8`YhnMLq*#Y#eEvQT>-ZUSZquoL1bq@WMNc*7)W+t`#)|IWF5~$!~A>Sh?c#{V&OKfStVrA9dwH}E|0)}p^ z&VT^DnW1b9Yj#FZ@Mq@c#OY7{UgrutK;U$1bV_UZ3ZZqjLh~d6wUux{rn+g zoqiAgHq)$ literal 0 HcmV?d00001 diff --git a/lib/interactive/TMB_DIGIT_SYMBOL_CODING/_resp2.webp b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/_resp2.webp new file mode 100644 index 0000000000000000000000000000000000000000..2767f865d598e11f33beeaec47a96bd8f3e85e60 GIT binary patch literal 802 zcmV+-1Ks>mNk&E*0{{S5MM6+kP&gnC0{{S!5dfV5Dp~+q06vjIn@T04q9LSnJm9br z326Wm%b!i$FOTlyw3b}{Wt6x`p?z8)T1&oU^9!+MA|=a!$J$; zrW#MG@eya6Dq=2`rfq1%F&z?M#B#Myb0}5qz@b`+x7bsOr^=wZqJMw$kUznt z5JwQvC;>ahOXb(;{E{R0#@$9o+0pyv#fQ=qjUvqi9jXY$d;_J?ahfjM&K_OFO#tfv zpL7CUP)nNgD`Q|HYjFLpaR}i2bL0#A(?CaxRCo@{d-WIXE4y7d6W^VEiRQk7fGBKr zvT?wP)foFu5NatYJIxenw~Xdie>01OtCZJmrLv1=i~lS+d~S{YSe~%Rz!U^+r-^wE zbhRn|E6CJLqGj~(1Ti8x#(&_0$Xu`(l|GlW>WqK{HI3x34IP!-7WsUeFEI+FQK|7j zlxW?cXd0?TL8nA;G|?LNs;P0jbR|AnbT*L%YpJI4to6x%^6)gfaeo-ZC0>!yM#5)n z<=#UeRkAO$5-v@Og@f@G81F*l+QQeb?K1U|Nx^`%+~I-;N*S7%etPm7k@zOqIgdjs g_wJQ0B@*=5D99@6V-NW5;Evzf=r_={O=N%o04J@C(*OVf literal 0 HcmV?d00001 diff --git a/lib/interactive/TMB_DIGIT_SYMBOL_CODING/_resp3.webp b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/_resp3.webp new file mode 100644 index 0000000000000000000000000000000000000000..545a2b31a3d1cfa87d79c74e2ebd77726b571aad GIT binary patch literal 902 zcmV;119|*XNk&F~0{{S5MM6+kP&goR0{{RJ5&)e6Dp~+q06vjKn@T04q9LNST@bJm z326Wp)U6r%{yh%fL|o^`2&ztJ9zMRe_6+is_6g|@YBHdf+5d0C2H8^MjsgT9L9v0$ z&5qRIf+wb0)h*3Q1f71o=?}szEN~2Kr4BfAg2PBJ49QJGX@vO#FcL9 z*^k$lsBJIPU0mW>?ExfB=r;m^Kx~=-0RH$2g&JH~^!2`e&;~_=oQdRRB2u0w z^nBtpFz9Z&p+LbeT;{t?ISr-Hh4npN<>U6MRC}~ANJ@im+#-CxpP;EbBbie?!SqXN zpD*tO@s3{p_q-@l)M0wZkuZA&KQ4P-vBu%HnMeHZ{z>JzpjeutsQrf#ESWPY6-qI?$cRg+nv`BJ zaUM4MAGwc-li!>FHojh>5j)f zLG!mC`~Qw#%%!nL8mdAPnFyCzr&FrybYde;e)nsS z;5JJXH7iT_X62a>F86@s1GA(V-(%mbrtWhW83_EDZkXnaNZ z2h~v!7~Ues67D^K0@e3>QPsVEV^jK(Z{|`363`w?UU!k4?@u1`0JZ;3#q6Xzv@J7p z(FbCft}+|@`$m0jWknN8LP-Y(gwk`)>5QxX|0~~Dok0IMRuqW?rcV{;&><-9;UbRm+q#*! zW@$e~i=fN>yqagWS!0eJGqY8GF+IES_3xGkT9=Zqq~+3M9kvA^lJz|h?(5FVEIrVO c-`Hf<5Pmlkhu}yD38<%t-Ha}SM|Y#(07j^{xBvhE literal 0 HcmV?d00001 diff --git a/lib/interactive/TMB_DIGIT_SYMBOL_CODING/chooseInput.v1.Feb24.js b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/chooseInput.v1.Feb24.js new file mode 100644 index 0000000..9575b8b --- /dev/null +++ b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/chooseInput.v1.Feb24.js @@ -0,0 +1,265 @@ +/* eslint-disable */ + +/* + + Copyright 2024 The Many Brains Project, Inc. and McLean Hospital. + + This code is made available under a GNU Lesser General Public License 3.0 + (LGPLv3). + https://www.gnu.org/licenses/lgpl-3.0.html. + + Author: Paolo Martini + Last updated: 02.27.2024 + Version: chooseInput.v1.Feb24 + +*/ + +function chooseInput(inputTypes, callback) { + /* Given valid inputTypes {'keyboard','mouse','touch'}, it returns + the user's choice as one of ['keys','clicks','taps'] + + Usage: + + chooseInput({keyboard: true, mouse: false, touch: true}, + function(input) {console.log(input);}); + */ + + var lang, + els, + msg = '', + errMsg = ' ', + oldAction = '', + divs = []; + var centeredTable, centeredCell, chooseInputBox, choiceSpan, errSpan; + + if (inputTypes === null || typeof inputTypes !== 'object') + throw new TypeError('chooseInput: missing or invalid inputTypes object.'); + inputTypes.keyboard = inputTypes.keyboard || false; + inputTypes.mouse = inputTypes.mouse || false; + inputTypes.touch = inputTypes.touch || false; + + // dictionary + els = [ + { + en: 'Keyboard', // 0 + es: 'Teclado', + fr: 'Clavier', + zh: 'Keyboard', + 'zh-hk': 'Keyboard', + nl: 'Toetsenbord' + }, + { + en: 'Touch', // 1 + es: 'Pantalla táctil', + fr: 'Touche', + zh: 'Touch', + 'zh-hk': 'Touch', + nl: 'Scherm' + }, + { + en: 'Mouse / Trackpad', // 2 + es: 'Mouse / Trackpad', + fr: 'Souris / pavé tactile', + zh: 'Mouse / Trackpad', + 'zh-hk': 'Mouse / Trackpad', + nl: 'Muis / Trackpad' + }, + { + en: 'Pen', // 3 + es: 'El lápiz óptico', + fr: 'Stylo', + zh: 'Pen', + 'zh-hk': 'Pen', + nl: 'Pen' + }, + { + en: ' not valid for this test: try another input.', // 4 + es: ' no es válido para esta prueba: intente con otra entrada.', + fr: ' non valide pour ce test: essayez une autre entrée.', + zh: ' not valid for this test: try another input.', + 'zh-hk': ' not valid for this test: try another input.', + nl: ' niet mogelijk voor deze taak, probeer een andere reactiemethode.' + }, + { + en: '

    Please click here
    to choose how you will
    respond in this test.

    ', // 5 + es: '

    Por favor presione aquí para elegir cómo responderá en esta prueba.

    ', + fr: '

    Veuillez cliquer ici pour choisir comment vous allez répondre à ce test.

    ', + zh: '

    Please click here
    to choose how you will
    respond in this test.

    ', + 'zh-hk': '

    Please click here
    to choose how you will
    respond in this test.

    ', + nl: '

    Klik hier om te bepalen hoe
    je in deze test wil reageren.

    ' + }, + { + en: '- To use a keyboard, press any key now.

    ', // 6 + es: '- Para usar un teclado, presione cualquier tecla ahora.

    ', + fr: '- Pour utiliser le clavier, appuyez sur une touche maintenant.

    ', + zh: '- To use a keyboard, press any key now.

    ', + 'zh-hk': '- To use a keyboard, press any key now.

    ', + nl: '- Om het toetsenbord te gebruiken, druk nu op een toets

    ' + }, + { + en: '- To use a mouse or trackpad, click here now.

    ', // 7 + es: '- Para utilizar un mouse o un trackpad, presione aquí ahora.

    ', + fr: '- Pour utiliser une souris ou un pavé tactile, cliquez ici maintenant.

    ', + zh: '- To use a mouse or trackpad, click here now.

    ', + 'zh-hk': '- To use a mouse or trackpad, click here now.

    ', + nl: '- Om je muis of trackpad te gebruiken, klik nu hier.

    ' + }, + { + en: '- To use a touch screen, touch here now.

    ', // 8 + es: '- Para utilizar una pantalla táctil, toque aquí ahora.

    ', + fr: '- Pour utiliser un écran tactile, touchez ici maintenant.', + zh: '- To use a touch screen, touch here now.

    ', + 'zh-hk': '- To use a touch screen, touch here now.

    ', + nl: '- Om je touch screen te gebruiken, raak dit aan.

    ' + } + ]; + + // get the language + lang = document.documentElement.lang; + if (!els[0][lang]) lang = 'en'; + + // choice event handler + function getinput(e) { + var input; + errMsg = ''; + + e.preventDefault(); + e.stopPropagation(); + + // identify the event and validate by allowed input types; + // the order of checking is IMPORTANT: + // - pointer events with pen device will output pen->touch + // in Chrome + if (e.type === 'keyup') { + if (inputTypes.keyboard) input = 'keys'; + else errMsg = els[0][lang]; + } else if (e.type === 'pointerup' || e.type === 'MSPointerUp') { + if (e.pointerType === 'touch' || e.pointerType === e.MSPOINTER_TYPE_TOUCH) { + if (inputTypes.touch) input = 'taps'; + else errMsg = els[1][lang]; + } else if (e.pointerType === 'mouse' || e.pointerType === e.MSPOINTER_TYPE_MOUSE) { + if (inputTypes.mouse) input = 'clicks'; + else errMsg = els[2][lang]; + } else if (e.pointerType === 'pen' || e.pointerType === e.MSPOINTER_TYPE_PEN) { + if (inputTypes.touch) input = 'taps'; + else errMsg = els[3][lang]; + } + } else if (e.type === 'touchend') { + if (inputTypes.touch) input = 'taps'; + else errMsg = els[1][lang]; + } else if (e.type === 'mouseup') { + if (inputTypes.mouse) input = 'clicks'; + else errMsg = els[2][lang]; + } + + // warn if the user entered an invalid input + if (errMsg) errMsg += els[4][lang]; + errSpan.innerHTML = errMsg; + + // if we got a valid input, remove the listeners, + // remove the chooseInput div from the DOM, restore original display + // mode for other divs and return the input type + // to the callback function + if (input) { + document.removeEventListener('keyup', getinput, true); + if ('ontouchend' in window || navigator.maxTouchPoints || navigator.msMaxTouchPoints) + document.removeEventListener('touchend', getinput, true); + document.removeEventListener('mouseup', getinput, true); + if (window.PointerEvent) document.removeEventListener('pointerup', getinput, true); + else if (window.MSPointerEvent) document.removeEventListener('MSPointerUp', getinput, true); + + if ('touchAction' in document.body.style) document.body.style.touchAction = oldAction; + else if ('msTouchAction' in document.body.style) document.body.style.msTouchAction = oldAction; + + centeredTable.remove(); + + divs.forEach(function (d) { + d[0].style.display = d[1]; + }); + + if (callback) callback(input); + } + } + + function setup() { + // prevent default touch action + if ('touchAction' in document.body.style) { + oldAction = document.body.style.touchAction; + document.body.style.touchAction = 'none'; + } else if ('msTouchAction' in document.body.style) { + oldAction = document.body.style.msTouchAction; + document.body.style.msTouchAction = 'none'; + } + + // setup input listeners + document.addEventListener('keyup', getinput, true); + document.addEventListener('mouseup', getinput, true); + if ('ontouchend' in window || navigator.maxTouchPoints || navigator.msMaxTouchPoints) + document.addEventListener('touchend', getinput, true); + if (window.PointerEvent) document.addEventListener('pointerup', getinput, true); + else if (window.MSPointerEvent) document.addEventListener('MSPointerUp', getinput, true); + } + + function trigger() { + msg = ''; + if (inputTypes.keyboard) msg += els[6][lang]; + if (inputTypes.mouse) msg += els[7][lang]; + if (inputTypes.touch) msg += els[8][lang]; + + chooseInputBox.style.textAlign = 'left'; + choiceSpan.innerHTML = msg; + chooseInputBox.removeEventListener('click', trigger, true); + setup(); + } + + // hide all existing divs + [].forEach.call(document.getElementsByTagName('div'), function (d) { + divs.push([d, window.getComputedStyle(d).getPropertyValue('display')]); + d.style.display = 'none'; + }); + + // create elements to output the choice message + centeredTable = document.createElement('div'); + centeredTable.id = 'centeredTable'; + centeredTable.style.boxSizing = 'border-box'; + centeredTable.style.display = 'table'; + centeredTable.style.margin = 'auto'; + centeredTable.style.height = 'inherit'; //document.body.clientHeight + "px"; + centeredTable.style.width = 'inherit'; //document.body.clientWidth + "px"; + centeredTable.style.padding = '0 5% 0 5%'; + centeredTable.style.textAlign = 'center'; + centeredTable.style.fontFamily = '\"Helvetica Neue\",Helvetica,Arial,sans-serif'; + document.body.appendChild(centeredTable); + + centeredCell = document.createElement('div'); + centeredCell.id = 'centeredCell'; + centeredCell.style.display = 'table-cell'; + centeredCell.style.verticalAlign = 'middle'; + centeredTable.appendChild(centeredCell); + + chooseInputBox = document.createElement('div'); + chooseInputBox.id = 'chooseInput'; + chooseInputBox.style.margin = 'auto'; + chooseInputBox.style.maxWidth = '450px'; + chooseInputBox.style.border = 'solid 2px #f1c40f'; + chooseInputBox.style.borderRadius = '1em'; + chooseInputBox.style.background = '#f7f7f7'; + chooseInputBox.style.padding = '10px'; + chooseInputBox.style.fontSize = '18pt'; + centeredCell.appendChild(chooseInputBox); + + choiceSpan = document.createElement('span'); + choiceSpan.id = 'choiceMsg'; + chooseInputBox.appendChild(choiceSpan); + choiceSpan.innerHTML = els[5][lang]; + + errSpan = document.createElement('span'); + errSpan.id = 'errMsg'; + errSpan.style.color = 'red'; + errSpan.style.fontSize = '14pt'; + chooseInputBox.appendChild(errSpan); + errSpan.innerHTML = ' '; + + // trigger the choice + chooseInputBox.addEventListener('click', trigger, true); +} diff --git a/lib/interactive/TMB_DIGIT_SYMBOL_CODING/fragment.html b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/fragment.html new file mode 100644 index 0000000..005279c --- /dev/null +++ b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/fragment.html @@ -0,0 +1,14 @@ +
    +
    + probe +
    +
    +
    + +
    +
    + response 1 + response 2 + response 3 +
    +
    diff --git a/lib/interactive/TMB_DIGIT_SYMBOL_CODING/index.ts b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/index.ts new file mode 100644 index 0000000..406c918 --- /dev/null +++ b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/index.ts @@ -0,0 +1,90 @@ +import { defineInstrument } from '/runtime/v1/@opendatacapture/runtime-core'; +import { z } from '/runtime/v1/zod@3.x/v4'; + +import img1 from './_1.webp'; +import img2 from './_2.webp'; +import img3 from './_3.webp'; +import img4 from './_4.webp'; +import img5 from './_5.webp'; +import img6 from './_6.webp'; +import img7 from './_7.webp'; +import img8 from './_8.webp'; +import img9 from './_9.webp'; +import resp1 from './_resp1.webp'; +import resp2 from './_resp2.webp'; +import resp3 from './_resp3.webp'; +import html from './fragment.html'; +import { render } from './render.js'; + +import './styles.css'; + +const staticAssets = { + '/images/1.png': img1, + '/images/2.png': img2, + '/images/3.png': img3, + '/images/4.png': img4, + '/images/5.png': img5, + '/images/6.png': img6, + '/images/7.png': img7, + '/images/8.png': img8, + '/images/9.png': img9, + '/images/resp1.png': resp1, + '/images/resp2.png': resp2, + '/images/resp3.png': resp3 +}; + +import './TestMyBrain.12.18.min.js?legacy'; +import './chooseInput.v1.Feb24.js?legacy'; +import './TestHelper.v1.Oct23.js?legacy'; + +export default defineInstrument({ + kind: 'INTERACTIVE', + language: ['en', 'fr'], + tags: { + en: ['TestMyBrain'], + fr: ['TestMyBrain'] + }, + internal: { + edition: 1, + name: 'TMB_DIGIT_SYMBOL_CODING' + }, + content: { + meta: { + charset: 'UTF-8', + 'apple-mobile-web-app-capable': 'yes', + 'mobile-web-app-capable': 'yes', + 'apple-mobile-web-app-title': 'TMB DSC', + 'theme-color': 'white', + description: 'TMB Digit Symbol Coding', + keywords: 'cognitive test, brain test, digit-symbol coding', + copyright: '2023 The Many Brains Project, Inc. and McLean Hospital LGPLv3', + viewport: 'width=device-width, initial-scale=1, viewport-fit=contain' + }, + html, + render, + staticAssets, + defaultFullscreen: true, + enableLanguageLock: true, + enableLanguageSelect: true + }, + clientDetails: { + estimatedDuration: 5, + instructions: { + en: ['Instructions will be presented on screen in the task.'], + fr: ["Les instructions seront présentées à l'écran pendant la tâche."] + } + }, + details: { + description: { + en: 'A cognitive test that assesses processing speed and attention by coding symbols as digits according to a nine-symbol key.', + fr: "Un test cognitif qui évalue la vitesse de traitement et l'attention en codant des symboles en chiffres selon une grille de correspondance de neuf symboles." + }, + license: 'LGPL-3.0', + title: { + en: 'TMB Digit Symbol Coding', + fr: 'TMB Codage Chiffres-Symboles' + } + }, + measures: {}, + validationSchema: z.any() +}); diff --git a/lib/interactive/TMB_DIGIT_SYMBOL_CODING/render.d.ts b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/render.d.ts new file mode 100644 index 0000000..c883261 --- /dev/null +++ b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/render.d.ts @@ -0,0 +1 @@ +export declare function render(done: (data: any) => void): void; diff --git a/lib/interactive/TMB_DIGIT_SYMBOL_CODING/render.js b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/render.js new file mode 100644 index 0000000..aba2080 --- /dev/null +++ b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/render.js @@ -0,0 +1,594 @@ +// @ts-nocheck +/* eslint-disable */ + +import { translator } from './translator.ts'; + +export function render(done) { + translator.init(); + + function tFormat(key, vars) { + var s = translator.t(key); + if (vars) { + for (var k in vars) s = s.replace(new RegExp('\\{' + k + '\\}', 'g'), vars[k]); + } + return s; + } + + var testVersion = 'TMB_DIGIT_SYMBOL_CODING.v1'; // version identifier for this test + var chosenInput; // input type (taps or keys) + var symbols = [1, 2, 3, 4, 5, 6, 7, 8, 9]; // symbols used for this test + var symbol; // the symbol to show (1-9) + var digit; // the digit corresponding to the symbol + var correct; // correct=1, wrong=0 + var testStart = 0; // start timestamp of the test + var score = 0; // accumulated score + var results = []; // array to store trials details and responses + var outcomes = {}; // object containing outcome variables + var frameSequence = []; // object containing the sequence of frames and their properties + var frame; // single frame object + var presentationTime; // variable for logging trial presentation time + var feedbackTimeoutRef = null; // reference to the response feedback timer + var nopractice; // URL parameter: no practice trials + var duration; // URL parameter: duration of the test in seconds + var seed; // URL parameter: random number generator seed + var debug; // URL parameter: output to console + var demo; // URL parameter: run in demo mode + var showresults; // URL parameter: if they want to show results in a popup window + var autosave; // URL parameter: if they want to save data in a file automatically + var filename; // URL parameter: filename for data + var useChooseInput; // URL parameter: whether to use chooseInput + var usage = ''; // URL parameter: show usage + var practiceChoice = null; // whether the participant chose to complete optional practice trials + + // how long the chosen digit stays visible under the key, in ms + var feedbackDuration = 500; + + // the digit that codes a given symbol + function digitOf(symbol) { + return symbol % 3 === 0 ? 3 : symbol % 3; + } + + // markup for the key: nine symbols in a row, each over its digit. + // built from spans, because showFrame() hides every div in the document, + // so a div-based key would be invisible on the instruction screens + function keyMarkup(modifier) { + var cells = ''; + var i; + + for (i = 0; i < symbols.length; i++) + cells += ""; + for (i = 0; i < symbols.length; i++) + cells += ""; + + return "" + cells + ''; + } + + // show the digit the participant chose under the key. + // the next symbol is presented immediately, so the feedback from the + // previous trial overlaps the start of the next one + function showFeedback(responseDigit) { + var el = getID('feedback'); + if (!el) return; + + if (feedbackTimeoutRef) clearTimeout(feedbackTimeoutRef); + + el.src = 'images/resp' + responseDigit + '.png'; + el.style.visibility = 'visible'; + + feedbackTimeoutRef = setTimeout(function () { + el.style.visibility = 'hidden'; + feedbackTimeoutRef = null; + }, feedbackDuration); + } + + // clear the feedback digit before leaving the trial screen + function clearFeedback() { + var el = getID('feedback'); + + if (feedbackTimeoutRef) { + clearTimeout(feedbackTimeoutRef); + feedbackTimeoutRef = null; + } + if (el) el.style.visibility = 'hidden'; + } + + // the frames making up the trial screen, minus the response buttons, + // which are only needed when responding by touch + function trialFrames() { + var frames = ['container', 'probeRow', 'keyRow', 'feedbackRow']; + if (chosenInput === 'taps') frames.push('response'); + return frames; + } + + // message for optional practice trials + function showOptionalPractice() { + setTimeout(function () { + showAlert( + '

    ' + + translator.t('optionalPractice.heading') + + '

    ' + + translator.t('optionalPractice.prompt') + + '


    ' + + "

    ' + + "
    ' + + '

    ', + translator.t('buttons.clickContinue'), + function () { + practiceChoice = document.getElementById('practiceSkip').checked ? 'skip' : 'noSkip'; + setFrameSequence(); + }, + '20pt' + ); + }, 50); + } + + // specify actions to take on user input + tmbUI.onreadyUI = function () { + // if we are debugging and there was an error, log the message + if (debug === 'true' && tmbUI.message) console.log(tmbUI.message); + + // the digit chosen by the participant + var responseDigit = tmbUI.response ? tmbUI.response.slice(-1) : ''; + + // is the response correct? + correct = parseInt(responseDigit) === frame.digit ? 1 : 0; + + // confirm the response by showing the chosen digit under the key + if (tmbUI.status !== 'timeout' && /^[123]$/.test(responseDigit)) showFeedback(responseDigit); + + // store the results + if (frame.type === 'practice' || (frame.type === 'test' && tmbUI.status !== 'timeout')) { + results.push({ + type: frame.type, // one of practice or test + symbol: frame.symbol, // symbol index + digit: frame.digit, // symbol digit + response: responseDigit, // the key or element chosen + correct: correct, // boolean correct + rt: tmbUI.rt, // response time + stimOnsetTimestamp: presentationTime, // stimulus presentation timestamp + responseTimestamp: tmbUI.downTimestamp, // response timestamp + state: tmbUI.status // state of the response handler + }); + + // if we are debugging, log the results + if (debug === 'true') logResults(results, 'inc'); + } + // log the final trial, which times out and ends the test + else if (frame.type === 'test' && tmbUI.status === 'timeout') { + results.push({ + type: frame.type, // one of practice or test + symbol: frame.symbol, // symbol index + digit: frame.digit, // symbol digit + response: null, + correct: null, + rt: null, + stimOnsetTimestamp: presentationTime, // stimulus presentation timestamp + responseTimestamp: now(), + state: 'timeout' + }); + } + + if (frame.type === 'practice') { + // on practice trials, if the input event returns a timeout + // or the response is not correct, + // stop the sequence and advise the participant + if (tmbUI.status === 'timeout' || !correct) { + // rewind the frame sequence by one frame, + // so that the same frame is displayed again + frameSequence.unshift(frame); + + clearFeedback(); + + showAlert( + '
    " + + '
    ' + + (chosenInput === 'taps' + ? translator.t('practiceFeedback.rememberTaps') + + '

    ' + + tFormat('practiceFeedback.youShouldTap', { digit: frame.digit }) + + '
    ' + : translator.t('practiceFeedback.rememberKeys') + + '

    ' + + tFormat('practiceFeedback.youShouldKey', { digit: frame.digit }) + + '
    ') + + translator.t('practiceFeedback.whenYouSee') + + '

    ', + chosenInput === 'taps' ? translator.t('buttons.clickRetry') : '', + function () { + showFrame('null'); + nextTrial(); + }, + '20pt', + null, + chosenInput === 'taps' ? null : translator.t('buttons.spaceRetry') + ); + } else { + nextTrial(); + } + } else if (frame.type === 'test') { + if (tmbUI.status !== 'timeout') { + // choose a symbol randomly, but avoid 1-back repetitions + while (symbols[(symbol = randInt(1, symbols.length)) - 1] === frame.symbol) {} + digit = digitOf(symbol); + + // set up the next frame + frameSequence.push({ + type: 'test', + message: '', + symbol: symbols[symbol - 1], + digit: digit, + source: 'images/' + symbols[symbol - 1] + '.png' + }); + } + + nextTrial(); + } + }; + + // iterate through the frameSequence object, + // implementing stimulus presentation, + // response collection and data management + function nextTrial() { + // read the frame sequence one frame at a time + frame = frameSequence.shift(); + if (frame) { + // check if it's the startup frame + if (frame.type === 'begin') { + clearFeedback(); + showAlert( + frame.message, + chosenInput === 'taps' ? translator.t('buttons.clickInstructions') : '', + function () { + showFrame('null'); + nextTrial(); + }, + '20pt', + null, + chosenInput === 'taps' ? null : translator.t('buttons.spaceInstructions') + ); + } + // else if it's a message frame, show it + else if (frame.type === 'message') { + clearFeedback(); + showAlert( + frame.message, + chosenInput === 'taps' ? translator.t('buttons.clickContinue') : '', + function () { + showFrame('null'); + nextTrial(); + }, + '20pt', + null, + chosenInput === 'taps' ? null : translator.t('buttons.spaceContinue') + ); + } + // deal with practice and test frames + else { + // hide the cursor + hideCursor('document.body'); + + // set the image source of the symbol + getID('probe').src = frame.source; + + // set response timeout: + // - for practice trials -> a fixed interval + // - for test trials -> what's left of 'duration' seconds since + // start, with a minimum of 150 ms + if (frame.type === 'practice') tmbUI.timeout = 5000; + else { + if (!testStart) testStart = now(); + if (demo === 'true') tmbUI.timeout = 10000 - (now() - testStart); + else tmbUI.timeout = duration * 1e3 - (now() - testStart); + + // give participant 150 ms for last trial if time has not expired + if (tmbUI.timeout < 150 && tmbUI.timeout > 0) { + tmbUI.timeout = 150; + } + // end test immediately if time has expired + else if (tmbUI.timeout <= 0) { + nextTrial(); + return; + } + } + + requestAnimationFrame(function () { + showFrame(trialFrames()); + presentationTime = now(); + tmbUI.getInput(); + }); + } + } + // else the sequence is empty, we are done! + else { + clearFeedback(); + showCursor('document.body'); + + // all test trials (excluding practice and timeouts) + var tmp1 = results.filter(function (obj) { + return obj.type !== 'practice' && obj.state !== 'timeout'; + }); + + // all correct rts + var tmp2 = tmp1 + .filter(function (obj) { + return obj.correct === 1; + }) + .pluck('rt'); + + // response device + var tmp3 = tmp1[0] ? tmp1[0].state : null; + tmp3 = /key/i.test(tmp3) + ? 'keyboard' + : /touch/i.test(tmp3) + ? 'touch' + : /mouse/i.test(tmp3) + ? 'mouse' + : /pen/i.test(tmp3) + ? 'pen' + : 'unknown'; + + // compute score and outcome variables + score = outcomes.score = tmp2.length; + outcomes.num_correct = tmp2.length; + outcomes.num_responses = tmp1.length; + outcomes.meanRTc = tmp2.length ? tmp2.average().round(2) : null; + outcomes.medianRTc = tmp2.length ? tmp2.median().round(2) : null; + outcomes.sdRTc = tmp2.length > 1 ? tmp2.sd().round(2) : null; + outcomes.accuracy = outcomes.num_responses > 0 ? (outcomes.num_correct / outcomes.num_responses).round(4) : null; + outcomes.cvRTc = tmp2.length > 1 ? (outcomes.sdRTc / outcomes.medianRTc).round(4) : null; + outcomes.didPracticeTrials = nopractice === 'false' || practiceChoice === 'noSkip' ? 1 : 0; + outcomes.symbolsUsed = symbols.toString(); + outcomes.responseDevice = tmp3; + outcomes.testVersion = testVersion; + + outcomes.type = 'summaryScores'; + results.push(outcomes); + + done(results); + } + } + + // generate the frameSequence object, + // where each object's element codes the parameters + // for a single trial/frame + function setFrameSequence() { + var testMessage; + + // messages + testMessage = { + begin: '

    ' + translator.t('instructions.title') + '

    ' + keyMarkup() + '

    ', + instructions: [ + '

    ' + + translator.t('instructions.heading') + + '

    ' + + '
    ' + + keyMarkup() + + '

    ' + + translator.t('instructions.eachSymbol') + + '

    ', + "Instructions
    " + + keyMarkup('key--small') + + '

    ' + + (chosenInput === 'taps' + ? translator.t('instructions.whenSymbolTaps') + : translator.t('instructions.whenSymbolKeys')) + + '
    ' + + translator.t('instructions.hereItIs') + + '

    ' + ], + practice: [ + "Instructions
    " + + keyMarkup('key--small') + + '

    ' + + translator.t('instructions.letsPractice') + + '


    ', + translator.t('instructions.excellent') + '

    ' + ], + test: tFormat('instructions.scoreInfo', { duration: duration }) + '

    ' + }; + + if (nopractice !== 'optional') { + // type of frame to display + var frameType = ['begin', 'message', 'message']; + + // message to display + var frameMessage = [testMessage.begin, testMessage.instructions[0], testMessage.instructions[1]]; + + // symbol to display + var frameSymbol = [0, 0, 0]; + + // corresponding digit + var frameDigit = [0, 0, 0]; + } else { + // type of frame to display + var frameType = ['message', 'message']; + + // message to display + var frameMessage = [testMessage.instructions[0], testMessage.instructions[1]]; + + // symbol to display + var frameSymbol = [0, 0]; + + // corresponding digit + var frameDigit = [0, 0]; + } + + // add practice trials as needed + if (practiceChoice === 'noSkip' || nopractice === 'false') { + frameType = frameType.concat(['message', 'practice', 'practice', 'practice', 'message']); + frameMessage = frameMessage.concat([testMessage.practice[0], '', '', '', testMessage.practice[1]]); + frameSymbol = frameSymbol.concat([0, 1, 6, 8, 0]); + frameDigit = frameDigit.concat([0, 1, 3, 2, 0]); + } + + // add test trials + frameType = frameType.concat(['message', 'test']); + frameMessage = frameMessage.concat([testMessage.test, '']); + frameSymbol = frameSymbol.concat([0, 4]); + frameDigit = frameDigit.concat([0, 1]); + + // push all components into the frames chain + for (var i = 0; i < frameType.length; i++) { + frameSequence.push({ + type: frameType[i], + message: frameMessage[i], + symbol: symbols[frameSymbol[i] - 1], + digit: frameDigit[i], + source: 'images/' + symbols[frameSymbol[i] - 1] + '.png' + }); + } + + // start displaying the frame sequence + nextTrial(); + } + + function setup(input) { + // determine events to listen to and + // customize response elements + chosenInput = input; + if (chosenInput === 'taps') { + tmbUI.UIevents = ['taps']; + tmbUI.UIelements = ['resp1', 'resp2', 'resp3']; + } else { + tmbUI.UIevents = ['keys']; + tmbUI.UIkeys = [ + keyToCode('1'), + keyToCode('2'), + keyToCode('3'), + keyToCode('numpad1'), + keyToCode('numpad2'), + keyToCode('numpad3') + ]; + tmbUI.UIelements = []; + } + + // no highlight: the response is confirmed by the digit shown under the + // key, and highlighting would delay the next symbol by 250 ms + tmbUI.highlight = ''; + + // preload images and start the testing sequence + var images = []; + + for (var i = 0; i < symbols.length; i++) images[i] = 'images/' + symbols[i] + '.png'; + images.push('images/resp1.png', 'images/resp2.png', 'images/resp3.png'); + + imagePreLoad(images, { + pipeline: false, + callBack: function () { + getID('keyRow').innerHTML = keyMarkup(); + // either show optional practice trial screen, or set the frame sequence + nopractice === 'optional' ? showOptionalPractice() : setFrameSequence(); + } + }); + } + + // on page load completion, set up initial parameters, + // call the frameSequence generator + // and start the trials sequence + (function () { + var copyright = 'Copyright ' + document.querySelector('meta[name="copyright"]').content; + var scriptName = window.location.pathname.split('/').pop(); + + // add appropriate meta viewport for scaling + setBodyScale(760, 620); + + // see if they are just asking for help + if ((usage = getUrlParameters('help', '', true))) { + showAlert( + "

    " + + '' + + document.title + + '
    ' + + '' + + copyright + + '

    ' + + 'Usage:' + + '
    ' + + scriptName + + '?urlParam1=1&urlParam2=0

    ' + + 'URL Parameters:
    ' + + 'nopractice=false -- omits practice trials [true, false, optional]
    ' + + 'duration=90 -- test duration in seconds
    ' + + 'seed=123 -- random number generator seed
    ' + + 'demo=true -- runs in demo mode only for 10 seconds
    ' + + 'chooseinput=true -- whether we use chooseInput when touch is detected
    ' + + 'debug=true -- outputs trial by trial info to the console
    ' + + 'showresults=true -- allows to save results locally in a file
    ' + + 'autosave=true -- will attempt to save results automatically to file
    ' + + 'filename=subject1.csv -- the filename to save results to
    ' + + 'help -- print this message' + ); + document.getElementById('helpSpan').style.textAlign = 'left'; + document.getElementById('helpSpan').style.margin = '50px'; + return; + } + + // check if this is a debug session + debug = getUrlParameters('debug', '', true); + + // check if they want a demo run + demo = getUrlParameters('demo', '', true); + + // check if they want to load results in a new page when the test is over, + // if data is to be saved automatically to a file and the filename + showresults = getUrlParameters('showresults', '', true); + autosave = getUrlParameters('autosave', '', true); + filename = getUrlParameters('filename', '', true); + + // see if they don't want practice or optional practice + nopractice = getUrlParameters('nopractice', '', true); + if (!nopractice) nopractice = 'false'; + else if (!(nopractice === 'true' || nopractice === 'false' || nopractice === 'optional')) { + showAlert( + "Error: URL parameter 'nopractice' must
    " + "be set to 'true', 'false', or 'optional'.

    ", + '', + null, + '20pt' + ); + return; + } + + // check if they want to bypass chooseInput + useChooseInput = getUrlParameters('chooseinput', '', true); + if (!useChooseInput || useChooseInput === 'true') { + useChooseInput = true; + } else if (useChooseInput === 'false') { + useChooseInput = false; + } else { + showAlert( + "Error: URL parameter 'chooseinput' must
    " + "be set to 'true' or 'false'.

    ", + '', + null, + '20pt' + ); + return; + } + + // set the random generator's seed + seed = getUrlParameters('seed', '', true); + if (!(seed = parseInt(seed))) seed = 'DScoding'; + Math.seedrandom(seed); + + // set the duration of the test in seconds + duration = getUrlParameters('duration', '', true); + if (!(duration = parseInt(duration))) duration = 90; + + // disable spurious user interactions + disableSelect(); + disableRightClick(); + disableDrag(); + disableDoubleTapZoom(); + + if (!hasTouch) setup('keys'); + else { + if (useChooseInput) chooseInput({ keyboard: true, touch: true }, setup); + else setup('taps'); + } + })(); +} diff --git a/lib/interactive/TMB_DIGIT_SYMBOL_CODING/styles.css b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/styles.css new file mode 100644 index 0000000..667debc --- /dev/null +++ b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/styles.css @@ -0,0 +1,138 @@ +* { + border-radius: 0; + box-sizing: border-box; +} + +*::after, +*::before { + box-sizing: border-box; +} + +html { + width: 100vw; + height: 100vh; +} + +body { + width: 100vw; + height: 100vh; + margin: auto; + background: #ffffff; + color: #000000; + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-size: 13pt; + text-align: center; +} + +/* height is left to the content, so the task stays centred whether or not + the response buttons are shown */ + +#container { + width: 520px; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + display: none; +} + +.button { + border: 2px solid #f1c40f; + border-radius: 1em; + background: transparent; + color: #000000; + box-shadow: 0 5px 15px 5px grey; +} + +.button:active { + box-shadow: 0 5px 15px 1px lightgrey; +} + +.button:focus { + outline: none; +} + +/* the symbol to respond to */ + +#probeRow { + height: 108px; +} + +#probe { + display: inline-block; + width: 100px; + height: 100px; + margin: 4px 0; +} + +/* the key: nine symbols in a row, each over its digit. + built from spans rather than divs, because showFrame() toggles the + display of every div in the document, including inside alert screens */ + +#keyRow { + margin-top: 6px; +} + +.key { + display: inline-grid; + grid-template-columns: repeat(9, 54px); + grid-template-rows: 56px 44px; +} + +.key--small { + grid-template-columns: repeat(9, 40px); + grid-template-rows: 42px 34px; +} + +.keyCell { + display: flex; + align-items: center; + justify-content: center; + padding: 4px; + border-right: 1px solid #000000; + border-bottom: 1px solid #000000; +} + +.keyCell:nth-child(-n + 9) { + border-top: 1px solid #000000; +} + +.keyCell:nth-child(9n + 1) { + border-left: 1px solid #000000; +} + +.keyCell img { + max-width: 100%; + max-height: 100%; +} + +/* the digit chosen by the participant, shown briefly under the key. + the row keeps its height at all times, so the layout never shifts */ + +#feedbackRow { + height: 72px; + margin-top: 12px; +} + +#feedback { + display: inline-block; + width: 60px; + height: 60px; + visibility: hidden; +} + +/* response buttons, shown only when responding by touch */ + +#response { + margin-top: 4px; +} + +.respButton { + display: inline-block; + width: 76px; + height: 76px; + margin: 0 14px; + padding: 6px; + border: 2px solid #cccccc; + border-radius: 8px; +} diff --git a/lib/interactive/TMB_DIGIT_SYMBOL_CODING/translator.ts b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/translator.ts new file mode 100644 index 0000000..2c11554 --- /dev/null +++ b/lib/interactive/TMB_DIGIT_SYMBOL_CODING/translator.ts @@ -0,0 +1,110 @@ +import { Translator } from '/runtime/v1/@opendatacapture/runtime-core'; + +export const translator = new Translator({ + translations: { + optionalPractice: { + heading: { + en: 'TMB Digit Symbol Coding', + fr: 'TMB Codage Chiffres-Symboles' + }, + prompt: { + en: 'Please choose whether to:', + fr: 'Veuillez choisir :' + }, + skip: { + en: 'Skip practice trials', + fr: "Sauter les essais d'entraînement" + }, + view: { + en: 'View practice trials', + fr: "Voir les essais d'entraînement" + } + }, + buttons: { + clickContinue: { + en: 'Click here to continue', + fr: 'Cliquez ici pour continuer' + }, + clickInstructions: { + en: 'Click here for instructions', + fr: 'Cliquez ici pour les instructions' + }, + clickRetry: { + en: 'Click here to retry', + fr: 'Cliquez ici pour réessayer' + }, + spaceContinue: { + en: 'Press the SPACEBAR to continue', + fr: "Appuyez sur la BARRE D'ESPACE pour continuer" + }, + spaceInstructions: { + en: 'Press the SPACEBAR for instructions', + fr: "Appuyez sur la BARRE D'ESPACE pour les instructions" + }, + spaceRetry: { + en: 'Press the SPACEBAR to retry', + fr: "Appuyez sur la BARRE D'ESPACE pour réessayer" + } + }, + practiceFeedback: { + rememberTaps: { + en: 'Remember:
    touch the screen to respond.', + fr: 'Rappel :
    touchez l’écran pour répondre.' + }, + rememberKeys: { + en: 'Remember:
    use the keyboard to respond.', + fr: 'Rappel :
    utilisez le clavier pour répondre.' + }, + youShouldTap: { + en: 'You should touch {digit}', + fr: 'Vous devez toucher le {digit}' + }, + youShouldKey: { + en: 'You should press {digit} on the keyboard', + fr: 'Vous devez appuyer sur {digit} au clavier' + }, + whenYouSee: { + en: 'when you see this symbol.', + fr: 'lorsque vous voyez ce symbole.' + } + }, + instructions: { + title: { + en: 'Digit-Symbol Coding', + fr: 'Codage chiffres-symboles' + }, + heading: { + en: 'Instructions:', + fr: 'Instructions :' + }, + eachSymbol: { + en: 'Each symbol has a number.', + fr: 'Chaque symbole a un chiffre.' + }, + whenSymbolTaps: { + en: 'When a symbol appears at the top,
    touch its number on the screen', + fr: "Lorsqu'un symbole apparaît en haut,
    touchez son chiffre à l'écran" + }, + whenSymbolKeys: { + en: 'When a symbol appears at the top,
    press its number on the keyboard', + fr: "Lorsqu'un symbole apparaît en haut,
    appuyez sur son chiffre au clavier" + }, + hereItIs: { + en: '(here it is 1).', + fr: "(ici c'est 1)." + }, + letsPractice: { + en: "Let's practice a few symbols.", + fr: 'Entraînons-nous sur quelques symboles.' + }, + excellent: { + en: 'Excellent!
    You have completed the practice.
    Now let’s do more.', + fr: 'Excellent !
    Vous avez terminé l’entraînement.
    Passons à la suite.' + }, + scoreInfo: { + en: 'Your score will be
    how many correct responses
    you make in {duration} seconds,
    so try to be ACCURATE and QUICK!', + fr: 'Votre score correspondra
    au nombre de bonnes réponses
    que vous donnerez en {duration} secondes,
    alors soyez PRÉCIS et RAPIDE !' + } + } + } +});